Repository: ARM-DOE/ACT

Issue:
Missing kwargs in plot_stacked_bar_graph
### Description

I just saw this in the code and wanted to report it.  I think we need to pass in kawrgs to the below line in plot_stacked_bar_graph.

'''
my_hist, bins = np.histogram(xdata.values.flatten(), bins=bins, density=density)
'''


Discussion:
@AdamTheisen Sounds good, I can get a fix in for that
@AdamTheisen Looks like the kwargs are intended to being fed into the axes.step, or the plotting functionality instead of the numpy histogram function. Do we want a **hist_kwargs as well? Values not covered are range and weight


Resolving patch:
diff --git a/act/plotting/histogramdisplay.py b/act/plotting/histogramdisplay.py
--- a/act/plotting/histogramdisplay.py
+++ b/act/plotting/histogramdisplay.py
@@ -92,12 +92,13 @@ def plot_stacked_bar_graph(
         self,
         field,
         dsname=None,
-        bins=None,
+        bins=10,
         sortby_field=None,
         sortby_bins=None,
         subplot_index=(0,),
         set_title=None,
         density=False,
+        hist_kwargs=dict(),
         **kwargs,
     ):
         """
@@ -110,9 +111,9 @@ def plot_stacked_bar_graph(
         dsname : str or None
             The name of the datastream the field is contained in. Set
             to None to let ACT automatically determine this.
-        bins : array-like or None
-            The histogram bin boundaries to use. Set to None to use
-            numpy's default boundaries.
+        bins : array-like or int
+            The histogram bin boundaries to use. If not specified, numpy's
+            default 10 is used.
         sortby_field : str or None
             Set this option to a field name in order to sort the histograms
             by a given field parameter. For example, one can sort histograms of CO2
@@ -123,8 +124,10 @@ def plot_stacked_bar_graph(
             The subplot index to place the plot in
         set_title : str
             The title of the plot.
-        density: bool
+        density : bool
             Set to True to plot a p.d.f. instead of a frequency histogram.
+        hist_kwargs : dict
+            Additional keyword arguments to pass to numpy histogram.
 
         Other keyword arguments will be passed into :func:`matplotlib.pyplot.bar`.
 
@@ -155,7 +158,7 @@ def plot_stacked_bar_graph(
         else:
             xtitle = field
 
-        if bins is not None and sortby_bins is None and sortby_field is not None:
+        if sortby_bins is None and sortby_field is not None:
             # We will defaut the y direction to have the same # of bins as x
             sortby_bins = np.linspace(ydata.values.min(), ydata.values.max(), len(bins))
 
@@ -172,17 +175,18 @@ def plot_stacked_bar_graph(
                 ytitle = ''.join(['(', ydata.attrs['units'], ')'])
             else:
                 ytitle = field
-            if bins is None:
+            if sortby_bins is None:
                 my_hist, x_bins, y_bins = np.histogram2d(
-                    xdata.values.flatten(), ydata.values.flatten(), density=density
-                )
+                    xdata.values.flatten(), ydata.values.flatten(), density=density,
+                    bins=bins,
+                    **hist_kwargs)
             else:
                 my_hist, x_bins, y_bins = np.histogram2d(
                     xdata.values.flatten(),
                     ydata.values.flatten(),
                     density=density,
                     bins=[bins, sortby_bins],
-                )
+                    **hist_kwargs)
             x_inds = (x_bins[:-1] + x_bins[1:]) / 2.0
             self.axes[subplot_index].bar(
                 x_inds,
@@ -200,11 +204,8 @@ def plot_stacked_bar_graph(
                 )
             self.axes[subplot_index].legend()
         else:
-            if bins is None:
-                bmin = np.nanmin(xdata)
-                bmax = np.nanmax(xdata)
-                bins = np.arange(bmin, bmax, (bmax - bmin) / 10.0)
-            my_hist, bins = np.histogram(xdata.values.flatten(), bins=bins, density=density)
+            my_hist, bins = np.histogram(xdata.values.flatten(), bins=bins,
+                                         density=density, **hist_kwargs)
             x_inds = (bins[:-1] + bins[1:]) / 2.0
             self.axes[subplot_index].bar(x_inds, my_hist)
 
@@ -324,7 +325,7 @@ def plot_size_distribution(
             )
 
         self.axes[subplot_index].set_title(set_title)
-        self.axes[subplot_index].step(bins.values, xdata.values)
+        self.axes[subplot_index].step(bins.values, xdata.values, **kwargs)
         self.axes[subplot_index].set_xlabel(xtitle)
         self.axes[subplot_index].set_ylabel(ytitle)
 
@@ -334,12 +335,13 @@ def plot_stairstep_graph(
         self,
         field,
         dsname=None,
-        bins=None,
+        bins=10,
         sortby_field=None,
         sortby_bins=None,
         subplot_index=(0,),
         set_title=None,
         density=False,
+        hist_kwargs=dict(),
         **kwargs,
     ):
         """
