netsse.tools.viz
================

.. py:module:: netsse.tools.viz

.. autoapi-nested-parse::

   **Data visualisation** functions for NetSSE.

   .. dropdown:: Copyright (C) 2023-2026 Technical University of Denmark, R.E.G. Mounet
       :color: primary
       :icon: law

       *This code is part of the NetSSE software.*

       NetSSE is free software: you can redistribute it and/or modify it under
       the terms of the GNU General Public License as published by the Free
       Software Foundation, either version 3 of the License, or (at your
       option) any later version.

       NetSSE is distributed in the hope that it will be useful, but WITHOUT
       ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       for more details.

       You should have received a copy of the GNU General Public License along
       with this program.  If not, see https://www.gnu.org/licenses/.

       To credit the author, users are encouraged to use below reference:

       .. code-block:: text

           Mounet, R. E. G., & Nielsen, U. D. NetSSE: An open-source Python package
           for network-based sea state estimation from ships, buoys, and other
           observation platforms (version 2.2). Technical University of Denmark,
           GitLab. February 2026. https://doi.org/10.11583/DTU.26379811.

   *Last updated on 09-02-2026 by R.E.G. Mounet*



Functions
---------

.. autoapisummary::

   netsse.tools.viz.plot_bathymetry
   netsse.tools.viz.plot_dirwavespec
   netsse.tools.viz.plot_sea_state_scatter


Module Contents
---------------

.. py:function:: plot_bathymetry(depths, shp_dict, ax, cmap='Blues_r')

   Plots the bathymetry map for a given area.

   The function plots the bathymetry map for a given area using the shapefiles contained in the
   dictionary `shp_dict`. The shapefiles are sorted by depth, from the surface to the bottom.

   :param depths: List of the depths in the shapefiles for the specified area.
   :type depths: list
   :param shp_dict: Dictionary containing the shapefiles.
   :type shp_dict: dict
   :param ax: Axes object to plot on.
   :type ax: matplotlib.axes
   :param cmap: Colormap to use for the plot. Default is ``'Blues_r'``.

                .. note::
                    Other colormap options include ``'plasma'``, ``'inferno'``, ``'magma'``, ``'viridis'``.
                    Visit the `Matplotlib documentation
                    <https://matplotlib.org/stable/tutorials/colors/colormaps.html>`_ for an overview of
                    the options.
   :type cmap: str, optional

   :returns: * **ax** (*matplotlib.axes._subplots.AxesSubplot*) -- The axes object with the plot.
             * **colormap** (*matplotlib.colors.ListedColormap*) -- The colormap used for the plot.

   .. seealso::

      :py:obj:`netsse.model.bathymetry.load_bathymetry`
          Retrieve and read bathymetry shapefiles.

   .. rubric:: Example

   .. code-block:: python

       import matplotlib.pyplot as plt
       import cartopy.crs as ccrs
       import cartopy.feature as cfeature
       from netsse.model.bathymetry import load_bathymetry
       from netsse.tools.viz import plot_bathymetry

       depths, shp_dict = load_bathymetry(lonmin=-5, lonmax=15, latmin=35, latmax=45)
       fig, ax = plt.subplots(subplot_kw={'projection':ccrs.Mercator(central_longitude=5,min_latitude=35,max_latitude=45)},figsize=(6,6))
       ax.set_extent([-5, 15, 35, 45], crs=ccrs.PlateCarree())
       ax, colormap = plot_bathymetry(depths, shp_dict, ax)
       ax.add_feature(cfeature.LAND,edgecolor='black',facecolor='gainsboro',alpha=0.5)


