Skip to content

Commit

Permalink
Doc update, WT analysis fixed, added example notebook
Browse files Browse the repository at this point in the history
  • Loading branch information
MerlinDumeur committed Apr 12, 2024
1 parent b54e531 commit 2d142c4
Show file tree
Hide file tree
Showing 19 changed files with 373 additions and 972 deletions.
6 changes: 2 additions & 4 deletions doc/_templates/autosummary/class.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
{{ fullname | escape | underline}}
{{ objname | escape | underline}}

.. currentmodule:: {{ module }}

.. autoclass:: {{ objname }}
.. autoclass:: {{ fullname }}
6 changes: 2 additions & 4 deletions doc/_templates/autosummary/function.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
{{ fullname | escape | underline }}
{{ objname | escape | underline }}

.. currentmodule:: {{ module }}

.. autofunction:: {{ objname }}
.. autofunction:: {{ fullname }}
22 changes: 21 additions & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import sphinx
import numpydoc

from sphinx.ext.autosummary.generate import AutosummaryRenderer


# -- Project information -----------------------------------------------------

Expand All @@ -45,7 +47,7 @@
# 'sphinx_autodoc_typehints',
# 'sphinx_gallery.notebook',
# 'sphinx_bootstrap_theme',
# 'nbsphinx',
'nbsphinx',
'sphinx.ext.mathjax']

# Add any paths that contain templates here, relative to this directory.
Expand Down Expand Up @@ -272,3 +274,21 @@
"--InlineBackend.figure_formats={'svg', 'pdf'}",
"--InlineBackend.rc={'figure.dpi': 96}",
]

#%% Adjusting the displayed name of functions
# https://stackoverflow.com/a/72658470

# def smart_fullname(fullname):
# parts = fullname.split(".")
# return ".".join(parts[1:])


# def fixed_init(self, app, template_dir=None):
# AutosummaryRenderer.__old_init__(self, app, template_dir)
# self.env.filters["smart_fullname"] = smart_fullname


# AutosummaryRenderer.__old_init__ = AutosummaryRenderer.__init__
# AutosummaryRenderer.__init__ = fixed_init

#%%
9 changes: 9 additions & 0 deletions doc/examples.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
========
Examples
========

.. nbgallery::
:name: nb-gallery
:glob:

notebooks/Demo
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ Contents
:caption: Overview:

reference
examples
theory
766 changes: 171 additions & 595 deletions doc/notebooks/Demo.ipynb

Large diffs are not rendered by default.

64 changes: 45 additions & 19 deletions doc/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,36 @@ API Reference
=============

Multifractal Analysis
---------------------
=====================

.. currentmodule:: pymultifracs

:py:mod:`pymultifracs`:

.. autosummary::
:toctree: _autosummary
:caption: Multifractal analysis

wavelet_analysis
mfa

