From d8925cf1e59223ae2c540ba8b4f1041a7daf4dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20de=20Menten?= Date: Tue, 23 Dec 2025 15:49:49 +0100 Subject: [PATCH 1/5] FIX: fixed release date in changelog I have no idea why this was not changed by the release script --- doc/source/changes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/changes.rst b/doc/source/changes.rst index c433ea8ec..410d88c99 100644 --- a/doc/source/changes.rst +++ b/doc/source/changes.rst @@ -4,7 +4,7 @@ Version 0.35 ============ -In development. +Released on 2025-12-23. CORE ---- From 43fe592bcbb9d72727bbed212c828cf734f89491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20de=20Menten?= Date: Mon, 5 Jan 2026 12:42:14 +0100 Subject: [PATCH 2/5] FIX: mirror fixes to larray-editor changelog rendering issues also includes style improvements --- .../changes/editor/version_0_35.rst.inc | 132 ++++++++++-------- 1 file changed, 71 insertions(+), 61 deletions(-) diff --git a/doc/source/changes/editor/version_0_35.rst.inc b/doc/source/changes/editor/version_0_35.rst.inc index 7aeac275e..9187243e1 100644 --- a/doc/source/changes/editor/version_0_35.rst.inc +++ b/doc/source/changes/editor/version_0_35.rst.inc @@ -3,67 +3,73 @@ New features ^^^^^^^^^^^^ -* allow displaying *many* more different kinds of objects, and not only arrays - from larray. One specific goal when developing this new feature was speed. +* allow displaying **many** more different kinds of objects, and not only arrays + from LArray. One specific goal when developing this new feature was speed. Most of these viewers should be fast (when at all possible), even on (very) large datasets. We only support displaying (not editing) all the new types. The following types are supported so far (but adding more is relatively easy): - * Python builtin objects: - - tuple (including named tuple), list (sequences), dict (mappings), - dict views, memoryview and array + * Python **builtin** objects: + + - ``tuple`` (including named tuple), ``list`` (sequences), ``dict`` + (mappings), dict views, ``memoryview`` and ``array`` - text and binary files - * Python stdlib objects: - - pathlib.Path + + * Python **standard library** objects: + + - ``pathlib.Path`` + * if the path points to a directory, it will display the content of the directory * if the path points to a file, it will try to display it, if we implemented support for that file type (see below for the list of supported types). - - sqlite3.Connection (and their tables) - - pstats.Stats (results of Python's profiler) - - zipfile.ZipFile and zipfile.Path - * new objects from LArray: Axis, Excel Workbook (what you get from - larray.open_excel()), Sheets and Range - * IODE "collections" objects: Comments, Equations, Identities, Lists, Tables, - Scalars and Variables, as well as Table objects - * Pandas: DataFrame, Series and DataFrameGroupBy - * Polars: DataFrame and LazyFrame - * Numpy: ndarray - * PyArrow: Array, Table, RecordBatchFileReader (reader object for feather - files) and ParquetFile - * Narwhals: DataFrame and LazyFrame - * PyTables: File, Group (with special support for Pandas DataFrames written - in HDF files), Array and Table - * IBIS: Table - * DuckDB: DuckDBPyConnection and DuckDBPyRelation (what you receive from any - query) - - File types (extensions) currently supported: - - Iode files: .ac, .ae, .ai, .al, .as, .at, .av, .cmt, .eqs, .idt, .lst, - .scl, .tbl, .var - - Text files: .bat, .c, .cfg, .cpp, .h, .htm, .html, .ini, .log, .md, - .py, .pyx, .pxd, .rep, .rst, .sh, .sql, .toml, .txt, .wsgi, - .yaml, .yml - - HDF5 files: .h5, .hdf - - Parquet files: .parquet - - Stata files: .dta - - Feather files: .feather - - SAS files: .sas7bdat - It is limited to the first few thousand rows (the exact number depends on - the number of columns), because reading later rows get increasingly slow, - to the point of being unusable. - - CSV files: .csv - - Gzipped CSV files: .csv.gz - - Excel files: .xls, .xlsx - - Zip files: .zip - - DuckDB files: .ddb, .duckdb - -* the editor now features a new "File Explorer" (accessible from the "File" + - ``sqlite3.Connection`` (and their tables) + - ``pstats.Stats`` (results of Python's profiler) + - ``zipfile.ZipFile`` and ``zipfile.Path`` + + * new objects from **LArray**: ``Axis``, Excel ``Workbook`` (what you get from + larray.open_excel()), ``Sheet`` and ``Range`` + * **IODE** "collections" objects: ``Comments``, ``Equations``, ``Identities``, + ``Lists``, ``Tables``, ``Scalars`` and ``Variables``, as well as ``Table`` + objects + * **Pandas** objects: ``DataFrame``, ``Series`` and ``DataFrameGroupBy`` + * **Polars** objects: ``DataFrame`` and ``LazyFrame`` + * **Numpy** objects: ``ndarray`` + * **PyArrow** objects: ``Array``, ``Table``, ``RecordBatchFileReader`` + (reader object for feather files) and ``ParquetFile`` + * **Narwhals** objects: ``DataFrame`` and ``LazyFrame`` + * **PyTables** objects: ``File``, ``Group`` (with special support for Pandas + DataFrames written in HDF files), ``Array`` and ``Table`` + * **IBIS** objects: ``Table`` + * **DuckDB** objects: ``DuckDBPyConnection`` and ``DuckDBPyRelation`` (what + you receive from any query) + +File types (extensions) currently supported: + + - **IODE** files: .ac, .ae, .ai, .al, .as, .at, .av, .cmt, .eqs, .idt, .lst, + .scl, .tbl, .var + - **Text** files: .bat, .c, .cfg, .cpp, .h, .htm, .html, .ini, .log, .md, + .py, .pyx, .pxd, .rep, .rst, .sh, .sql, .toml, .txt, .wsgi, .yaml, .yml + - **HDF5** files: .h5, .hdf + - **Parquet** files: .parquet + - **Stata** files: .dta + - **Feather** files: .feather + - **SAS** files: .sas7bdat + It is limited to the first few thousand rows (the exact number depends on + the number of columns), because reading later rows get increasingly slow, + to the point of being unusable. + - **CSV** files: .csv + - Gzipped CSV files: .csv.gz + - **Excel** files: .xls, .xlsx + - **Zip** files: .zip + - **DuckDB** files: .ddb, .duckdb + +* the editor now features a new "**File Explorer**" (accessible from the "File" menu) so that one can more easily make use of all the above file viewers. -* added a new SQL Console (next to the iPython console) for querying Polars +* added a new **SQL Console** (next to the iPython console) for querying Polars structures (DataFrame, LazyFrame and Series) as SQL tables. The console features auto-completion for SQL keywords, table names and column names and stores the last 1000 queries (even across sessions). Recalling a query @@ -71,32 +77,36 @@ New features console, it searches through history with the current command as prefix. This console will only be present if the polars module is installed. -* allow sorting some objects by column by pressing on an horizontal label. +* allow **sorting** some objects by column by pressing on an horizontal label. This is currently implemented for the following objects: + - python built-in sequences (e.g. tuples and lists) - python pathlib.Path objects representing directories - LArray (only for 2D arrays) - - Pandas DataFrame - - Polars DataFrame and LazyFrame - - Narwhals LazyFrame + - Pandas ``DataFrame`` + - Polars ``DataFrame and ``LazyFrame`` + - Narwhals ``LazyFrame`` - SQLite tables - DuckDB relations -* allow filtering some objects by pressing on an horizontal label. +* allow **filtering** some objects by pressing on an horizontal label. This is currently implemented for the following objects: - - Pandas DataFrame - - Polars DataFrame and LazyFrame + + - Pandas ``DataFrame`` + - Polars ``DataFrame`` and ``LazyFrame`` - DuckDB relations * allow comparing arrays/sessions with different axes in :py:obj:`compare()`. The function gained ``align`` and ``fill_value`` arguments and the interface has a new combobox to change the alignment method during the comparison: - - outer: will use a label if it is in any array (ordered like the first array). - This is the default as it results in no information loss. - - inner: will use a label if it is in all arrays (ordered like the first array). - - left: will use the first array axis labels. - - right: will use the last array axis labels. - - exact: raise an error when axes are not equal. + + - *outer*: will use a label if it is in any array (ordered like the first array). + This is the default as it results in no information loss. + - *inner*: will use a label if it is in all arrays (ordered like the first array). + - *left*: will use the first array axis labels. + - *right*: will use the last array axis labels. + - *exact*: raise an error when axes are not equal. + Closes :editor_issue:`214` and :editor_issue:`251`. * double-clicking on a name in the variable list will open it in a new window From 27d675657a5cb2242cc6909d33b120c3fcfc85bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20de=20Menten?= Date: Tue, 6 Jan 2026 16:54:38 +0100 Subject: [PATCH 3/5] MAINT: update sphinx and sphinx-rtd-theme versions --- doc/requirements.txt | 6 +++--- doc/source/conf.py | 15 ++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/doc/requirements.txt b/doc/requirements.txt index 7b86168a3..b3af04838 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,5 +1,5 @@ # dependencies to run larray tutorials (via nbsphinx) -numpy >=1.22, <2.0.0 +numpy >=1.22 pandas >=0.20 matplotlib tables # ==pytables @@ -7,8 +7,8 @@ openpyxl pydantic ==2.12 # dependencies to actually build the documentation -sphinx ==5.3.0 -sphinx-rtd-theme ==1.1.1 +sphinx ==8.2.3 +sphinx-rtd-theme ==3.0.2 numpydoc # This only installs the python bindings for pandoc. It works on read-the-docs # because it has a system-wide pandoc installed but elsewhere, installing diff --git a/doc/source/conf.py b/doc/source/conf.py index 617c02439..8a99cda3f 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -33,14 +33,14 @@ 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.doctest', - 'sphinx.ext.intersphinx', - 'sphinx.ext.viewcode', 'sphinx.ext.extlinks', - 'numpydoc', - 'nbsphinx', + 'sphinx.ext.intersphinx', 'sphinx.ext.mathjax', + 'sphinx.ext.viewcode', 'IPython.sphinxext.ipython_directive', 'IPython.sphinxext.ipython_console_highlighting', + 'numpydoc', + 'nbsphinx', 'sphinx_rtd_theme', ] @@ -91,7 +91,7 @@ templates_path = ['_templates'] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = {'.rst': 'restructuredtext'} # The encoding of source files. #source_encoding = 'utf-8-sig' @@ -101,7 +101,7 @@ # General information about the project. project = 'LArray' -copyright = '2014-2023, Gaëtan de Menten, Geert Bryon, Johan Duyck, Alix Damman' +copyright = '2014-2026, Gaëtan de Menten, Geert Bryon, Johan Duyck, Alix Damman' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -319,6 +319,7 @@ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False +# -- Options for intersphinx extension --------------------------------------- # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/3': None} +intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} From 46bf26f8ccd743d8ab0e6d777c79b60497ce7fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20de=20Menten?= Date: Tue, 6 Jan 2026 17:00:55 +0100 Subject: [PATCH 4/5] DOC: document how to create the environment to build the documentation locally --- doc/requirements.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/requirements.txt b/doc/requirements.txt index b3af04838..2c47bee5e 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,3 +1,11 @@ +# To create the environment used to build the documentation: +# > conda create -n larray_doc2026 python=3.13 +# > conda activate -n larray_doc2026 +# > pip install -r .\doc\requirements.txt +# > cd +# > pip install -e . +# > cd +# > pip install -e . # dependencies to run larray tutorials (via nbsphinx) numpy >=1.22 pandas >=0.20 From 83c1a482e4e43cb9a3cd0605f6ea5da9f1004578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20de=20Menten?= Date: Tue, 6 Jan 2026 17:02:52 +0100 Subject: [PATCH 5/5] DOC: fixed a few documentation rendering issues also avoid useless indentation in docstrings --- larray/core/array.py | 375 ++++++++++++++++++++++-------------------- larray/core/ufuncs.py | 160 +++++++++--------- 2 files changed, 278 insertions(+), 257 deletions(-) diff --git a/larray/core/array.py b/larray/core/array.py index 347a67ec2..a88920346 100644 --- a/larray/core/array.py +++ b/larray/core/array.py @@ -601,167 +601,175 @@ def get_axis(obj, i): _arg_agg = { 'q': """ - q : int in range of [0,100] (or sequence of floats) - Percentile to compute, which must be between 0 and 100 inclusive.""" +q : int in range of [0,100] (or sequence of floats) + Percentile to compute, which must be between 0 and 100 inclusive.""" } _kwarg_agg = { 'dtype': {'value': None, 'doc': """ - dtype : dtype, optional - The data type of the returned array. Defaults to None (the dtype of the input array)."""}, +dtype : dtype, optional + The data type of the returned array. Defaults to None (the dtype of the input array)."""}, 'out': {'value': None, 'doc': """ - out : Array, optional - Alternate output array in which to place the result. It must have the same shape as the expected output and - its type is preserved (e.g., if dtype(out) is float, the result will consist of 0.0's and 1.0's). - Axes and labels can be different, only the shape matters. Defaults to None (create a new array)."""}, +out : Array, optional + Alternate output array in which to place the result. It must have + the same shape as the expected output and its type is preserved + (e.g., if dtype(out) is float, the result will consist of 0.0's and + 1.0's). Axes and labels can be different, only the shape matters. + Defaults to None (create a new array)."""}, 'ddof': {'value': 1, 'doc': """ - ddof : int, optional - "Delta Degrees of Freedom": the divisor used in the calculation is ``N - ddof``, where ``N`` represents - the number of elements. Defaults to 1."""}, +ddof : int, optional + "Delta Degrees of Freedom": the divisor used in the calculation is + ``N - ddof``, where ``N`` represents the number of elements. + Defaults to 1."""}, 'skipna': {'value': None, 'doc': """ - skipna : bool, optional - Whether to skip NaN (null) values. If False, resulting cells will be NaN if any of the aggregated - cells is NaN. Defaults to True."""}, +skipna : bool, optional + Whether to skip NaN (null) values. If False, resulting cells will be NaN if any of the aggregated + cells is NaN. Defaults to True."""}, 'keepaxes': {'value': False, 'doc': """ - keepaxes : bool or label-like, optional - Whether reduced axes are left in the result as dimensions with size one. - If True, reduced axes will contain a unique label representing the applied aggregation - (e.g. 'sum', 'prod', ...). It is possible to override this label by passing a specific value - (e.g. keepaxes='summation'). Defaults to False."""}, +keepaxes : bool or label-like, optional + Whether reduced axes are left in the result as dimensions with size one. + If True, reduced axes will contain a unique label representing the applied aggregation + (e.g. 'sum', 'prod', ...). It is possible to override this label by passing a specific value + (e.g. keepaxes='summation'). Defaults to False."""}, 'method': {'value': 'linear', 'doc': """ - method : str, optional - This parameter specifies the method to use for estimating the - percentile when the desired percentile lies between two indexes. - The different methods supported are described in the Notes section. The options are: - * 'inverted_cdf' - * 'averaged_inverted_cdf' - * 'closest_observation' - * 'interpolated_inverted_cdf' - * 'hazen' - * 'weibull' - * 'linear' (default) - * 'median_unbiased' - * 'normal_unbiased' - * 'lower' - * 'higher' - * 'midpoint' - * 'nearest' - The first three and last four methods are discontinuous. Defaults to 'linear'."""} +method : str, optional + This parameter specifies the method to use for estimating the + percentile when the desired percentile lies between two indexes. + + The different methods supported are described in the Notes section. + The options are: + + * 'inverted_cdf' + * 'averaged_inverted_cdf' + * 'closest_observation' + * 'interpolated_inverted_cdf' + * 'hazen' + * 'weibull' + * 'linear' (default) + * 'median_unbiased' + * 'normal_unbiased' + * 'lower' + * 'higher' + * 'midpoint' + * 'nearest' + + The first three and last four methods are discontinuous. + Defaults to 'linear'."""} } PERCENTILE_NOTES = """Notes - ----- - Given a vector ``V`` of length ``n``, the q-th percentile of ``V`` is - the value ``q/100`` of the way from the minimum to the maximum in a - sorted copy of ``V``. The values and distances of the two nearest - neighbors as well as the `method` parameter will determine the - percentile if the normalized ranking does not match the location of - ``q`` exactly. This function is the same as the median if ``q=50``, the - same as the minimum if ``q=0`` and the same as the maximum if - ``q=100``. - - The optional `method` parameter specifies the method to use when the - desired percentile lies between two indexes ``i`` and ``j = i + 1``. - In that case, we first determine ``i + g``, a virtual index that lies - between ``i`` and ``j``, where ``i`` is the floor and ``g`` is the - fractional part of the index. The final result is, then, an interpolation - of ``a[i]`` and ``a[j]`` based on ``g``. During the computation of ``g``, - ``i`` and ``j`` are modified using correction constants ``alpha`` and - ``beta`` whose choices depend on the ``method`` used. Finally, note that - since Python uses 0-based indexing, the code subtracts another 1 from the - index internally. - - The following formula determines the virtual index ``i + g``, the location - of the percentile in the sorted sample: - - .. math:: - i + g = (q / 100) * ( n - alpha - beta + 1 ) + alpha - - The different methods then work as follows - - inverted_cdf: - method 1 of H&F [1]_. - This method gives discontinuous results: - - * if g > 0 ; then take j - * if g = 0 ; then take i - - averaged_inverted_cdf: - method 2 of H&F [1]_. - This method give discontinuous results: - - * if g > 0 ; then take j - * if g = 0 ; then average between bounds - - closest_observation: - method 3 of H&F [1]_. - This method give discontinuous results: - - * if g > 0 ; then take j - * if g = 0 and index is odd ; then take j - * if g = 0 and index is even ; then take i - - interpolated_inverted_cdf: - method 4 of H&F [1]_. - This method give continuous results using: - - * alpha = 0 - * beta = 1 - - hazen: - method 5 of H&F [1]_. - This method give continuous results using: - - * alpha = 1/2 - * beta = 1/2 - - weibull: - method 6 of H&F [1]_. - This method give continuous results using: - - * alpha = 0 - * beta = 0 - - linear: - method 7 of H&F [1]_. - This method give continuous results using: - - * alpha = 1 - * beta = 1 - - median_unbiased: - method 8 of H&F [1]_. - This method is probably the best method if the sample - distribution function is unknown (see reference). - This method give continuous results using: - - * alpha = 1/3 - * beta = 1/3 - - normal_unbiased: - method 9 of H&F [1]_. - This method is probably the best method if the sample - distribution function is known to be normal. - This method give continuous results using: - - * alpha = 3/8 - * beta = 3/8 - - lower: - NumPy method kept for backwards compatibility. - Takes ``i`` as the interpolation point. - - higher: - NumPy method kept for backwards compatibility. - Takes ``j`` as the interpolation point. - - nearest: - NumPy method kept for backwards compatibility. - Takes ``i`` or ``j``, whichever is nearest. - - midpoint: - NumPy method kept for backwards compatibility. - Uses ``(i + j) / 2``.""" +----- +Given a vector ``V`` of length ``n``, the q-th percentile of ``V`` is +the value ``q/100`` of the way from the minimum to the maximum in a +sorted copy of ``V``. The values and distances of the two nearest +neighbors as well as the `method` parameter will determine the +percentile if the normalized ranking does not match the location of +``q`` exactly. This function is the same as the median if ``q=50``, the +same as the minimum if ``q=0`` and the same as the maximum if +``q=100``. + +The optional `method` parameter specifies the method to use when the +desired percentile lies between two indexes ``i`` and ``j = i + 1``. +In that case, we first determine ``i + g``, a virtual index that lies +between ``i`` and ``j``, where ``i`` is the floor and ``g`` is the +fractional part of the index. The final result is, then, an interpolation +of ``a[i]`` and ``a[j]`` based on ``g``. During the computation of ``g``, +``i`` and ``j`` are modified using correction constants ``alpha`` and +``beta`` whose choices depend on the ``method`` used. Finally, note that +since Python uses 0-based indexing, the code subtracts another 1 from the +index internally. + +The following formula determines the virtual index ``i + g``, the location +of the percentile in the sorted sample: + +.. math:: + i + g = (q / 100) * ( n - alpha - beta + 1 ) + alpha + +The different methods then work as follows + +inverted_cdf: + method 1 of H&F [1]_. + This method gives discontinuous results: + + * if g > 0 ; then take j + * if g = 0 ; then take i + +averaged_inverted_cdf: + method 2 of H&F [1]_. + This method give discontinuous results: + + * if g > 0 ; then take j + * if g = 0 ; then average between bounds + +closest_observation: + method 3 of H&F [1]_. + This method give discontinuous results: + + * if g > 0 ; then take j + * if g = 0 and index is odd ; then take j + * if g = 0 and index is even ; then take i + +interpolated_inverted_cdf: + method 4 of H&F [1]_. + This method give continuous results using: + + * alpha = 0 + * beta = 1 + +hazen: + method 5 of H&F [1]_. + This method give continuous results using: + + * alpha = 1/2 + * beta = 1/2 + +weibull: + method 6 of H&F [1]_. + This method give continuous results using: + + * alpha = 0 + * beta = 0 + +linear: + method 7 of H&F [1]_. + This method give continuous results using: + + * alpha = 1 + * beta = 1 + +median_unbiased: + method 8 of H&F [1]_. + This method is probably the best method if the sample + distribution function is unknown (see reference). + This method give continuous results using: + + * alpha = 1/3 + * beta = 1/3 + +normal_unbiased: + method 9 of H&F [1]_. + This method is probably the best method if the sample + distribution function is known to be normal. + This method give continuous results using: + + * alpha = 3/8 + * beta = 3/8 + +lower: + NumPy method kept for backwards compatibility. + Takes ``i`` as the interpolation point. + +higher: + NumPy method kept for backwards compatibility. + Takes ``j`` as the interpolation point. + +nearest: + NumPy method kept for backwards compatibility. + Takes ``i`` or ``j``, whichever is nearest. + +midpoint: + NumPy method kept for backwards compatibility. + Uses ``(i + j) / 2``.""" def _doc_agg_method(func, by=False, long_name='', action_verb='perform', extra_args=(), kwargs=()): @@ -774,7 +782,7 @@ def _doc_agg_method(func, by=False, long_name='', action_verb='perform', extra_a if by: specific_template = """The {long_name} is {action_verb}ed along all axes except the given one(s). - For groups, {long_name} is {action_verb}ed along groups and non associated axes.""" + For groups, {long_name} is {action_verb}ed along groups and non associated axes.""" else: specific_template = "Axis(es) or group(s) along which the {long_name} is {action_verb}ed." doc_specific = specific_template.format(long_name=long_name, action_verb=action_verb) @@ -782,34 +790,39 @@ def _doc_agg_method(func, by=False, long_name='', action_verb='perform', extra_a doc_args = "".join(_arg_agg[arg] for arg in extra_args) doc_kwargs = "".join(_kwarg_agg[kw]['doc'] for kw in kwargs) doc_varargs = fr""" - \*axes_and_groups : None or int or str or Axis or Group or any combination of those - {doc_specific} - The default (no axis or group) is to {action_verb} the {long_name} over all the dimensions of the input - array. - - An axis can be referred by: - - * its index (integer). Index can be a negative integer, in which case it counts from the last to the - first axis. - * its name (str or AxisReference). You can use either a simple string ('axis_name') or the special - variable X (X.axis_name). - * a variable (Axis). If the axis has been defined previously and assigned to a variable, you can pass it as - argument. - - You may not want to {action_verb} the {long_name} over a whole axis but over a selection of specific - labels. To do so, you have several possibilities: - - * (['a1', 'a3', 'a5'], 'b1, b3, b5') : labels separated by commas in a list or a string - * ('a1:a5:2') : select labels using a slice (general syntax is 'start:end:step' where is 'step' is - optional and 1 by default). - * (a='a1, a2, a3', X.b['b1, b2, b3']) : in case of possible ambiguity, i.e. if labels can belong to more - than one axis, you must precise the axis. - * ('a1:a3; a5:a7', b='b0,b2; b1,b3') : create several groups with semicolons. - Names are simply given by the concatenation of labels (here: 'a1,a2,a3', 'a5,a6,a7', 'b0,b2' and 'b1,b3') - * ('a1:a3 >> a123', 'b[b0,b2] >> b12') : operator ' >> ' allows to rename groups.""" +\*axes_and_groups : None or int or str or Axis or Group or any combination of those + {doc_specific} + The default (no axis or group) is to {action_verb} the {long_name} over all the dimensions of the input + array. + + An axis can be referred by: + + * its index (integer). Index can be a negative integer, in which case it counts from the last to the + first axis. + * its name (str or AxisReference). You can use either a simple string ('axis_name') or the special + variable X (X.axis_name). + * a variable (Axis). If the axis has been defined previously and assigned to a variable, you can pass it as + argument. + + You may not want to {action_verb} the {long_name} over a whole axis but over a selection of specific + labels. To do so, you have several possibilities: + + * (['a1', 'a3', 'a5'], 'b1, b3, b5') : labels separated by commas in a list or a string + * ('a1:a5:2') : select labels using a slice (general syntax is 'start:end:step' where is 'step' is + optional and 1 by default). + * (a='a1, a2, a3', X.b['b1, b2, b3']) : in case of possible ambiguity, i.e. if labels can belong to more + than one axis, you must precise the axis. + * ('a1:a3; a5:a7', b='b0,b2; b1,b3') : create several groups with semicolons. + Names are simply given by the concatenation of labels (here: 'a1,a2,a3', 'a5,a6,a7', 'b0,b2' and 'b1,b3') + * ('a1:a3 >> a123', 'b[b0,b2] >> b12') : operator ' >> ' allows to rename groups.""" parameters = f"""Parameters - ----------{doc_args}{doc_varargs}{doc_kwargs}""" - func.__doc__ = func.__doc__.format(signature=signature, parameters=parameters, percentile_notes=PERCENTILE_NOTES) +----------{doc_args}{doc_varargs}{doc_kwargs}""" + docstring = func.__doc__.format(signature=signature, parameters=parameters, + percentile_notes=PERCENTILE_NOTES) + # Compared to a normal/manual docstring, we get no indentation. We could + # add it here but that is not necessary. Tools like inspect.getdoc() + # strips any leading indentation anyway. + func.__doc__ = docstring _always_return_float = {np.mean, np.nanmean, np.median, np.nanmedian, np.percentile, np.nanpercentile, @@ -7220,10 +7233,12 @@ def plot(self) -> PlotObject: ax : matplotlib axes object, default None subplots : boolean, Axis, int, str or tuple, default False Make several subplots. + - if an Axis (or int or str), make subplots for each label of that axis. - if a tuple of Axis (or int or str), make subplots for each combination of labels of those axes. - True is equivalent to all axes except the last. + Defaults to False. sharex : boolean, default True if ax is None else False When subplots are used, share x axis and set some x axis labels to invisible; @@ -7278,18 +7293,23 @@ def plot(self) -> PlotObject: Error bars on x axis stack : boolean, Axis, int, str or tuple, optional Make a stacked plot. + - if an Axis (or int or str), stack that axis. - if a tuple of Axis (or int or str), stack each combination of labels of those axes. - True is equivalent to all axes (not already used in other arguments) except the last. + Defaults to False in line and bar plots, and True in area plot. animate : Axis, int, str or tuple, optional Make an animated plot. + - if an Axis (or int or str), animate that axis (create one image per label on that axis). One would usually use a time-related axis. - if a tuple of Axis (or int or str), animate each combination of labels of those axes. + Defaults to None. anim_params: dict, optional Optional parameters to control how animations are saved to file. + - writer : str, optional Backend to use. Defaults to 'pillow' for images (.gif .png and .tiff), 'ffmpeg' otherwise. @@ -7304,6 +7324,7 @@ def plot(self) -> PlotObject: means higher quality movies, but increase the file size. A value of -1 lets the underlying movie encoder select the bitrate. + **kwargs : keywords Options to pass to matplotlib plotting method diff --git a/larray/core/ufuncs.py b/larray/core/ufuncs.py index 481285a26..e12826a35 100644 --- a/larray/core/ufuncs.py +++ b/larray/core/ufuncs.py @@ -100,6 +100,7 @@ def wrap_numpy_func(func, doc=None): doc = f'{short_desc}\n\n{ident}larray specific variant of ``numpy.{func.__name__}``.\n\n' \ f'{ident}Documentation from numpy:{numpy_doc}' wrapper = wrap_elementwise_array_func(func, doc) + # set __qualname__ explicitly (all these functions are supposed to be top-level function in the ufuncs module) wrapper.__qualname__ = func.__name__ # we should not copy __module__ @@ -397,92 +398,91 @@ def _generalized_nan_to_num(arr, copy=True, nan=0, posinf=None, neginf=None): return np.nan_to_num(arr, copy=copy, nan=nan, posinf=posinf, neginf=neginf) nan_to_num = wrap_elementwise_array_func(_generalized_nan_to_num,r""" - Replace NaN with zero and infinity with large finite numbers (default - behaviour) or with the numbers defined by the user using the `nan`, - `posinf` and/or `neginf` keywords. +Replace NaN with zero and infinity with large finite numbers (default +behaviour) or with the numbers defined by the user using the `nan`, +`posinf` and/or `neginf` keywords. - If `x` is inexact or an object array, NaN is replaced by zero or by the user - defined value in `nan` keyword, infinity is replaced by the largest finite - floating point value representable by ``x.dtype`` or by the user defined - value in `posinf` keyword and -infinity is replaced by the most negative - finite floating point value representable by ``x.dtype`` or by the user - defined value in `neginf` keyword. +If `x` is inexact or an object array, NaN is replaced by zero or by the user +defined value in `nan` keyword, infinity is replaced by the largest finite +floating point value representable by ``x.dtype`` or by the user defined +value in `posinf` keyword and -infinity is replaced by the most negative +finite floating point value representable by ``x.dtype`` or by the user +defined value in `neginf` keyword. - For complex dtypes, the above is applied to each of the real and - imaginary components of `x` separately. +For complex dtypes, the above is applied to each of the real and +imaginary components of `x` separately. - If `x` is not inexact or object, then no replacements are made. +If `x` is not inexact or object, then no replacements are made. - Parameters - ---------- - x : scalar or array_like - Input data. - copy : bool, optional - Whether to create a copy of `x` (True) or to replace values - in-place (False). The in-place operation only occurs if - casting to an array does not require a copy. - Default is True. - nan : int, float or array_like, optional - Value to be used to fill NaN values. If no value is passed - then NaN values will be replaced with 0.0. - posinf : int, float, optional - Value to be used to fill positive infinity values. If no value is - passed then positive infinity values will be replaced with the largest - finite floating point value representable by ``x.dtype``. - neginf : int, float, optional - Value to be used to fill negative infinity values. If no value is - passed then negative infinity values will be replaced with the most - negative finite floating point value representable by ``x.dtype``. +Parameters +---------- +x : scalar or array_like + Input data. +copy : bool, optional + Whether to create a copy of `x` (True) or to replace values + in-place (False). The in-place operation only occurs if + casting to an array does not require a copy. + Default is True. +nan : int, float or array_like, optional + Value to be used to fill NaN values. If no value is passed + then NaN values will be replaced with 0.0. +posinf : int, float, optional + Value to be used to fill positive infinity values. If no value is + passed then positive infinity values will be replaced with the largest + finite floating point value representable by ``x.dtype``. +neginf : int, float, optional + Value to be used to fill negative infinity values. If no value is + passed then negative infinity values will be replaced with the most + negative finite floating point value representable by ``x.dtype``. - Returns - ------- - out : Array or scalar - `x`, with the non-finite values replaced. If `copy` is False, this may - be `x` itself. +Returns +------- +out : Array or scalar + `x`, with the non-finite values replaced. If `copy` is False, this may + be `x` itself. - See Also - -------- - isinf : Shows which elements are positive or negative infinity. - isneginf : Shows which elements are negative infinity. - isposinf : Shows which elements are positive infinity. - isnan : Shows which elements are Not a Number (NaN). - isfinite : Shows which elements are finite (not NaN, not infinity) +See Also +-------- +isinf : Shows which elements are positive or negative infinity. +isneginf : Shows which elements are negative infinity. +isposinf : Shows which elements are positive infinity. +isnan : Shows which elements are Not a Number (NaN). +isfinite : Shows which elements are finite (not NaN, not infinity) - Notes - ----- - Contrary to the numpy implementation, this function support object arrays. +Notes +----- +Contrary to the numpy implementation, this function support object arrays. - NumPy uses the IEEE Standard for Binary Floating-Point for Arithmetic - (IEEE 754). This means that Not a Number is not equivalent to infinity. +NumPy uses the IEEE Standard for Binary Floating-Point for Arithmetic +(IEEE 754). This means that Not a Number is not equivalent to infinity. - Examples - -------- - >>> import larray as la - - >>> la.nan_to_num(la.inf) - 1.7976931348623157e+308 - >>> la.nan_to_num(-la.inf) - -1.7976931348623157e+308 - >>> la.nan_to_num(np.nan) - 0.0 - - >>> x = la.Array([-la.inf, 1, la.nan, 2, la.inf], la.Axis(5, 'values')) - >>> la.nan_to_num(x) - values* 0 1 2 3 4 - -1.7976931348623157e+308 1.0 0.0 2.0 1.7976931348623157e+308 - >>> la.nan_to_num(x, nan=-1, posinf=999, neginf=-999) - values* 0 1 2 3 4 - -999.0 1.0 -1.0 2.0 999.0 - - >>> x = la.Array([1, 'abc', la.nan, 2], la.Axis(4, 'values'), dtype=object) - >>> la.nan_to_num(x) - values* 0 1 2 3 - 1 abc 0 2 - - >>> y = la.Array([complex(la.inf, la.nan), la.nan, complex(la.nan, la.inf)], - ... la.Axis(3, 'values')) - >>> la.nan_to_num(y) - values* 0 1 2 - (1.7976931348623157e+308+0j) 0j 1.7976931348623157e+308j - """ -) \ No newline at end of file +Examples +-------- +>>> import larray as la + +>>> la.nan_to_num(la.inf) +1.7976931348623157e+308 +>>> la.nan_to_num(-la.inf) +-1.7976931348623157e+308 +>>> la.nan_to_num(np.nan) +0.0 + +>>> x = la.Array([-la.inf, 1, la.nan, 2, la.inf], la.Axis(5, 'values')) +>>> la.nan_to_num(x) +values* 0 1 2 3 4 + -1.7976931348623157e+308 1.0 0.0 2.0 1.7976931348623157e+308 +>>> la.nan_to_num(x, nan=-1, posinf=999, neginf=-999) +values* 0 1 2 3 4 + -999.0 1.0 -1.0 2.0 999.0 + +>>> x = la.Array([1, 'abc', la.nan, 2], la.Axis(4, 'values'), dtype=object) +>>> la.nan_to_num(x) +values* 0 1 2 3 + 1 abc 0 2 + +>>> y = la.Array([complex(la.inf, la.nan), la.nan, complex(la.nan, la.inf)], +... la.Axis(3, 'values')) +>>> la.nan_to_num(y) +values* 0 1 2 + (1.7976931348623157e+308+0j) 0j 1.7976931348623157e+308j +""") \ No newline at end of file