From 56f71a8989e3aae40229dfc8bb878fc5abb13c80 Mon Sep 17 00:00:00 2001 From: jonasvdd Date: Tue, 13 Feb 2024 14:35:34 +0100 Subject: [PATCH] :fire: delegate nan behavior to aggregators --- CHANGELOG.md | 9 + plotly_resampler/aggregation/aggregators.py | 28 ++- .../figure_resampler_interface.py | 55 +---- poetry.lock | 194 +----------------- pyproject.toml | 2 +- tests/test_aggregators.py | 45 ++++ tests/test_figure_resampler.py | 30 --- tests/test_figurewidget_resampler.py | 33 --- 8 files changed, 90 insertions(+), 306 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 051a584b..8f8641ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# . + +Removed the `check_nans` argument of the FigureResampler construct and its `add_traces` method. This argument was used to check for NaNs in the input data, but this is now handled by the `nan_policy` argument of specific aggregators. + + + + +# v0.9.2 +`TODO` # v0.9.1 ## Major changes: diff --git a/plotly_resampler/aggregation/aggregators.py b/plotly_resampler/aggregation/aggregators.py index e7891370..542979e7 100644 --- a/plotly_resampler/aggregation/aggregators.py +++ b/plotly_resampler/aggregation/aggregators.py @@ -17,6 +17,9 @@ LTTBDownsampler, MinMaxDownsampler, MinMaxLTTBDownsampler, + NaNMinMaxDownsampler, + NaNMinMaxLTTBDownsampler, + # TODO -> integrate NANM4 (after the candlestick PR) ) from ..aggregation.aggregation_interface import DataAggregator, DataPointSelector @@ -171,18 +174,25 @@ class MinMaxAggregator(DataPointSelector): """ - def __init__(self, **downsample_kwargs): + def __init__(self, nan_policy="omit", **downsample_kwargs): """ Parameters ---------- **downsample_kwargs Keyword arguments passed to the :class:`MinMaxDownsampler`. - The `parallel` argument is set to False by default. + nan_policy: str, optional + The policy to handle NaNs. Can be 'omit' or 'keep'. By default, 'omit'. """ # this downsampler supports all dtypes super().__init__(**downsample_kwargs) - self.downsampler = MinMaxDownsampler() + if nan_policy not in ("omit", "keep"): + raise ValueError("nan_policy must be either 'omit' or 'keep'") + if nan_policy == "omit": + self.downsampler = MinMaxDownsampler() + else: + self.downsampler = NaNMinMaxDownsampler() def _arg_downsample( self, @@ -208,13 +218,17 @@ class MinMaxLTTB(DataPointSelector): Paper: [https://arxiv.org/pdf/2305.00332.pdf](https://arxiv.org/pdf/2305.00332.pdf) """ - def __init__(self, minmax_ratio: int = 4, **downsample_kwargs): + def __init__( + self, minmax_ratio: int = 4, nan_policy: str = "omit", **downsample_kwargs + ): """ Parameters ---------- minmax_ratio: int, optional The ratio between the number of data points in the MinMax-prefetching and the number of data points that will be outputted by LTTB. By default, 4. + nan_policy: str, optional + The policy to handle NaNs. Can be 'omit' or 'keep'. By default, 'omit'. **downsample_kwargs Keyword arguments passed to the `MinMaxLTTBDownsampler`. - The `parallel` argument is set to False by default. @@ -222,7 +236,13 @@ def __init__(self, minmax_ratio: int = 4, **downsample_kwargs): proven to be a good default. """ - self.minmaxlttb = MinMaxLTTBDownsampler() + if nan_policy not in ("omit", "keep"): + raise ValueError("nan_policy must be either 'omit' or 'keep'") + if nan_policy == "omit": + self.minmaxlttb = MinMaxLTTBDownsampler() + else: + self.minmaxlttb = NaNMinMaxLTTBDownsampler() + self.minmax_ratio = minmax_ratio super().__init__( diff --git a/plotly_resampler/figure_resampler/figure_resampler_interface.py b/plotly_resampler/figure_resampler/figure_resampler_interface.py index 13a304ff..173b42a2 100644 --- a/plotly_resampler/figure_resampler/figure_resampler_interface.py +++ b/plotly_resampler/figure_resampler/figure_resampler_interface.py @@ -555,7 +555,6 @@ def _parse_get_trace_props( hf_hovertext: Iterable = None, hf_marker_size: Iterable = None, hf_marker_color: Iterable = None, - check_nans: bool = True, ) -> _hf_data_container: """Parse and capture the possibly high-frequency trace-props in a datacontainer. @@ -572,11 +571,6 @@ def _parse_get_trace_props( hf_hovertext : Iterable, optional High-frequency trace "hovertext" data, overrides the current trace its hovertext data. - check_nans: bool, optional - Whether the `hf_y` should be checked for NaNs, by default True. - As checking for NaNs is expensive, this can be disabled when the `hf_y` is - already known to contain no NaNs (or when the downsampler can handle NaNs, - e.g., EveryNthPoint). Returns ------- @@ -677,22 +671,6 @@ def _parse_get_trace_props( if isinstance(hf_marker_color, (tuple, list, np.ndarray, pd.Series)): hf_marker_color = np.asarray(hf_marker_color) - # Remove NaNs for efficiency (storing less meaningless data) - # NaNs introduce gaps between enclosing non-NaN data points & might distort - # the resampling algorithms - if check_nans and pd.isna(hf_y).any(): - not_nan_mask = ~pd.isna(hf_y) - hf_x = hf_x[not_nan_mask] - hf_y = hf_y[not_nan_mask] - if isinstance(hf_text, np.ndarray): - hf_text = hf_text[not_nan_mask] - if isinstance(hf_hovertext, np.ndarray): - hf_hovertext = hf_hovertext[not_nan_mask] - if isinstance(hf_marker_size, np.ndarray): - hf_marker_size = hf_marker_size[not_nan_mask] - if isinstance(hf_marker_color, np.ndarray): - hf_marker_color = hf_marker_color[not_nan_mask] - # Try to parse the hf_x data if it is of object type or if len(hf_x) and (hf_x.dtype.type is np.str_ or hf_x.dtype == "object"): try: @@ -876,7 +854,6 @@ def add_trace( hf_hovertext: Union[str, Iterable] = None, hf_marker_size: Union[str, Iterable] = None, hf_marker_color: Union[str, Iterable] = None, - check_nans: bool = True, **trace_kwargs, ): """Add a trace to the figure. @@ -932,13 +909,6 @@ def add_trace( hf_marker_color: Iterable, optional The original high frequency marker color. If set, this has priority over the trace its ``marker.color`` argument. - check_nans: boolean, optional - If set to True, the trace's data will be checked for NaNs - which will be - removed. By default True. - As this is a costly operation, it is recommended to set this parameter to - False if you are sure that your data does not contain NaNs (or when the - downsampler can handle NaNs, e.g., EveryNthPoint). This should considerably - speed up the graph construction time. **trace_kwargs: dict Additional trace related keyword arguments. e.g.: row=.., col=..., secondary_y=... @@ -1019,7 +989,6 @@ def add_trace( hf_hovertext, hf_marker_size, hf_marker_color, - check_nans, ) # These traces will determine the autoscale its RANGE! @@ -1078,7 +1047,6 @@ def add_traces( downsamplers: None | List[AbstractAggregator] | AbstractAggregator = None, gap_handlers: None | List[AbstractGapHandler] | AbstractGapHandler = None, limit_to_views: List[bool] | bool = False, - check_nans: List[bool] | bool = True, **traces_kwargs, ): """Add traces to the figure. @@ -1124,14 +1092,6 @@ def add_traces( by default False.\n Remark that setting this parameter to True ensures that low frequency traces are added to the ``hf_data`` property. - check_nans : None | List[bool] | bool, optional - List of check_nans booleans for the added traces. If set to True, the - trace's datapoints will be checked for NaNs. If a single boolean is passed, - all to be added traces will use this value, by default True.\n - As this is a costly operation, it is recommended to set this parameter to - False if the data is known to contain no NaNs (or when the downsampler can - handle NaNs, e.g., EveryNthPoint). This will considerably speed up the graph - construction time. **traces_kwargs: dict Additional trace related keyword arguments. e.g.: rows=.., cols=..., secondary_ys=... @@ -1174,16 +1134,11 @@ def add_traces( gap_handlers = [gap_handlers] * len(data) if isinstance(limit_to_views, bool): limit_to_views = [limit_to_views] * len(data) - if isinstance(check_nans, bool): - check_nans = [check_nans] * len(data) - zipped = zip( - data, max_n_samples, downsamplers, gap_handlers, limit_to_views, check_nans - ) - for ( - i, - (trace, max_out, downsampler, gap_handler, limit_to_view, check_nan), - ) in enumerate(zipped): + zipped = zip(data, max_n_samples, downsamplers, gap_handlers, limit_to_views) + for (i, (trace, max_out, downsampler, gap_handler, limit_to_view)) in enumerate( + zipped + ): if ( trace.type.lower() not in self._high_frequency_traces or self._hf_data.get(trace.uid) is not None @@ -1194,7 +1149,7 @@ def add_traces( if not limit_to_view and (trace.y is None or len(trace.y) <= max_out_s): continue - dc = self._parse_get_trace_props(trace, check_nans=check_nan) + dc = self._parse_get_trace_props(trace) self._hf_data[trace.uid] = self._construct_hf_data_dict( dc, trace=trace, diff --git a/poetry.lock b/poetry.lock index 53bbf373..7496f995 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. [[package]] name = "ansi2html" version = "1.8.0" description = "" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -23,7 +22,6 @@ test = ["pytest", "pytest-cov"] name = "anyio" version = "3.7.1" description = "High level compatibility layer for multiple asynchronous event loop implementations" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -46,7 +44,6 @@ trio = ["trio (<0.22)"] name = "appnope" version = "0.1.3" description = "Disable App Nap on macOS >= 10.9" -category = "main" optional = false python-versions = "*" files = [ @@ -58,7 +55,6 @@ files = [ name = "argon2-cffi" version = "23.1.0" description = "Argon2 for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -80,7 +76,6 @@ typing = ["mypy"] name = "argon2-cffi-bindings" version = "21.2.0" description = "Low-level CFFI bindings for Argon2" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -118,7 +113,6 @@ tests = ["pytest"] name = "atomicwrites" version = "1.4.1" description = "Atomic file writes." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -129,7 +123,6 @@ files = [ name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -151,7 +144,6 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte name = "babel" version = "2.13.1" description = "Internationalization utilities" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -170,7 +162,6 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] name = "backcall" version = "0.2.0" description = "Specifications for callback functions passed in to an API" -category = "main" optional = false python-versions = "*" files = [ @@ -182,7 +173,6 @@ files = [ name = "beautifulsoup4" version = "4.12.2" description = "Screen-scraping library" -category = "dev" optional = false python-versions = ">=3.6.0" files = [ @@ -201,7 +191,6 @@ lxml = ["lxml"] name = "black" version = "22.12.0" description = "The uncompromising code formatter." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -238,7 +227,6 @@ uvloop = ["uvloop (>=0.15.2)"] name = "bleach" version = "6.0.0" description = "An easy safelist-based HTML-sanitizing tool." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -257,7 +245,6 @@ css = ["tinycss2 (>=1.1.0,<1.2)"] name = "blinker" version = "1.6.3" description = "Fast, simple object-to-object and broadcast signaling" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -269,7 +256,6 @@ files = [ name = "brotli" version = "1.1.0" description = "Python bindings for the Brotli compression library" -category = "dev" optional = false python-versions = "*" files = [ @@ -362,7 +348,6 @@ files = [ name = "cached-property" version = "1.5.2" description = "A decorator for caching properties in classes." -category = "dev" optional = false python-versions = "*" files = [ @@ -374,7 +359,6 @@ files = [ name = "certifi" version = "2023.7.22" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -386,7 +370,6 @@ files = [ name = "cffi" version = "1.15.1" description = "Foreign Function Interface for Python calling C code." -category = "main" optional = false python-versions = "*" files = [ @@ -463,7 +446,6 @@ pycparser = "*" name = "cffi" version = "1.16.0" description = "Foreign Function Interface for Python calling C code." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -528,7 +510,6 @@ pycparser = "*" name = "charset-normalizer" version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -628,7 +609,6 @@ files = [ name = "click" version = "8.1.7" description = "Composable command line interface toolkit" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -644,7 +624,6 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -656,7 +635,6 @@ files = [ name = "comm" version = "0.1.4" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -676,7 +654,6 @@ typing = ["mypy (>=0.990)"] name = "coverage" version = "7.2.7" description = "Code coverage measurement for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -752,7 +729,6 @@ toml = ["tomli"] name = "cryptography" version = "42.0.2" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -807,7 +783,6 @@ test-randomorder = ["pytest-randomly"] name = "dash" version = "2.14.1" description = "A Python framework for building reactive web-apps. Developed by Plotly." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -842,7 +817,6 @@ testing = ["beautifulsoup4 (>=4.8.2)", "cryptography (<3.4)", "dash-testing-stub name = "dash-core-components" version = "2.0.0" description = "Core component suite for Dash" -category = "main" optional = false python-versions = "*" files = [ @@ -854,7 +828,6 @@ files = [ name = "dash-html-components" version = "2.0.0" description = "Vanilla HTML components for Dash" -category = "main" optional = false python-versions = "*" files = [ @@ -866,7 +839,6 @@ files = [ name = "dash-table" version = "5.0.0" description = "Dash table" -category = "main" optional = false python-versions = "*" files = [ @@ -878,7 +850,6 @@ files = [ name = "debugpy" version = "1.7.0" description = "An implementation of the Debug Adapter Protocol for Python" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -910,7 +881,6 @@ files = [ name = "decorator" version = "5.1.1" description = "Decorators for Humans" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -922,7 +892,6 @@ files = [ name = "defusedxml" version = "0.7.1" description = "XML bomb protection for Python stdlib modules" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -934,7 +903,6 @@ files = [ name = "entrypoints" version = "0.4" description = "Discover and load entry points from installed packages." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -946,7 +914,6 @@ files = [ name = "exceptiongroup" version = "1.1.3" description = "Backport of PEP 654 (exception groups)" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -961,7 +928,6 @@ test = ["pytest (>=6)"] name = "fastjsonschema" version = "2.18.1" description = "Fastest Python implementation of JSON schema" -category = "dev" optional = false python-versions = "*" files = [ @@ -976,7 +942,6 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc name = "flask" version = "2.2.5" description = "A simple framework for building complex web applications." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -999,7 +964,6 @@ dotenv = ["python-dotenv"] name = "flask-cors" version = "3.0.10" description = "A Flask extension adding a decorator for CORS support" -category = "main" optional = true python-versions = "*" files = [ @@ -1015,7 +979,6 @@ Six = "*" name = "ghp-import" version = "2.1.0" description = "Copy your docs directly to the gh-pages branch." -category = "dev" optional = false python-versions = "*" files = [ @@ -1033,7 +996,6 @@ dev = ["flake8", "markdown", "twine", "wheel"] name = "griffe" version = "0.30.1" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1049,7 +1011,6 @@ colorama = ">=0.4" name = "griffe" version = "0.36.9" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1064,7 +1025,6 @@ colorama = ">=0.4" name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1079,7 +1039,6 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""} name = "h2" version = "4.1.0" description = "HTTP/2 State-Machine based protocol implementation" -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -1095,7 +1054,6 @@ hyperframe = ">=6.0,<7" name = "hpack" version = "4.0.0" description = "Pure-Python HPACK header compression" -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -1107,7 +1065,6 @@ files = [ name = "hyperframe" version = "6.0.1" description = "HTTP/2 framing layer for Python" -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -1119,7 +1076,6 @@ files = [ name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1131,7 +1087,6 @@ files = [ name = "importlib-metadata" version = "6.7.0" description = "Read metadata from Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1152,7 +1107,6 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs name = "importlib-resources" version = "5.12.0" description = "Read resources from Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1171,7 +1125,6 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1183,7 +1136,6 @@ files = [ name = "ipykernel" version = "6.16.2" description = "IPython Kernel for Jupyter" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1212,7 +1164,6 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-cov", "p name = "ipython" version = "7.34.0" description = "IPython: Productive Interactive Computing" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1249,7 +1200,6 @@ test = ["ipykernel", "nbformat", "nose (>=0.10.1)", "numpy (>=1.17)", "pygments" name = "ipython-genutils" version = "0.2.0" description = "Vestigial utilities from IPython" -category = "dev" optional = false python-versions = "*" files = [ @@ -1261,7 +1211,6 @@ files = [ name = "ipywidgets" version = "7.8.1" description = "IPython HTML widgets for Jupyter" -category = "dev" optional = false python-versions = "*" files = [ @@ -1284,7 +1233,6 @@ test = ["ipykernel", "mock", "pytest (>=3.6.0)", "pytest-cov"] name = "itsdangerous" version = "2.1.2" description = "Safely pass data to untrusted environments and back." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1296,7 +1244,6 @@ files = [ name = "jedi" version = "0.19.1" description = "An autocompletion tool for Python that can be used for text editors." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1316,7 +1263,6 @@ testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1334,7 +1280,6 @@ i18n = ["Babel (>=2.7)"] name = "jsonschema" version = "4.17.3" description = "An implementation of JSON Schema validation for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1358,7 +1303,6 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- name = "jupyter-client" version = "7.4.9" description = "Jupyter protocol implementation and client libraries" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1383,7 +1327,6 @@ test = ["codecov", "coverage", "ipykernel (>=6.12)", "ipython", "mypy", "pre-com name = "jupyter-core" version = "4.12.0" description = "Jupyter core package. A base package on which Jupyter projects rely." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1402,7 +1345,6 @@ test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] name = "jupyter-dash" version = "0.4.2" description = "Dash support for the Jupyter notebook interface" -category = "main" optional = true python-versions = ">=3.5" files = [ @@ -1427,7 +1369,6 @@ dev = ["jupyter-server-proxy", "jupyterlab (>=2.0)", "notebook (>=6.0)"] name = "jupyter-server" version = "1.24.0" description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1440,7 +1381,7 @@ anyio = ">=3.1.0,<4" argon2-cffi = "*" jinja2 = "*" jupyter-client = ">=6.1.12" -jupyter-core = ">=4.12,<5.0.0 || >=5.1.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" nbconvert = ">=6.4.4" nbformat = ">=5.2.0" packaging = "*" @@ -1460,7 +1401,6 @@ test = ["coverage", "ipykernel", "pre-commit", "pytest (>=7.0)", "pytest-console name = "jupyterlab-pygments" version = "0.2.2" description = "Pygments theme using JupyterLab CSS variables" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1472,7 +1412,6 @@ files = [ name = "jupyterlab-widgets" version = "1.1.7" description = "A JupyterLab extension." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1484,7 +1423,6 @@ files = [ name = "kaitaistruct" version = "0.10" description = "Kaitai Struct declarative parser generator for binary data: runtime library for Python" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" files = [ @@ -1496,7 +1434,6 @@ files = [ name = "kaleido" version = "0.2.1" description = "Static image export for web-based visualization libraries with zero dependencies" -category = "main" optional = true python-versions = "*" files = [ @@ -1512,7 +1449,6 @@ files = [ name = "line-profiler" version = "4.1.2" description = "Line-by-line profiler" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1585,7 +1521,6 @@ tests-strict = ["coverage[toml] (==5.3)", "pytest (==4.6.0)", "pytest (==4.6.0)" name = "markdown" version = "3.4.4" description = "Python implementation of John Gruber's Markdown." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1604,7 +1539,6 @@ testing = ["coverage", "pyyaml"] name = "markupsafe" version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1664,7 +1598,6 @@ files = [ name = "matplotlib-inline" version = "0.1.6" description = "Inline Matplotlib backend for Jupyter" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1679,7 +1612,6 @@ traitlets = "*" name = "memory-profiler" version = "0.60.0" description = "A module for monitoring memory usage of a python program" -category = "dev" optional = false python-versions = ">=3.4" files = [ @@ -1693,7 +1625,6 @@ psutil = "*" name = "mergedeep" version = "1.3.4" description = "A deep merge function for 🐍." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1705,7 +1636,6 @@ files = [ name = "mike" version = "1.1.2" description = "Manage multiple versions of your MkDocs-powered documentation" -category = "dev" optional = false python-versions = "*" files = [ @@ -1727,7 +1657,6 @@ test = ["coverage", "flake8 (>=3.0)", "shtab"] name = "mistune" version = "3.0.2" description = "A sane and fast Markdown parser with useful plugins and renderers" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1739,7 +1668,6 @@ files = [ name = "mkdocs" version = "1.5.3" description = "Project documentation with Markdown." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1772,7 +1700,6 @@ min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-imp name = "mkdocs-autorefs" version = "0.4.1" description = "Automatically link across pages in MkDocs." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1788,7 +1715,6 @@ mkdocs = ">=1.1" name = "mkdocs-gen-files" version = "0.5.0" description = "MkDocs plugin to programmatically generate documentation pages during the build" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1803,7 +1729,6 @@ mkdocs = ">=1.0.3" name = "mkdocs-literate-nav" version = "0.6.1" description = "MkDocs plugin to specify the navigation in Markdown instead of YAML" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1818,7 +1743,6 @@ mkdocs = ">=1.0.3" name = "mkdocs-material" version = "9.2.7" description = "Documentation that simply works" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1843,7 +1767,6 @@ requests = ">=2.26,<3.0" name = "mkdocs-material-extensions" version = "1.2" description = "Extension pack for Python Markdown and MkDocs Material." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1855,7 +1778,6 @@ files = [ name = "mkdocs-section-index" version = "0.3.8" description = "MkDocs plugin to allow clickable sections that lead to an index page" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1870,7 +1792,6 @@ mkdocs = ">=1.2" name = "mkdocstrings" version = "0.20.0" description = "Automatic documentation from sources, for MkDocs." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1895,7 +1816,6 @@ python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] name = "mkdocstrings-python" version = "1.1.2" description = "A Python handler for mkdocstrings." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1911,7 +1831,6 @@ mkdocstrings = ">=0.20" name = "mkdocstrings-python" version = "1.7.3" description = "A Python handler for mkdocstrings." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1927,7 +1846,6 @@ mkdocstrings = ">=0.20" name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1939,7 +1857,6 @@ files = [ name = "nbclassic" version = "1.0.0" description = "Jupyter Notebook as a Jupyter Server extension." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1975,7 +1892,6 @@ test = ["coverage", "nbval", "pytest", "pytest-cov", "pytest-jupyter", "pytest-p name = "nbclient" version = "0.7.4" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -1985,7 +1901,7 @@ files = [ [package.dependencies] jupyter-client = ">=6.1.12" -jupyter-core = ">=4.12,<5.0.0 || >=5.1.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" nbformat = ">=5.1" traitlets = ">=5.3" @@ -1998,7 +1914,6 @@ test = ["flaky", "ipykernel", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "p name = "nbconvert" version = "7.6.0" description = "Converting Jupyter Notebooks" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2037,7 +1952,6 @@ webpdf = ["pyppeteer (>=1,<1.1)"] name = "nbformat" version = "5.8.0" description = "The Jupyter Notebook format" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2060,7 +1974,6 @@ test = ["pep440", "pre-commit", "pytest", "testpath"] name = "nest-asyncio" version = "1.5.8" description = "Patch asyncio to allow nested event loops" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -2072,7 +1985,6 @@ files = [ name = "notebook" version = "6.5.4" description = "A web-based notebook environment for interactive computing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2107,7 +2019,6 @@ test = ["coverage", "nbval", "pytest", "pytest-cov", "requests", "requests-unixs name = "notebook-shim" version = "0.2.3" description = "A shim layer for notebook traits and config" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2125,7 +2036,6 @@ test = ["pytest", "pytest-console-scripts", "pytest-jupyter", "pytest-tornasync" name = "numpy" version = "1.21.6" description = "NumPy is the fundamental package for array computing with Python." -category = "main" optional = false python-versions = ">=3.7,<3.11" files = [ @@ -2166,7 +2076,6 @@ files = [ name = "numpy" version = "1.26.3" description = "Fundamental package for array computing in Python" -category = "main" optional = false python-versions = ">=3.9" files = [ @@ -2212,7 +2121,6 @@ files = [ name = "orjson" version = "3.9.7" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2282,7 +2190,6 @@ files = [ name = "outcome" version = "1.3.0.post0" description = "Capture the outcome of Python function calls." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2297,7 +2204,6 @@ attrs = ">=19.2.0" name = "packaging" version = "23.2" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2309,7 +2215,6 @@ files = [ name = "paginate" version = "0.5.6" description = "Divides large result sets into pages for easier browsing" -category = "dev" optional = false python-versions = "*" files = [ @@ -2320,7 +2225,6 @@ files = [ name = "pandas" version = "1.3.5" description = "Powerful data structures for data analysis, time series, and statistics" -category = "main" optional = false python-versions = ">=3.7.1" files = [ @@ -2353,7 +2257,7 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.17.3", markers = "platform_machine != \"aarch64\" and platform_machine != \"arm64\" and python_version < \"3.10\""}, + {version = ">=1.17.3", markers = "(platform_machine != \"aarch64\" and platform_machine != \"arm64\") and python_version < \"3.10\""}, {version = ">=1.19.2", markers = "platform_machine == \"aarch64\" and python_version < \"3.10\""}, {version = ">=1.20.0", markers = "platform_machine == \"arm64\" and python_version < \"3.10\""}, {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, @@ -2368,7 +2272,6 @@ test = ["hypothesis (>=3.58)", "pytest (>=6.0)", "pytest-xdist"] name = "pandocfilters" version = "1.5.0" description = "Utilities for writing pandoc filters in python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2380,7 +2283,6 @@ files = [ name = "parso" version = "0.8.3" description = "A Python Parser" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2396,7 +2298,6 @@ testing = ["docopt", "pytest (<6.0.0)"] name = "pathspec" version = "0.11.2" description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2408,7 +2309,6 @@ files = [ name = "pexpect" version = "4.8.0" description = "Pexpect allows easy control of interactive console applications." -category = "main" optional = false python-versions = "*" files = [ @@ -2423,7 +2323,6 @@ ptyprocess = ">=0.5" name = "pickleshare" version = "0.7.5" description = "Tiny 'shelve'-like database with concurrency support" -category = "main" optional = false python-versions = "*" files = [ @@ -2435,7 +2334,6 @@ files = [ name = "pkgutil-resolve-name" version = "1.3.10" description = "Resolve a name to an object." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2447,7 +2345,6 @@ files = [ name = "platformdirs" version = "3.11.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2466,7 +2363,6 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co name = "plotly" version = "5.18.0" description = "An open-source, interactive data visualization library for Python" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2482,7 +2378,6 @@ tenacity = ">=6.2.0" name = "pluggy" version = "1.2.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2501,7 +2396,6 @@ testing = ["pytest", "pytest-benchmark"] name = "prometheus-client" version = "0.17.1" description = "Python client for the Prometheus monitoring system." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2516,7 +2410,6 @@ twisted = ["twisted"] name = "prompt-toolkit" version = "3.0.39" description = "Library for building powerful interactive command lines in Python" -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -2531,7 +2424,6 @@ wcwidth = "*" name = "psutil" version = "5.9.6" description = "Cross-platform lib for process and system monitoring in Python." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -2560,7 +2452,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] name = "ptyprocess" version = "0.7.0" description = "Run a subprocess in a pseudo terminal" -category = "main" optional = false python-versions = "*" files = [ @@ -2572,7 +2463,6 @@ files = [ name = "py" version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -2584,7 +2474,6 @@ files = [ name = "pyarrow" version = "10.0.1" description = "Python library for Apache Arrow" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2622,7 +2511,6 @@ numpy = ">=1.16.6" name = "pyarrow" version = "15.0.0" description = "Python library for Apache Arrow" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2671,7 +2559,6 @@ numpy = ">=1.16.6,<2" name = "pyasn1" version = "0.5.0" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ @@ -2683,7 +2570,6 @@ files = [ name = "pycparser" version = "2.21" description = "C parser in Python" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2695,7 +2581,6 @@ files = [ name = "pydivert" version = "2.1.0" description = "Python binding to windivert driver" -category = "dev" optional = false python-versions = "*" files = [ @@ -2711,7 +2596,6 @@ test = ["codecov (>=2.0.5)", "hypothesis (>=3.5.3)", "mock (>=1.0.1)", "pytest ( name = "pygments" version = "2.16.1" description = "Pygments is a syntax highlighting package written in Python." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2726,7 +2610,6 @@ plugins = ["importlib-metadata"] name = "pymdown-extensions" version = "10.2.1" description = "Extension pack for Python Markdown." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2745,7 +2628,6 @@ extra = ["pygments (>=2.12)"] name = "pyopenssl" version = "24.0.0" description = "Python wrapper module around the OpenSSL library" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2764,7 +2646,6 @@ test = ["flaky", "pretend", "pytest (>=3.0.1)"] name = "pyparsing" version = "3.1.1" description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "dev" optional = false python-versions = ">=3.6.8" files = [ @@ -2779,7 +2660,6 @@ diagrams = ["jinja2", "railroad-diagrams"] name = "pyrsistent" version = "0.19.3" description = "Persistent/Functional/Immutable data structures" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2816,7 +2696,6 @@ files = [ name = "pysocks" version = "1.7.1" description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2829,7 +2708,6 @@ files = [ name = "pytest" version = "6.2.5" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2855,7 +2733,6 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm name = "pytest-base-url" version = "2.0.0" description = "pytest plugin for URL based testing" -category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -2871,7 +2748,6 @@ requests = ">=2.9" name = "pytest-cov" version = "3.0.0" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2890,7 +2766,6 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-html" version = "3.2.0" description = "pytest plugin for generating HTML reports" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2907,7 +2782,6 @@ pytest-metadata = "*" name = "pytest-lazy-fixture" version = "0.6.3" description = "It helps to use fixtures in pytest.mark.parametrize" -category = "dev" optional = false python-versions = "*" files = [ @@ -2922,7 +2796,6 @@ pytest = ">=3.2.5" name = "pytest-metadata" version = "2.0.4" description = "pytest plugin for test session metadata" -category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -2937,7 +2810,6 @@ pytest = ">=3.0.0,<8.0.0" name = "pytest-selenium" version = "2.0.1" description = "pytest plugin for Selenium" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2961,7 +2833,6 @@ appium = ["appium-python-client (>=0.44)"] name = "pytest-variables" version = "2.0.0" description = "pytest plugin for providing variables to tests/fixtures" -category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -2981,7 +2852,6 @@ yaml = ["PyYAML"] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -2996,7 +2866,6 @@ six = ">=1.5" name = "pytz" version = "2023.3.post1" description = "World timezone definitions, modern and historical" -category = "main" optional = false python-versions = "*" files = [ @@ -3008,7 +2877,6 @@ files = [ name = "pywin32" version = "306" description = "Python for Window Extensions" -category = "main" optional = false python-versions = "*" files = [ @@ -3032,7 +2900,6 @@ files = [ name = "pywinpty" version = "2.0.10" description = "Pseudo terminal support for Windows from Python." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3048,7 +2915,6 @@ files = [ name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3057,7 +2923,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -3065,15 +2930,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -3090,7 +2948,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -3098,7 +2955,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -3108,7 +2964,6 @@ files = [ name = "pyyaml-env-tag" version = "0.1" description = "A custom YAML tag for referencing environment variables in YAML files. " -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3123,7 +2978,6 @@ pyyaml = "*" name = "pyzmq" version = "25.1.2" description = "Python bindings for 0MQ" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -3229,7 +3083,6 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} name = "regex" version = "2022.10.31" description = "Alternative regular expression module, to replace re." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3327,7 +3180,6 @@ files = [ name = "requests" version = "2.31.0" description = "Python HTTP for Humans." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3349,7 +3201,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "retrying" version = "1.3.4" description = "Retrying" -category = "main" optional = false python-versions = "*" files = [ @@ -3364,7 +3215,6 @@ six = ">=1.7.0" name = "ruff" version = "0.0.262" description = "An extremely fast Python linter, written in Rust." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3391,7 +3241,6 @@ files = [ name = "selenium" version = "4.2.0" description = "" -category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -3407,7 +3256,6 @@ urllib3 = {version = ">=1.26,<2.0", extras = ["secure", "socks"]} name = "selenium-wire" version = "5.1.0" description = "Extends Selenium to give you the ability to inspect requests made by the browser." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3438,7 +3286,6 @@ dev = ["black", "bumpversion", "coverage", "flake8", "gunicorn", "httpbin", "iso name = "send2trash" version = "1.8.2" description = "Send file to trash natively under Mac OS X, Windows and Linux" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -3455,7 +3302,6 @@ win32 = ["pywin32"] name = "setuptools" version = "68.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3472,7 +3318,6 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs ( name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -3484,7 +3329,6 @@ files = [ name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3496,7 +3340,6 @@ files = [ name = "sortedcontainers" version = "2.4.0" description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" -category = "dev" optional = false python-versions = "*" files = [ @@ -3508,7 +3351,6 @@ files = [ name = "soupsieve" version = "2.4.1" description = "A modern CSS selector implementation for Beautiful Soup." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3520,7 +3362,6 @@ files = [ name = "tenacity" version = "6.3.1" description = "Retry code until it succeeds" -category = "main" optional = false python-versions = "*" files = [ @@ -3538,7 +3379,6 @@ doc = ["reno", "sphinx", "tornado (>=4.5)"] name = "terminado" version = "0.17.1" description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3559,7 +3399,6 @@ test = ["pre-commit", "pytest (>=7.0)", "pytest-timeout"] name = "tinycss2" version = "1.2.1" description = "A tiny CSS parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3578,7 +3417,6 @@ test = ["flake8", "isort", "pytest"] name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -3590,7 +3428,6 @@ files = [ name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3602,7 +3439,6 @@ files = [ name = "tornado" version = "6.2" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." -category = "main" optional = false python-versions = ">= 3.7" files = [ @@ -3623,7 +3459,6 @@ files = [ name = "traitlets" version = "5.9.0" description = "Traitlets Python configuration system" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3639,7 +3474,6 @@ test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"] name = "trio" version = "0.22.2" description = "A friendly Python library for async concurrency and I/O" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3660,7 +3494,6 @@ sortedcontainers = "*" name = "trio-websocket" version = "0.11.1" description = "WebSocket library for Trio" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3677,7 +3510,6 @@ wsproto = ">=0.14" name = "tsdownsample" version = "0.1.3" description = "Time series downsampling in rust" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3763,7 +3595,6 @@ numpy = "*" name = "typed-ast" version = "1.5.5" description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3814,7 +3645,6 @@ files = [ name = "typing-extensions" version = "4.7.1" description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3826,7 +3656,6 @@ files = [ name = "urllib3" version = "1.26.18" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -3851,7 +3680,6 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] name = "urllib3-secure-extra" version = "0.1.0" description = "Marker library to detect whether urllib3 was installed with the deprecated [secure] extra" -category = "dev" optional = false python-versions = "*" files = [ @@ -3863,7 +3691,6 @@ files = [ name = "verspec" version = "0.1.0" description = "Flexible version handling" -category = "dev" optional = false python-versions = "*" files = [ @@ -3878,7 +3705,6 @@ test = ["coverage", "flake8 (>=3.7)", "mypy", "pretend", "pytest"] name = "watchdog" version = "3.0.0" description = "Filesystem events monitoring" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3918,7 +3744,6 @@ watchmedo = ["PyYAML (>=3.10)"] name = "wcwidth" version = "0.2.9" description = "Measures the displayed width of unicode strings in a terminal" -category = "main" optional = false python-versions = "*" files = [ @@ -3930,7 +3755,6 @@ files = [ name = "webencodings" version = "0.5.1" description = "Character encoding aliases for legacy web content" -category = "dev" optional = false python-versions = "*" files = [ @@ -3942,7 +3766,6 @@ files = [ name = "websocket-client" version = "1.6.1" description = "WebSocket client for Python with low level API options" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3959,7 +3782,6 @@ test = ["websockets"] name = "werkzeug" version = "2.2.3" description = "The comprehensive WSGI web application library." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3977,7 +3799,6 @@ watchdog = ["watchdog"] name = "widgetsnbextension" version = "3.6.6" description = "IPython HTML widgets for Jupyter" -category = "dev" optional = false python-versions = "*" files = [ @@ -3992,7 +3813,6 @@ notebook = ">=4.4.1" name = "wsproto" version = "1.2.0" description = "WebSockets state-machine based protocol implementation" -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -4007,7 +3827,6 @@ h11 = ">=0.9.0,<1" name = "zipp" version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4023,7 +3842,6 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more name = "zstandard" version = "0.21.0" description = "Zstandard bindings for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4079,9 +3897,9 @@ cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\ cffi = ["cffi (>=1.11)"] [extras] -inline-persistent = ["kaleido", "Flask-Cors", "jupyter-dash"] +inline-persistent = ["Flask-Cors", "jupyter-dash", "kaleido"] [metadata] lock-version = "2.0" python-versions = "^3.7.1" -content-hash = "1e8a6ac1a7cf5ed0f93b3e61b0b520d50dffa8cbdb8f597c7bb97acc1ce832b8" +content-hash = "73b4e112cdae8914af9fef53fd377f2b252df89ae825375fbf8b3129490b0d3b" diff --git a/pyproject.toml b/pyproject.toml index 0cc17ef6..12ad6c91 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ orjson = "^3.8.0" # Faster json serialization Flask-Cors = { version = "^3.0.10", optional = true } # Lock kaleido dependency until https://github.com/plotly/Kaleido/issues/156 is resolved kaleido = {version = "0.2.1", optional = true} -tsdownsample = "^0.1.2" +tsdownsample = ">=0.1.3" [tool.poetry.extras] # Optional dependencies diff --git a/tests/test_aggregators.py b/tests/test_aggregators.py index 3b4e92c4..b85dcd19 100644 --- a/tests/test_aggregators.py +++ b/tests/test_aggregators.py @@ -232,6 +232,51 @@ def test_wrap_aggregate_range_index_data_point_selection( assert x_agg[0] == -20_000 +# ------------------------------- NAN handling ------------------------------- +@pytest.mark.parametrize("downsampler", [MinMaxLTTB, MinMaxAggregator]) +@pytest.mark.parametrize("gap_handler", [MedDiffGapHandler, NoGapHandler]) +@pytest.mark.parametrize("series", [lf("float_series")]) +def test_nan_behavior(series, downsampler, gap_handler): + series = series.copy() + series.iloc[np.random.choice(len(series), 100)] = np.nan + + # OMIT -> no NaNs in the output + for n in np.random.randint(100, len(series), 6): + x_agg, y_agg, indices = wrap_aggregate( + hf_x=series.index, + hf_y=series.values, + downsampler=downsampler(nan_policy="omit"), + gap_handler=NoGapHandler(), + n_out=100, + ) + assert not pd.Series(y_agg).isna().any() + assert len(x_agg) == len(y_agg) == len(indices) + assert len(y_agg) <= n + (n % 2) + + # KEEP -> NaN will be returned in the output + for n in np.random.randint(100, len(series), 6): + x_agg, y_agg, indices = wrap_aggregate( + hf_x=series.index, + hf_y=series.values, + downsampler=downsampler(nan_policy="keep"), + gap_handler=NoGapHandler(), + n_out=100, + ) + assert pd.Series(y_agg).isna().any() + assert len(x_agg) == len(y_agg) == len(indices) + assert len(y_agg) <= n + (n % 2) + + ## INVALID nan_policy -> should raise a ValueError + with pytest.raises(ValueError): + wrap_aggregate( + hf_x=series.index, + hf_y=series.values, + downsampler=downsampler(nan_policy="invalid"), + gap_handler=NoGapHandler(), + n_out=100, + ) + + # # ------------------------------- DataAggregator ------------------------------- @pytest.mark.parametrize("agg_func", [np.mean]) # np.median, sum]) @pytest.mark.parametrize("series", [lf("float_series"), lf("bool_series")]) diff --git a/tests/test_figure_resampler.py b/tests/test_figure_resampler.py index f34e91df..ec6d68d6 100644 --- a/tests/test_figure_resampler.py +++ b/tests/test_figure_resampler.py @@ -467,36 +467,6 @@ def test_nan_removed_input(float_series): ) -def test_nan_removed_input_check_nans_false(float_series): - # see: https://plotly.com/python/subplots/#custom-sized-subplot-with-subplot-titles - base_fig = make_subplots( - rows=2, - cols=2, - specs=[[{}, {}], [{"colspan": 2}, None]], - ) - - fig = FigureResampler( - base_fig, - default_n_shown_samples=1000, - default_downsampler=EveryNthPoint(), - resampled_trace_prefix_suffix=( - '[R]', - '[R]', - ), - ) - - float_series = float_series.copy() - float_series.iloc[np.random.choice(len(float_series), 100)] = np.nan - fig.add_trace( - go.Scatter(x=float_series.index, y=float_series, name="float_series"), - row=1, - col=1, - hf_text="text", - hf_hovertext="hovertext", - check_nans=False, - ) - - def test_hf_text(): y = np.arange(10_000) diff --git a/tests/test_figurewidget_resampler.py b/tests/test_figurewidget_resampler.py index 795cbbdd..acba1373 100644 --- a/tests/test_figurewidget_resampler.py +++ b/tests/test_figurewidget_resampler.py @@ -297,39 +297,6 @@ def test_nan_removed_input(float_series): ) -def test_nan_removed_input_check_nans_false(float_series): - # see: https://plotly.com/python/subplots/#custom-sized-subplot-with-subplot-titles - base_fig = make_subplots( - rows=2, - cols=2, - specs=[[{}, {}], [{"colspan": 2}, None]], - ) - - fig = FigureWidgetResampler( - base_fig, - default_n_shown_samples=1000, - default_downsampler=EveryNthPoint(), - resampled_trace_prefix_suffix=( - '[R]', - '[R]', - ), - ) - - float_series = float_series.copy() - float_series.iloc[np.random.choice(len(float_series), 100)] = np.nan - fig.add_trace( - go.Scatter(x=float_series.index, y=float_series, name="float_series"), - row=1, - col=1, - hf_text="text", - hf_hovertext="hovertext", - check_nans=False, - ) - # Check the undesired behavior - assert len(fig.hf_data[0]["y"]) == len(float_series) - assert pd.isna(fig.hf_data[0]["y"]).any() - - def test_hf_text(): y = np.arange(10_000)