Dataclasses
```````````

Used to compute and store intermediary results

.. currentmodule:: pymultifracs
Used to compute and store intermediary results. Not meant to be created outside of the analysis functions.

.. autosummary::
:toctree: _autosummary
:caption: Multi Resolution Quantities

multiresquantity.WaveletDec
multiresquantity.WaveletLeader
multiresquantity.Wtwse

.. autosummary::
:toctree: _autosummary
:caption: Scaling Functions

scalingfunction.StructureFunction
scalingfunction.Cumulants
scalingfunction.MFSpectrum
Expand All @@ -37,46 +42,67 @@ Storing the multifractal analysis output
.. autosummary::
:toctree: _autosummary
:template: namedtuple.rst
:caption: Analysis output

utils.MFractalVar
utils.MFractalBiVar

Bivariate Analysis
------------------
Visualization
=============

:py:mod:`pymultifracs.viz`:

.. autosummary::
:toctree: _autosummary
:caption: Visualization

.. currentmodule:: pymultifracs.bivariate
viz.plot_psd


Bivariate Analysis
==================

:py:mod:`pymultifracs.bivariate`:

.. autosummary::
:toctree: _autosummary
:caption: Bivariate analysis

bimfa
BiStructureFunction
BiCumulants
bivariate.bimfa
bivariate.BiStructureFunction
bivariate.BiCumulants

Simulation
----------

.. currentmodule:: pymultifracs.simul
==========

:py:mod:`pymultifracs.simul`:

.. autosummary::
:toctree: _autosummary
:caption: Simulation

mrw
fbm
simul.mrw
simul.fbm


Utility functions
-----------------

.. currentmodule:: pymultifracs.utils
=================

:py:mod:`pymultifracs.utils`:

.. autosummary::
:toctree: _autosummary
:caption: Utility functions

utils.build_q_log

Outlier detection
=================

:py:mod:`pymultifracs.robust`:

.. autosummary::
:toctree: _autosummary
:caption: Robust estimation

build_q_log
robust.get_outliers
68 changes: 34 additions & 34 deletions notebooks/Outlier detection.ipynb

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions pymultifracs/multiresquantity.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def scale2freq(self, scale, sfreq):
freq : float | ndarray
Frequencies associated to `scales`.
"""
return pywt.scale2frequency(self.wt_name, scale) * sfreq
return pywt.scale2frequency(self.wt_name, 2 ** scale) * sfreq

def freq2scale(self, freq, sfreq):
"""
Expand All @@ -221,7 +221,7 @@ def freq2scale(self, freq, sfreq):
scales : float | ndarray
Scales associated to `freq`.
"""
return pywt.frequency2scale(self.wt_name, freq / sfreq)
return np.log2(pywt.frequency2scale(self.wt_name, freq / sfreq))

def max_scale_bootstrap(self, idx_reject=None):
"""
Expand Down Expand Up @@ -281,7 +281,7 @@ def get_values(self, j, idx_reject=None, reshape=False):
out, idx_reject, j, self.interval_size)

def plot(self, j1, j2, ax=None, vmin=None, vmax=None, cbar=True,
figsize=(2.5, 1), gamma=.3, nan_idx=None, signal_idx=0,
figsize=(4.5, 1.5), gamma=.3, nan_idx=None, signal_idx=0,
cbar_kw=None, cmap='magma'):
"""
Plot the multi-resolution quantity.
Expand Down Expand Up @@ -410,7 +410,7 @@ def get_wse(self, theta=.5, gamint=None):
gamint = self.gamint

if gamint == self.gamint:
return wavelet.compute_wse(self, theta, gamint)
return wavelet.compute_wse(self, theta)

if self.origin_mrq is not None:
return self.origin_mrq.compute_wse(theta, gamint)
Expand Down
3 changes: 2 additions & 1 deletion pymultifracs/regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ def prepare_weights(sf_nj_fun, weighted, n_ranges, j_min, j_max, scaling_ranges,
if weighted == 'Nj':

w = np.tile(
sf_nj_fun(floor(j_min), floor(j_max))[None, :, None, :],
sf_nj_fun(floor(j_min), floor(j_max)).astype(float)[
None, :, None, :],
(1, 1, n_ranges, 1))

elif weighted == 'bootstrap':
Expand Down
1 change: 1 addition & 0 deletions pymultifracs/robust/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .robust import get_outliers
48 changes: 43 additions & 5 deletions pymultifracs/robust/robust.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
# import hdbscan
# import umap

from .. import mfa
from ..utils import fast_power


Expand Down Expand Up @@ -1074,15 +1073,53 @@ def cluster_reject_leaders(j1, j2, cm, leaders, pelt_beta, verbose=False,
return idx_reject


def get_outliers(wt_coefs, scaling_ranges, robust_cm=False, verbose=False,
generalized=False, **reject_kw):
def get_outliers(wt_coefs, scaling_ranges, pelt_beta, threshold, pelt_jump=1,
robust_cm=False, verbose=False, generalized=False):
"""Detect outliers in a signal.
Parameters
----------
wt_coefs : WaveletDec
Input coefficients of the signal with outliers.
scaling_ranges : list[tuple[int, int]]
List of pairs of (j1, j2) ranges of scales for the linear regressions.
pelt_beta : float
Regularization parameter for the PELT segmentation.
threshold : float
Wasserstein distance threshold to indentify a segment as outlier.
pelt_jump : int
Optional, PELT algorithm checks segmentations every `pelt_jump` point.
robust_cm : bool
Whether to use robust cumulants in the detection.
generalized : bool
Whether to use the exponential power distribution model instead of
the normal distribution for the log 1-leaders in the detection.
verbose : bool, optional
Display figures outlining the detection process. If multiple signals
are being processed, will only show figures for the first signal.
Returns
-------
leaders : WaveletLeader
Wavelet 1-leaders used in the analysis.
idx_reject : dict[int, ndarray]
Dictionary associating to each scale the boolean mask of indices to
reject.
See Also
--------
mfa : Can be fed the output ``idx_reject``.
"""

from .. import mfa

p_exp = 1
n_cumul = 4 if generalized else 2

leaders = wt_coefs.get_leaders(p_exp, 1)

lwt = mfa(leaders, scaling_ranges=scaling_ranges, n_cumul=n_cumul)
lwt = mfa(leaders, scaling_ranges=scaling_ranges, n_cumul=n_cumul,
robust=robust_cm)

j2 = max(sr[1] for sr in scaling_ranges)
min_scale = min(sr[0] for sr in scaling_ranges)
Expand All @@ -1093,7 +1130,8 @@ def get_outliers(wt_coefs, scaling_ranges, robust_cm=False, verbose=False,

idx_reject = cluster_reject_leaders(
min_scale, j2, lwt.cumulants, leaders, verbose=verbose,
generalized=generalized, **reject_kw)
generalized=generalized, pelt_beta=pelt_beta, pelt_jump=pelt_jump,
threshold=threshold)

for j in range(min(idx_reject), max(idx_reject)):

Expand Down
Loading

0 comments on commit 2d142c4

Please sign in to comment.