Skip to content
Merged
2 changes: 1 addition & 1 deletion argopy/fetchers.py
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,7 @@ def plot(self, ptype: str = "trajectory", **kwargs):
Calling this method will automatically trigger a call to the :class:`argopy.DataFetcher.load` method.

"""
self.load()
# self.load()
if ptype in ["dac", "institution"]:
if "institution" not in self.index:
self.to_index(full=True)
Expand Down
27 changes: 26 additions & 1 deletion argopy/plot/argo_colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def __init__(self, name: str = "Set1", N: int = None):
"ticklabels": ['PROBABLE', 'CONFIRMED', 'REGISTERED', 'OPERATIONAL', 'INACTIVE', 'CLOSED'],
},
"qc": {
"name": "Quality control flag scale",
"name": "Quality control flag scale for measurements",
"aka": ["qc_flag", "quality_control", "quality_control_flag", "quality_control_flag_scale"],
"constructor": self._colormap_quality_control_flag,
"ticks": np.arange(0, 9 + 1),
Expand All @@ -104,6 +104,19 @@ def __init__(self, name: str = "Set1", N: int = None):
"ticklabels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
},
"pqc": {
"name": "Quality control flag scale for whole profiles",
"aka": ["pqc_flag", "profile_qc", "profile_quality_control_flag", "profile_quality_control_flag", "profile_quality_control_flag_scale"],
"constructor": self._colormap_profile_quality_control_flag,
"ticks": ["N", "A", "B", "C", "D", "E", "F"],
"ticklabels": ["No QC performed",
"100% of profile good",
"75% - 100% of profile good",
"50% - 75% of profile good",
"25% - 50% of profile good",
"0% - 25% of profile good",
"0% of profile good"]
},
}
self.registered = self.name in self.list_valid_known_colormaps
self._colormap = self.cmap
Expand Down Expand Up @@ -270,6 +283,18 @@ def _colormap_quality_control_flag(self):
]
return mcolors.LinearSegmentedColormap.from_list(self.definition['name'], clist, 10)

def _colormap_profile_quality_control_flag(self):
"""Return a colormap for Profile QC flag"""
clist = ['#000000',
'#31FC03',
'#ADFC03',
'#FCBA03',
'#324CA8',
'#B22CC9',
'#FC1C03',
]
return mcolors.LinearSegmentedColormap.from_list(self.definition['name'], clist, 7)

@property
def cmap(self):
"""Discrete colormap as :class:`matplotlib.colors.LinearSegmentedColormap`
Expand Down
7 changes: 5 additions & 2 deletions argopy/plot/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,10 @@ def guess_cmap(hue):
if hue.lower() in ArgoColors().list_valid_known_colormaps:
cmap = hue.lower()
elif "qc" in hue.lower():
cmap = "qc"
if "profile_" not in hue.lower():
cmap = "qc"
else:
cmap = "pqc"
elif "mode" in hue.lower():
cmap = "data_mode"
elif "status_code" in hue.lower():
Expand Down Expand Up @@ -789,7 +792,7 @@ def get_vlabel(this_ds, this_v):
# ax.set_facecolor(bgcolor)

if cbar:
cbar = fig.colorbar(m, shrink=0.9, extend="both", ax=ax)
cbar = fig.colorbar(m, shrink=0.9, ax=ax)
cbar.ax.set_ylabel(get_vlabel(ds, this_param), rotation=90)

ylim = ax.get_ylim()
Expand Down
5 changes: 3 additions & 2 deletions argopy/stores/float/argo_float.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ class ArgoFloat(FloatStore):
af.plot.trajectory()
af.plot.trajectory(figsize=(18,18), padding=[1, 5])
af.plot.map('TEMP', pres=450, cmap='Spectral_r')
af.plot.map('DATA_MODE', cbar=False, legend=True)
af.plot.scatter('PSAL')
af.plot.map('DATA_MODE')
af.plot.scatter('TEMP')
af.plot.scatter('PSAL_QC')
af.plot.scatter('DOXY', ds='Sprof')
af.plot.scatter('MEASUREMENT_CODE', ds='Rtraj')

Expand Down
53 changes: 44 additions & 9 deletions argopy/stores/float/implementations/plot.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import numpy as np
from typing import Any

from ....plot import scatter_plot, scatter_map
from ....utils.lists import list_multiprofile_file_variables, list_bgc_s_variables
from ....plot import scatter_plot, scatter_map, ArgoColors
from ....utils import list_multiprofile_file_variables, list_bgc_s_variables, to_list
from ..extensions import ArgoFloatPlotProto


Expand All @@ -24,7 +24,7 @@ class ArgoFloatPlot(ArgoFloatPlotProto):

af.plot.map('TEMP', pres=450, cmap='Spectral_r')

af.plot.map('DATA_MODE', cbar=False, legend=True)
af.plot.map('DATA_MODE')

