diff --git a/fastplotlib/widgets/histogram_lut.py b/fastplotlib/widgets/histogram_lut.py index 872cf4319..a3b36eb45 100644 --- a/fastplotlib/widgets/histogram_lut.py +++ b/fastplotlib/widgets/histogram_lut.py @@ -25,9 +25,10 @@ def __init__( ---------- data image_graphic - nbins - flank_divisor: float, default 5.0 - set `np.inf` for no flanks + nbins: int, defaut 100. + Total number of bins used in the histogram + flank_divisor: float, default 5.0. + Fraction of empty histogram bins on the tails of the distribution set `np.inf` for no flanks kwargs """ super().__init__(**kwargs) @@ -161,9 +162,10 @@ def _calculate_histogram(self, data): hist, edges = np.histogram(data_ss, bins=self._nbins) # used if data ptp <= 10 because event things get weird - # with tiny world objects due to floating point error + # with tiny world objects due to floating point error # so if ptp <= 10, scale up by a factor - self._scale_factor: int = max(1, 100 * int(10 / np.ptp(data_ss))) + data_interval = edges[-1] - edges[0] + self._scale_factor: int = max(1, 100 * int(10 / data_interval)) edges = edges * self._scale_factor @@ -178,7 +180,6 @@ def _calculate_histogram(self, data): ) edges_flanked = np.concatenate((flank_left, edges, flank_right)) - np.unique(np.diff(edges_flanked)) hist_flanked = np.concatenate( (np.zeros(flank_nbins), hist, np.zeros(flank_nbins)) @@ -186,7 +187,10 @@ def _calculate_histogram(self, data): # scale 0-100 to make it easier to see # float32 data can produce unnecessarily high values - hist_scaled = hist_flanked / (hist_flanked.max() / 100) + hist_scale_value = hist_flanked.max() + if np.allclose(hist_scale_value, 0): + hist_scale_value = 1 + hist_scaled = hist_flanked / (hist_scale_value / 100) if edges_flanked.size > hist_scaled.size: # we don't care about accuracy here so if it's off by 1-2 bins that's fine diff --git a/fastplotlib/widgets/image.py b/fastplotlib/widgets/image.py index df9b46b55..749403781 100644 --- a/fastplotlib/widgets/image.py +++ b/fastplotlib/widgets/image.py @@ -357,6 +357,9 @@ def __init__( """ self._names = None + if figure_kwargs is None: + figure_kwargs = dict() + # output context self._output = None @@ -368,13 +371,20 @@ def __init__( if all([_is_arraylike(d) for d in data]): # Grid computations if figure_shape is None: - figure_shape = calculate_figure_shape(len(data)) + if "shape" in figure_kwargs: + figure_shape = figure_kwargs["shape"] + else: + figure_shape = calculate_figure_shape(len(data)) - # verify that user-specified figure shape is large enough for the number of image arrays passed - elif figure_shape[0] * figure_shape[1] < len(data): + # Regardless of how figure_shape is computed, below code + # verifies that figure shape is large enough for the number of image arrays passed + if figure_shape[0] * figure_shape[1] < len(data): + original_shape = (figure_shape[0], figure_shape[1]) figure_shape = calculate_figure_shape(len(data)) warn( - f"Invalid `figure_shape` passed, setting figure shape to: {figure_shape}" + f"Original `figure_shape` was: {original_shape} " + f" but data length is {len(data)}" + f" Resetting figure shape to: {figure_shape}" ) self._data: list[np.ndarray] = data @@ -500,19 +510,18 @@ def __init__( ) figure_kwargs_default = {"controller_ids": "sync"} - if figure_kwargs is None: - figure_kwargs = dict() # update the default kwargs with any user-specified kwargs # user specified kwargs will overwrite the defaults figure_kwargs_default.update(figure_kwargs) + figure_kwargs_default["shape"] = figure_shape if graphic_kwargs is None: graphic_kwargs = dict() graphic_kwargs.update({"cmap": cmap}) - self._figure: Figure = Figure(shape=figure_shape, **figure_kwargs_default) + self._figure: Figure = Figure(**figure_kwargs_default) self._histogram_widget = histogram_widget for data_ix, (d, subplot) in enumerate(zip(self.data, self.figure)):