@@ -352,9 +354,9 @@ def plot_stairstep_graph(
         dsname : str or None
             The name of the datastream the field is contained in. Set
             to None to let ACT automatically determine this.
-        bins : array-like or None
-            The histogram bin boundaries to use. Set to None to use
-            numpy's default boundaries.
+        bins : array-like or int
+            The histogram bin boundaries to use. If not specified, numpy's
+            default 10 is used.
         sortby_field : str or None
             Set this option to a field name in order to sort the histograms
             by a given field parameter. For example, one can sort histograms of CO2
@@ -367,6 +369,8 @@ def plot_stairstep_graph(
             The title of the plot.
         density : bool
             Set to True to plot a p.d.f. instead of a frequency histogram.
+        hist_kwargs : dict
+            Additional keyword arguments to pass to numpy histogram.
 
         Other keyword arguments will be passed into :func:`matplotlib.pyplot.step`.
 
@@ -396,7 +400,7 @@ def plot_stairstep_graph(
         if sortby_field is not None:
             ydata = self._ds[dsname][sortby_field]
 
-        if bins is not None and sortby_bins is None and sortby_field is not None:
+        if sortby_bins is None and sortby_field is not None:
             # We will defaut the y direction to have the same # of bins as x
             sortby_bins = np.linspace(ydata.values.min(), ydata.values.max(), len(bins))
 
@@ -413,16 +417,17 @@ def plot_stairstep_graph(
                 ytitle = ''.join(['(', ydata.attrs['units'], ')'])
             else:
                 ytitle = field
-            if bins is None:
+            if sortby_bins is None:
                 my_hist, x_bins, y_bins = np.histogram2d(
-                    xdata.values.flatten(), ydata.values.flatten(), density=density
-                )
+                    xdata.values.flatten(), ydata.values.flatten(), bins=bins,
+                    density=density, **hist_kwargs)
             else:
                 my_hist, x_bins, y_bins = np.histogram2d(
                     xdata.values.flatten(),
                     ydata.values.flatten(),
                     density=density,
                     bins=[bins, sortby_bins],
+                    **hist_kwargs
                 )
             x_inds = (x_bins[:-1] + x_bins[1:]) / 2.0
             self.axes[subplot_index].step(
@@ -440,7 +445,9 @@ def plot_stairstep_graph(
                 )
             self.axes[subplot_index].legend()
         else:
-            my_hist, bins = np.histogram(xdata.values.flatten(), bins=bins, density=density)
+            my_hist, bins = np.histogram(xdata.values.flatten(), bins=bins,
+                                         density=density, **hist_kwargs)
+
             x_inds = (bins[:-1] + bins[1:]) / 2.0
             self.axes[subplot_index].step(x_inds, my_hist, **kwargs)
 
@@ -480,6 +487,7 @@ def plot_heatmap(
         set_title=None,
         density=False,
         set_shading='auto',
+        hist_kwargs=dict(),
         **kwargs,
     ):
         """
@@ -509,6 +517,7 @@ def plot_heatmap(
         set_shading : string
             Option to to set the matplotlib.pcolormesh shading parameter.
             Default to 'auto'
+        hist_kwargs : Additional keyword arguments to pass to numpy histogram.
 
         Other keyword arguments will be passed into :func:`matplotlib.pyplot.pcolormesh`.
 
@@ -555,14 +564,15 @@ def plot_heatmap(
 
         if x_bins is None:
             my_hist, x_bins, y_bins = np.histogram2d(
-                xdata.values.flatten(), ydata.values.flatten(), density=density
-            )
+                xdata.values.flatten(), ydata.values.flatten(), density=density,
+                **hist_kwargs)
         else:
             my_hist, x_bins, y_bins = np.histogram2d(
                 xdata.values.flatten(),
                 ydata.values.flatten(),
                 density=density,
                 bins=[x_bins, y_bins],
+                **hist_kwargs
             )
         x_inds = (x_bins[:-1] + x_bins[1:]) / 2.0
         y_inds = (y_bins[:-1] + y_bins[1:]) / 2.0
diff --git a/examples/plotting/plot_hist_kwargs.py b/examples/plotting/plot_hist_kwargs.py
new file mode 100644
--- /dev/null
+++ b/examples/plotting/plot_hist_kwargs.py
@@ -0,0 +1,24 @@
+"""
+Plot a histogram of Met data.
+----------------------------------------------------
+
+This is a simple example for how to plot a histogram
+of Meteorological data, while using hist_kwargs parameter.
+
+Author: Zachary Sherman
+"""
+
+from matplotlib import pyplot as plt
+import numpy as np
+
+import act
+
+files = act.tests.sample_files.EXAMPLE_MET1
+met_ds = act.io.armfiles.read_netcdf(files)
+
+# Plot data
+hist_kwargs = {'range': (-10, 10)}
+histdisplay = act.plotting.HistogramDisplay(met_ds)
+histdisplay.plot_stacked_bar_graph('temp_mean', bins=np.arange(-40, 40, 5),
+                                   hist_kwargs=hist_kwargs)
+plt.show()


Test patch:
diff --git a/act/tests/test_plotting.py b/act/tests/test_plotting.py
--- a/act/tests/test_plotting.py
+++ b/act/tests/test_plotting.py
@@ -3,6 +3,7 @@
 import matplotlib
 import matplotlib.pyplot as plt
 import numpy as np
+from numpy.testing import assert_allclose
 import pandas as pd
 import pytest
 import xarray as xr
@@ -1205,3 +1206,37 @@ def test_xlim_correction_plot():
     ds.close()
 
     return display.fig
+
+
+def test_histogram_kwargs():
+    files = sample_files.EXAMPLE_MET1
+    ds = arm.read_netcdf(files)
+    hist_kwargs = {'range': (-10, 10)}
+    histdisplay = HistogramDisplay(ds)
+    hist_dict = histdisplay.plot_stacked_bar_graph('temp_mean', bins=np.arange(-40, 40, 5),
+                                                   sortby_bins=np.arange(-40, 40, 5),
+                                                   hist_kwargs=hist_kwargs)
+    hist_array = np.array(
+        [0, 0, 0, 0, 0, 0, 493, 883, 64, 0, 0, 0, 0, 0, 0])
+    assert_allclose(hist_dict['histogram'], hist_array)
+    hist_dict = histdisplay.plot_stacked_bar_graph('temp_mean', hist_kwargs=hist_kwargs)
+    hist_array = np.array([0, 0, 950, 177, 249, 64, 0, 0, 0, 0])
+    assert_allclose(hist_dict['histogram'], hist_array)
+
+    hist_dict_stair = histdisplay.plot_stairstep_graph('temp_mean', bins=np.arange(-40, 40, 5),
+                                                       sortby_bins=np.arange(-40, 40, 5),
+                                                       hist_kwargs=hist_kwargs)
+    hist_array = np.array(
+        [0, 0, 0, 0, 0, 0, 493, 883, 64, 0, 0, 0, 0, 0, 0])
+    assert_allclose(hist_dict_stair['histogram'], hist_array)
+    hist_dict_stair = histdisplay.plot_stairstep_graph('temp_mean', hist_kwargs=hist_kwargs)
+    hist_array = np.array([0, 0, 950, 177, 249, 64, 0, 0, 0, 0])
+    assert_allclose(hist_dict_stair['histogram'], hist_array)
+
+    hist_dict_heat = histdisplay.plot_heatmap('temp_mean', 'rh_mean', x_bins=np.arange(-60, 10, 1),
+                                              y_bins=np.linspace(0, 10000.0, 50),
+                                              hist_kwargs=hist_kwargs)
+    hist_array = [0.0, 0.0, 0.0, 0.0]
+    assert_allclose(hist_dict_heat['histogram'][0, 0:4], hist_array)
+    ds.close()
+    matplotlib.pyplot.close(fig=histdisplay.fig)