Skip to content

Commit

Permalink
Histogram bin size and limits (#2309)
Browse files Browse the repository at this point in the history
* Allow setting of bin size and histogram limits

Add option to set histogram bin size and API for viewer limits

* Change stretch_hist_bin_size to stretch_hist_nbins

* Address review comments and add tests

* Fix bug and update tests

* Add methods to user api

* Remove x/y limits from user api
  • Loading branch information
javerbukh authored Jul 27, 2023
1 parent 3f2e43f commit e078a91
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 5 deletions.
40 changes: 37 additions & 3 deletions jdaviz/configs/default/plugins/plot_options/plot_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
PlotOptionsSyncState)
from jdaviz.core.user_api import PluginUserApi
from jdaviz.core.tools import ICON_DIR
from jdaviz.core.custom_traitlets import IntHandleEmpty
from jdaviz.utils import bqplot_clear_figure
from jdaviz.core.marks import HistogramMark

Expand Down Expand Up @@ -96,6 +97,7 @@ class PlotOptions(PluginTemplateMixin):
not exposed for Specviz. This only applies when ``contour_mode`` is "Linear".
* ``contour_custom_levels`` (:class:`~jdaviz.core.template_mixin.PlotOptionsSyncState`):
not exposed for Specviz. This only applies when ``contour_mode`` is "Custom".
* :meth: `set_histogram_nbins`
"""
template_file = __file__, "plot_options.vue"

Expand Down Expand Up @@ -189,6 +191,7 @@ class PlotOptions(PluginTemplateMixin):
stretch_vmax_sync = Dict().tag(sync=True)

stretch_hist_zoom_limits = Bool().tag(sync=True)
stretch_hist_nbins = IntHandleEmpty().tag(sync=True)
stretch_histogram = Any().tag(sync=True, **widget_serialization)

subset_visible_value = Bool().tag(sync=True)
Expand Down Expand Up @@ -428,7 +431,8 @@ def state_attr_for_line_visible(state):

@property
def user_api(self):
expose = ['multiselect', 'viewer', 'layer', 'select_all', 'subset_visible']
expose = ['multiselect', 'viewer', 'layer', 'select_all', 'subset_visible',
'set_histogram_nbins']
if self.config == "cubeviz":
expose += ['collapse_function']
if self.config != "imviz":
Expand Down Expand Up @@ -599,6 +603,7 @@ def _update_stretch_histogram(self, msg={}):
label='density')]

self.bqplot_figs_resize = [self.stretch_histogram]
self.stretch_hist_nbins = 25

else:
hist_mark = self.stretch_histogram.marks[0]
Expand All @@ -623,11 +628,18 @@ def _add_histogram_marks(self):
return
scales = {'x': self.stretch_histogram.axes[0].scale, 'y': bqplot.LinearScale()}
v_stretch_lines = []
if self.stretch_vmin.value >= self.stretch_histogram.marks[0].min:
# Set the viewer limits if they are None
if self.stretch_histogram.axes[0].scale.min is None:
self.stretch_histogram.axes[0].scale.min = self.stretch_histogram.marks[0].min
if self.stretch_histogram.axes[0].scale.max is None:
self.stretch_histogram.axes[0].scale.max = self.stretch_histogram.marks[0].max

# If the stretch limits are within the viewer limits, draw the HistogramMark
if self.stretch_vmin.value >= self.stretch_histogram.axes[0].scale.min:
vmin_lines = HistogramMark(min_max_value=[self.stretch_vmin.value, self.stretch_vmin.value], # noqa
scales=scales)
v_stretch_lines.append(vmin_lines)
if self.stretch_vmax.value <= self.stretch_histogram.marks[0].max:
if self.stretch_vmax.value <= self.stretch_histogram.axes[0].scale.max:
vmax_lines = HistogramMark(min_max_value=[self.stretch_vmax.value, self.stretch_vmax.value], # noqa
scales=scales)
v_stretch_lines.append(vmax_lines)
Expand All @@ -638,3 +650,25 @@ def _remove_histogram_marks(self):
return
self.stretch_histogram.marks = [mark for mark in self.stretch_histogram.marks
if not isinstance(mark, HistogramMark)]

@observe("stretch_hist_nbins")
def histogram_nbins_changed(self, msg):
if self.stretch_histogram is None or msg['new'] == '' or msg['new'] < 1:
return
self.set_histogram_nbins(msg['new'])

def set_histogram_nbins(self, nbins):
self.stretch_histogram.marks[0].bins = nbins
self.stretch_hist_nbins = nbins

def set_histogram_x_limits(self, x_min, x_max):
if x_min:
self.stretch_histogram.axes[0].scale.min = x_min
if x_max:
self.stretch_histogram.axes[0].scale.max = x_max

def set_histogram_y_limits(self, y_min, y_max):
if y_min:
self.stretch_histogram.axes[1].scale.min = y_min
if y_max:
self.stretch_histogram.axes[1].scale.max = y_max
10 changes: 10 additions & 0 deletions jdaviz/configs/default/plugins/plot_options/plot_options.vue
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,16 @@

<v-row v-if="stretch_function_sync.in_subscribed_states">
<!-- z-index to ensure on top of the jupyter widget with negative margin-top -->
<v-text-field
ref="stretch_hist_nbins"
type="number"
label="Number of Bins"
v-model.number="stretch_hist_nbins"
hint="The amount of bins used in the histogram."
persistent-hint
:rules="[() => stretch_hist_nbins !== '' || 'This field is required',
() => stretch_hist_nbins > 0 || 'Number of Bins must be greater than zero']"
></v-text-field>
<v-switch
v-model="stretch_hist_zoom_limits"
class="hide-input"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,27 @@ def test_stretch_histogram(cubeviz_helper, spectrum1d_cube_with_uncerts):
po.stretch_hist_zoom_limits = True
assert len(po.stretch_histogram.marks[0].sample) != len(flux_cube_sample)

po.stretch_vmin.value = po.stretch_histogram.marks[0].min
po.stretch_vmax.value = po.stretch_histogram.marks[0].max
po.stretch_vmin.value = 0.5
po.stretch_vmax.value = 1

v_min_max_marks = [mark for mark in po.stretch_histogram.marks
if isinstance(mark, HistogramMark)]
assert len(v_min_max_marks) == 2
assert v_min_max_marks[0].x[0] == po.stretch_vmin.value
assert v_min_max_marks[1].x[0] == po.stretch_vmax.value

assert po.stretch_histogram.marks[0].bins == 25
po.set_histogram_nbins(20)
assert po.stretch_histogram.marks[0].bins == 20

po.set_histogram_x_limits(x_min=0.25, x_max=2)
assert po.stretch_histogram.axes[0].scale.min == 0.25
assert po.stretch_histogram.axes[0].scale.max == 2

po.set_histogram_y_limits(y_min=1, y_max=2)
assert po.stretch_histogram.axes[1].scale.min == 1
assert po.stretch_histogram.axes[1].scale.max == 2

po._remove_histogram_marks()
assert len([mark for mark in po.stretch_histogram.marks
if isinstance(mark, HistogramMark)]) == 0
Expand Down

0 comments on commit e078a91

Please sign in to comment.