.. py:function:: plot_dirwavespec(spec, dirs, freqs, unit_dirs='deg', unit_freqs='Hz', levels=None, cmap='turbo', vmin=None, vmax=None, freq_max=None, show_dirlabels=True, show_freqlabels=True, rscale='linear', ax=None)

   Plots the input directional wave spectrum in a polar diagram.

   The plot shows the power spectral density (PSD) distribution over wave frequencies and
   directions.

   :param spec: Directional wave spectrum to be plotted. This must be a 2-D array of shape either
                `(Ndirs,Nfreqs)` or `(Nfreqs,Ndirs)`.
   :type spec: array_like
   :param dirs: Directions of the spectrum.
   :type dirs: array_like of shape (`Ndirs`,)
   :param freqs: Frequencies of the spectrum.
   :type freqs: array_like of shape (`Nfreqs`,)
   :param unit_dirs: Unit of the directions, either ``'deg'`` for degrees or ``'rad'`` for radians.
                     Default is ``'deg'``.
   :type unit_dirs: {'deg','rad'}, optional
   :param unit_freqs: Unit of the frequencies, either ``'Hz'`` for Hertz or ``'rad/s'`` for radians per second.
                      Default is ``'Hz'``.
   :type unit_freqs: {'Hz','rad/s'}, optional
   :param levels: Contour levels to use for the plot. If ``None``, levels are automatically determined
                  according to the formula below:

                  :math:`vmin*(vmax/vmin)^{i/29}` for :math:`i=0,1,...,29`.
                  Default is ``None``.
   :type levels: array_like, optional
   :param cmap: Colormap to use for the plot. Default is ``'turbo'``.

                .. note::
                    Other colormap options include ``'viridis'``, ``'plasma'``, ``'inferno'``, ``'magma'``.
                    Visit the `Matplotlib documentation
                    <https://matplotlib.org/stable/tutorials/colors/colormaps.html>`_ for an overview of
                    the options.
   :type cmap: str, optional
   :param vmin: Minimum value for the colormap. Default is ``None``, which means to use the value
                :math:`10^{-1/2}`.
   :type vmin: float, optional
   :param vmax: Maximum value for the colormap. Default is ``None``, which means to use the maximum value
                in ``spec``.

                .. warning::
                    ``vmin`` and ``vmax`` are used to set the colormap limits. These options will override the lower and upper limits of ``levels``, if the latter option is used.
   :type vmax: float, optional
   :param freq_max: Maximum frequency to plot. Default is ``None``, which means to use the maximum frequency in
                    the input data.
   :type freq_max: float, optional
   :param show_dirlabels: Whether to show direction labels.
                          If ``True``, shows labels in degrees. If ``'compass'``, shows compass directions.
                          If ``False``, no labels are shown. Default is ``True``.
   :type show_dirlabels: {True,False,'compass'}, optional
   :param show_freqlabels: Whether to show frequency labels. If ``True``, shows only the maximum frequency label.
                           If ``'all'``, shows all labels. If ``False``, no labels are shown. Default is ``True``.
   :type show_freqlabels: {True,False,'all'}, optional
   :param rscale: Scale for the radial axis (frequencies). Default is ``'linear'``.
   :type rscale: {'linear', 'log'}, optional
   :param ax: Axes object to plot on. If ``None``, a new figure and axes are created. Default is ``None``.
   :type ax: matplotlib.axes, optional

   :returns: **ax** -- The axes object with the plot.
   :rtype: matplotlib.axes._subplots.PolarAxesSubplot

   .. rubric:: Example

   >>> # Generate some example data
   >>> freqs = np.linspace(0.05, 0.5, 50)
   >>> dirs = np.linspace(0, 360, 36)
   >>> spec = np.random.rand(36, 50)
   >>> # Plot the directional wave spectrum
   >>> plot_dirwavespec(spec, dirs, freqs)


.. py:function:: plot_sea_state_scatter(y_data, x_data, y_bin=0.25, x_bin=0.2, y_range=None, x_range=None, y_label=None, x_label=None, cmap='viridis', norm='log', annotate=True, min_count_annot=1, ax=None, colorbar=True, grid=True)

   Create a sea state scatter diagram (2-D histogram heatmap) of counts for two wave parameters.

   :param y_data: Values to be displayed on the vertical axis. Typically, this some wave height parameter [in metres].
   :type y_data: array-like
   :param x_data: Values to be displayed on the horizontal axis. Typically, this is some wave period parameter [in seconds]. Must be same length as ``y_data``.
   :type x_data: array-like
   :param y_bin: Bin size for ``y_data``. Default is 0.25 [m].
   :type y_bin: float, optional
   :param x_bin: Bin size for ``x_data``. Default is 0.20 [s].
   :type x_bin: float, optional
   :param y_range: (min, max) explicit range for ``y_data``. If ``None``, inferred from data.
   :type y_range: tuple(float, float), optional
   :param x_range: (min, max) explicit range for ``x_data``. If ``None``, inferred from data.
   :type x_range: tuple(float, float), optional
   :param y_label: Y-axis label for scatter diagram. If ``None``, the scatter diagram display a `y`-axis label.
   :type y_label: str, optional.
   :param x_label: X-axis label for scatter diagram. If ``None``, the scatter diagram display an `x`-axis label.
   :type x_label: str, optional.
   :param cmap: Matplotlib colormap name.
   :type cmap: str, optional
   :param norm: Color normalization. ``"log"`` helps when counts vary widely.
   :type norm: {"log", "linear"}, optional
   :param annotate: If ``True``, annotate counts inside cells.
   :type annotate: bool, optional
   :param min_count_annot: Minimum count to annotate a cell (avoids clutter).
   :type min_count_annot: int, optional
   :param ax: Axes to draw on. If ``None``, a new figure and axes are created.
   :type ax: matplotlib.axes.Axes, optional
   :param colorbar: If ``True``, add a colorbar.
   :type colorbar: bool, optional
   :param grid: If ``True``, show grid lines.
   :type grid: bool, optional

   :returns: * **fig** (*matplotlib.figure.Figure*)
             * **ax** (*matplotlib.axes.Axes*)
             * **H** (*2-D ndarray*) -- Counts matrix of shape ``(len(y_edges)-1, len(x_edges)-1)``,
               where rows correspond to ``y_data`` bins and columns to ``x_data`` bins.
             * **y_edges** (*1-D ndarray*) -- Bin edges for ``x_data``.
             * **x_edges** (*1-D ndarray*) -- Bin edges for ``y_data``.

   .. rubric:: Notes

   NaNs and non-finite values are ignored.

   .. rubric:: Example

   >>> fig, ax, counts, hs_edges, tp_edges = plot_sea_state_scatter(
   ...    Hs, Tp,
   ...    y_bin=0.25,
   ...    x_bin=0.20,
   ...    norm="log",           # try "linear" if you prefer
   ...    annotate=False,       # set True to print counts in cells
   ... )