af.plot.scatter('PSAL')

Expand Down Expand Up @@ -143,8 +143,11 @@ def map(

from argopy import ArgoFloat
af = ArgoFloat(wmo)
af.plot.map('TEMP', pres=450, cmap='Spectral_r')
af.plot.map('DATA_MODE', cbar=False, legend=True)

af.plot.map('TEMP') # Plot pressure level closest to 0 by default
af.plot.map('PSAL', pres=450.)
af.plot.map('PROFILE_TEMP_QC')
af.plot.map('DATA_MODE')
"""

if ds == "prof" and param not in list_multiprofile_file_variables():
Expand Down Expand Up @@ -175,12 +178,29 @@ def map(
N_LEVELS=0
)

# Check if param will be plotted using a discrete and known Argo colormap
discrete, cmap = False, 'Spectral_r'
if "qc" in param.lower() or "mode" in param.lower():
discrete, cmap = True, None # Let scatter_map guess cmap

if "N_LEVELS" in self._obj.dataset(ds)[param].dims:
legend_title = "%s @ %s PRES level in [%0.1f-%0.1f] db" % (
param,
select,
bins[0],
bins[1],
)
else:
legend_title = param

default_kwargs = {
"x": "LONGITUDE",
"y": "LATITUDE",
"hue": param,
"legend": False,
"cbar": True,
"cmap": cmap,
"legend": True if discrete else False,
"cbar": False if discrete else True,
"legend_title": legend_title,
}
this_kwargs = {**default_kwargs, **kwargs}

Expand All @@ -189,7 +209,7 @@ def map(
return fig, ax, hdl

def scatter(self, param, ds="prof", **kwargs) -> Any:
"""Scatter plot for one dataset parameter
"""Scatter plot for a 2-dimensional dataset parameter

This method creates a 2D scatter plot with the :meth:`argopy.plot.scatter_plot` method.

Expand All @@ -207,14 +227,16 @@ def scatter(self, param, ds="prof", **kwargs) -> Any:
- :class:`matplotlib.figure.Figure`
- :class:`matplotlib.axes.Axes`
- list of patches
- :class:`matplotlib.colorbar.Colorbar`

Examples
--------
.. code-block:: python

from argopy import ArgoFloat
af = ArgoFloat(wmo)
af.plot.scatter('PSAL')
af.plot.scatter('TEMP')
af.plot.scatter('PSAL_QC') # Appropriate colormap automatically selected
af.plot.scatter('DOXY', ds='Sprof')
af.plot.scatter('MEASUREMENT_CODE', ds='Rtraj')

Expand All @@ -238,9 +260,22 @@ def scatter(self, param, ds="prof", **kwargs) -> Any:
default_kwargs = {"this_x": "JULD", "cbar": True}
this_kwargs = {**default_kwargs, **kwargs}

if "_QC" in param:
mycolors = ArgoColors('qc', 9)
this_kwargs.update({
"cmap": mycolors.cmap,
"vmin": 0,
"vmax": 9+1,
})

if this_kwargs["cbar"]:
fig, ax, m, cbar = scatter_plot(this_ds, param, **this_kwargs)
ax.set_title(self._default_title)

if "_QC" in param:
cbar.set_ticks(to_list([k + 0.5 for k in mycolors.ticklabels.keys()]))
cbar.set_ticklabels(to_list([k for k in mycolors.ticklabels.values()]))

return fig, ax, m, cbar
else:
fig, ax, m = scatter_plot(this_ds, param, **this_kwargs)
Expand Down
13 changes: 13 additions & 0 deletions argopy/stores/index/implementations/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ class ArgoIndexPlot(ArgoIndexPlotProto):

idx.plot.bar(by='dac')

.. code-block:: python
:caption: Full index vs query results

from argopy import ArgoIndex
idx = ArgoIndex(index_file='bgc-s')
idx.query.params('CHLA')

idx.plot.bar(by='profiler') # Plot query results (default)

idx.plot.bar(by='profiler', index=True) # Force plot of full index



See Also
--------
:class:`ArgoIndex.plot.trajectory`, :class:`ArgoIndex.plot.bar`
Expand Down
18 changes: 12 additions & 6 deletions argopy/tests/test_stores_float_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,18 @@ def test_plot_map_errors(self):
with pytest.raises(ValueError):
af.plot.map("NOT_A_BGC_PARAM", ds="Sprof")
with pytest.raises(ValueError):
af.plot.map("DOXY", ds="prof")
af.plot.map("NOT_A_TRAJ_PARAM", ds="Rtraj")

@requires_cartopy
@pytest.mark.parametrize(
"wmo", [VALID_WMO[0]], indirect=False, ids=[f"wmo={w}" for w in [VALID_WMO[0]]]
)
def test_plot_map(self, wmo):
@pytest.mark.parametrize(
"pres", [0., 200.], indirect=False, ids=[f"pres={p}" for p in [0., 200.]]
)
def test_plot_map(self, wmo, pres):
af = ArgoFloat(wmo, host=VALID_HOST, cache=True)
fig, ax, hdl = af.plot.map("TEMP", ds="prof")
fig, ax, hdl = af.plot.map("TEMP", pres=pres, ds="prof")
assert isinstance(fig, mpl.figure.Figure)
assert isinstance(ax, cartopy.mpl.geoaxes.GeoAxesSubplot)
mpl.pyplot.close(fig)
Expand All @@ -89,13 +92,16 @@ def test_plot_scatter_errors(self):
@pytest.mark.parametrize(
"cbar", [True, False], indirect=False, ids=[f"cbar={c}" for c in [True, False]]
)
def test_plot_scatter(self, wmo, cbar):
@pytest.mark.parametrize(
"param", ["TEMP", "TEMP_QC"], indirect=False, ids=[f"param={p}" for p in ["TEMP", "TEMP_QC"]]
)
def test_plot_scatter(self, wmo, cbar, param):
af = ArgoFloat(wmo, host=VALID_HOST, cache=True)

if cbar:
fig, ax, m, cbar = af.plot.scatter("TEMP", ds="prof", cbar=cbar)
fig, ax, m, cbar = af.plot.scatter(param, ds="prof", cbar=cbar)
else:
fig, ax, m = af.plot.scatter("TEMP", ds="prof", cbar=cbar)
fig, ax, m = af.plot.scatter(param, ds="prof", cbar=cbar)

assert isinstance(fig, mpl.figure.Figure)
assert isinstance(ax, mpl.axes.Axes)
Expand Down
Binary file added docs/_static/ArgoColors_pqc.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ArgoFloat_DATA_MODE.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ArgoFloat_MEASUREMENT_CODE.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ArgoFloat_PROFILE_PSAL_QC.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ArgoFloat_PSAL.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ArgoFloat_PSAL_QC.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ArgoFloat_TEMP.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ArgoFloat_TEMPscatter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ArgoFloat_trajectory.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ArgoIndex_dac.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ArgoIndex_institution.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ArgoIndex_profiler.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ArgoIndex_trajectory.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ArgoIndex_trajectory_ph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/bar_dac.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/bar_profiler.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/bar_profiler_whitegrid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/scatter_map_Spectral.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/scatter_map_datamode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/scatter_map_deployment_status.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/scatter_map_index.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/scatter_map_index_opts.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/scatter_map_qcflag.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/trajectory_sample.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
74 changes: 74 additions & 0 deletions docs/advanced-tools/stores/argofloat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,77 @@ The :class:`ArgoFloat` class is further used in **argopy** in the :class:`ArgoIn
for a_float in idx.iterfloats():
ds = a_float.open_dataset('meta')
print(a_float.WMO, ds['LAUNCH_DATE'].data)

.. _argofloat-visu:

Plotting features
-----------------
.. currentmodule:: argopy

The :class:`ArgoFloat` class come with a :class:`ArgoFloat.plot` accessor than can take several methods to quickly visualize data from the float:

Check all the detailed arguments on the API reference :class:`ArgoFloat.plot`.

.. tabs::

.. tab:: Simple trajectory

.. code-block:: python

from argopy import ArgoFloat
af = ArgoFloat(6903262)

af.plot.trajectory()
# af.plot.trajectory(figsize=(18,18), padding=[1, 5])

.. image:: ../../_static/ArgoFloat_trajectory.png

.. tab:: Data along trajectory

.. code-block:: python

from argopy import ArgoFloat
af = ArgoFloat(6903262)

af.plot.map('TEMP', pres=450, cmap='Spectral_r')

.. image:: ../../_static/ArgoFloat_TEMP.png

.. code-block:: python

from argopy import ArgoFloat
af = ArgoFloat(6903262)

af.plot.map('PROFILE_PSAL_QC')

.. image:: ../../_static/ArgoFloat_PROFILE_PSAL_QC.png

.. tab:: Data as a function of pressure

.. code-block:: python

from argopy import ArgoFloat
af = ArgoFloat(6903262)

af.plot.scatter('TEMP')

.. image:: ../../_static/ArgoFloat_TEMPscatter.png

Plotting QC will automatically select the appropriate colormap:

.. code-block:: python

af.plot.scatter('PSAL_QC')

.. image:: ../../_static/ArgoFloat_PSAL_QC.png

Note that by default, variables are loaded from the `prof` netcdf dataset, but variables from other netcdf dataset can also be plotted if the appropriate dataset is indicated with the `ds` argument:

.. code-block:: python

from argopy import ArgoFloat
af = ArgoFloat(6903262)

af.plot.scatter('MEASUREMENT_CODE', ds='Rtraj')

.. image:: ../../_static/ArgoFloat_MEASUREMENT_CODE.png
Loading