Skip to content
Snippets Groups Projects
Commit 85c216d5 authored by Peter Lünenschloß's avatar Peter Lünenschloß
Browse files

Merge branch 'docuUpdate_multiplot' into 'develop'

Docu update multiplot

See merge request !724
parents e57bc892 42b0fb87
No related branches found
No related tags found
1 merge request!724Docu update multiplot
Pipeline #187309 passed with stages
in 5 minutes and 7 seconds
......@@ -10,7 +10,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
[List of commits](https://git.ufz.de/rdm-software/saqc/-/compare/v2.4.0...develop)
### Added
- add multivariate plotting options to `plot`
- added `plot_kwargs` keyword to `plot` function
- added `plot_kwargs` keyword to `plot` function
- added checks and unified error message for common inputs.
- added command line `--version` option
- `-ll` CLI option as a shorthand for `--log-level`
......@@ -20,6 +20,9 @@ SPDX-License-Identifier: GPL-3.0-or-later
- pin pandas to versions >= 2.0
- parameter `fill_na` of `SaQC.flagUniLOF` and `SaQC.assignUniLOF` is now of type
`bool` instead of one of `[None, "linear"]`
- in `plot` function: changed default color for single variables to `black` with `80% transparency`
- in `plot` function: added seperate legend for flags
### Removed
- removed deprecated `DictOfSeries.to_df`
- removed plotting option with complete history (`history="complete"`)
......
......@@ -246,17 +246,14 @@ Check out the results for the year *2016*
.. doctest:: exampleMV
>>> plt.plot(qc.data['sac254_raw']['2016'], alpha=.5, color='black', label='original') # doctest:+SKIP
>>> plt.plot(qc.data['sac254_corrected']['2016'], color='black', label='corrected') # doctest:+SKIP
>>> qc.plot(['sac254_raw','sac254_corrected'], xscope='2016', plot_kwargs={'color':['black', 'black'], 'alpha':[.5, 1], 'label':['original', 'corrrected']}) # doctest:+SKIP
.. plot::
:context:
:include-source: False
plt.figure(figsize=(16,9))
plt.plot(qc.data['sac254_raw']['2016'], alpha=.5, color='black', label='original')
plt.plot(qc.data['sac254_corrected']['2016'], color='black', label='corrected')
plt.legend()
>>> qc.plot(['sac254_raw','sac254_corrected'], xscope='2016', plot_kwargs={'color':['black', 'black'], 'alpha':[.5, 1], 'label':['original', 'corrrected']})
Multivariate Flagging Procedure
-------------------------------
......
......@@ -255,25 +255,11 @@ This function object, we can pass on to the :py:meth:`~saqc.SaQC.processGeneric`
Visualisation
-------------
We can obtain those updated informations by generating a `pandas dataframe <https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html>`_
representation of it, with the :py:attr:`data <saqc.core.core.SaQC.data>` method:
To see all the results obtained so far, plotted in one figure window, we make use of the :py:meth:`~saqc.SaQC.plot` method.
.. doctest:: exampleOD
>>> data = qc.data
.. plot::
:context:
:include-source: False
data = qc.data
To see all the results obtained so far, plotted in one figure window, we make use of the dataframes `plot <https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.plot.html>`_ method.
.. doctest:: exampleOD
>>> data.to_pandas().plot()
<Axes...>
>>> qc.plot(".", regex=True) # doctest: +SKIP
.. plot::
:context:
......@@ -281,7 +267,7 @@ To see all the results obtained so far, plotted in one figure window, we make us
:width: 80 %
:class: center
data.to_pandas().plot()
qc.plot(".", regex=True)
Residuals and Scores
......
......@@ -37,7 +37,6 @@ Example Data
:context: close-figs
:include-source: False
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import saqc
......
......@@ -306,9 +306,16 @@ class ToolsMixin:
* ``"cycleskip"``: (int) start the cycle of shapes that are assigned any flag-type with a certain lag - defaults to ``0`` (no skip)
plot_kwargs :
Keywords to modify data line appearance. The markers are set via the
`matplotlib.pyplot.plot <https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.scatter.html>`_
method and can have the options listed there.
Keywords to modify the plot appearance. The plotting is delegated to
`matplotlib.pyplot.plot <https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.scatter.html>`_, all options listed there are available. Additionally the following saqc specific configurations are possible:
* ``"alpha"``: Either a scalar float in *[0,1]*, that determines all plots' transparencies, or
a list of floats, matching the number of variables to plot.
* ``"linewidth"``: Either single float in *[0,1]*, that determines the thickness of all plotted,
or a list of floats, matching the number of variables to plot.
Notes
-----
......
......@@ -35,7 +35,7 @@ MARKER_COL_CYCLE = [
]
# default color cycle for plot colors (many-in-one-plots)
PLOT_COL_CYCLE = MARKER_COL_CYCLE # itertools.cycle(MARKER_COL_CYCLE)
PLOT_COL_CYCLE = [(0, 0, 0)] + MARKER_COL_CYCLE # itertools.cycle(MARKER_COL_CYCLE)
# default data plot configuration (color kwarg only effective for many-to-one-plots)
PLOT_KWARGS = {"alpha": 0.8, "linewidth": 1, "color": PLOT_COL_CYCLE}
......@@ -248,14 +248,15 @@ def makeFig(
mode,
)
# readability formattin fo the x-tick labels:
fig.autofmt_xdate()
return fig
def _instantiateKwargContext(
def _instantiateAxesContext(
plot_kwargs, scatter_kwargs, ax_kwargs, var_num, var_name, mode
):
_scatter_mem = {}
_plot_kwargs = plot_kwargs.copy()
_scatter_kwargs = scatter_kwargs.copy()
_ax_kwargs = ax_kwargs.copy()
_scatter_mem = {}
......@@ -286,7 +287,6 @@ def _instantiateKwargContext(
_ax_kwargs["title"] = var_name if title is None else title
return (
_plot_kwargs,
_scatter_kwargs,
_ax_kwargs,
_scatter_mem,
......@@ -379,6 +379,26 @@ def _configMarkers(
return flags_i, _scatter_kwargs, _scatter_mem, marker_shape_cycle, marker_col_cycle
def _instantiatePlotContext(plot_kwargs, mode, var_name, var_num, plot_col_cycle):
_plot_kwargs = plot_kwargs.copy()
# get current plot color from plot color cycle
_plot_kwargs["color"] = next(plot_col_cycle)
# assign variable specific plot appearance
for plot_spec in ["alpha", "linewidth", "label"]:
spec = plot_kwargs.get(plot_spec, None)
if isinstance(spec, list):
_plot_kwargs[plot_spec] = spec[var_num]
elif isinstance(spec, dict):
_plot_kwargs[plot_spec] = spec.get(var_name, None)
if mode == "oneplot":
_plot_kwargs["label"] = _plot_kwargs.get("label", None) or var_name
# when plotting in subplots, plot black line and label it as 'data' (if not opted otherwise)
else:
_plot_kwargs["label"] = _plot_kwargs.get("label", None) or "data"
return _plot_kwargs
def _plotVarWithFlags(
axes,
dat_dict,
......@@ -410,25 +430,19 @@ def _plotVarWithFlags(
# every time, axis target is fresh, reinstantiate the kwarg-contexts :
if var_num == 0 or mode == "subplots":
(
_plot_kwargs,
_scatter_kwargs,
_ax_kwargs,
_scatter_mem,
marker_col_cycle,
marker_shape_cycle,
) = _instantiateKwargContext(
) = _instantiateAxesContext(
plot_kwargs, scatter_kwargs, ax_kwargs, var_num, var_name, mode
)
ax.set(**_ax_kwargs)
# get current color from plot color cycle
_plot_kwargs["color"] = next(plot_col_cycle)
if mode == "oneplot":
_plot_kwargs["label"] = var_name
# when plotting in subplots, plot black line and label it as 'data' (if not opted otherwise)
else:
_plot_kwargs["label"] = _plot_kwargs.get("label", None) or "data"
_plot_kwargs = _instantiatePlotContext(
plot_kwargs, mode, var_name, var_num, plot_col_cycle
)
# plot the data
ax.plot(var_dat, **_plot_kwargs)
......@@ -482,12 +496,14 @@ def _plotVarWithFlags(
_scatter_kwargs,
)
_rmDupesFromLegend(ax, dat_dict)
_formatLegend(ax, dat_dict)
if mode == "subplots":
for ax in axes[1:]:
_formatLegend(ax, dat_dict)
return
def _rmDupesFromLegend(ax, dat_dict):
def _formatLegend(ax, dat_dict):
# the legend generated might contain dublucate entries, we remove those, since dubed entries are assigned all
# the same marker color and shape:
legend_h, legend_l = ax.get_legend_handles_labels()
......@@ -503,7 +519,18 @@ def _rmDupesFromLegend(ax, dat_dict):
legend_f.append((legend_h[l[0]], l[1]))
leg_l = [l[1] for l in legend_v] + [l[1] for l in legend_f]
leg_h = [l[0] for l in legend_v] + [l[0] for l in legend_f]
ax.legend(leg_h, leg_l)
# if more than one variable is plotted, list plot line and flag marker shapes in seperate
# legends
h_types = np.array([isinstance(h, mpl.lines.Line2D) for h in leg_h])
if sum(h_types) > 1:
lines_h = np.array(leg_h)[h_types]
lines_l = np.array(leg_l)[h_types]
flags_h = np.array(leg_h)[~h_types]
flags_l = np.array(leg_l)[~h_types]
ax.add_artist(plt.legend(flags_h, flags_l))
ax.legend(lines_h, lines_l)
else:
ax.legend(leg_h, leg_l)
return
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment