Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add widgets for setting histogram bins #242

Merged
merged 27 commits into from
Jul 12, 2024

Conversation

p-j-smith
Copy link
Contributor

@p-j-smith p-j-smith commented Jan 11, 2024

Fixes #239

  • added QDoubleSpinBox widgets for setting the start and stop edges of the histogram bins (default to the min and max data values, same as existing values used)
  • added a QSpinBox widget for setting the number of bins to use (defaults to 100, same as the existing value used)
  • add callbacks to re-draw figure when value of widgets change
  • set the dtype for np.linspace when creating bins (so integer bin limits are used for integer images). This caused the test_histogram_2D test to fail (as the test layer has integer data but float bins were being used) so I've updated the baseline image - this is now done in Use integer bins for integer data in HistogramWidget #244
  • added a test for the HistogramWidget when the bin parameters are set from the widgets
  • add start, stop, and num_bins parameters to _get_bins function so that bin parameters set in the widgets can be used for settings bins
  • show notification if the bin parameters requested by the user have been modified before plotting (this can happen with integer data as we need to make sure the bins have integer widths)
napari-mpl-hist-bins.mov

@p-j-smith p-j-smith marked this pull request as draft January 11, 2024 11:51
@dstansby
Copy link
Member

Thanks for the PR! Could you put the integer dtype histogram change into a separate PR to make it easier to review?

@dstansby dstansby added this to the 2.0 milestone Jan 11, 2024
@p-j-smith
Copy link
Contributor Author

Could you put the integer dtype histogram change into a separate PR to make it easier to review?

Yep, will do 🙂

bins_start = QDoubleSpinBox()
bins_start.setObjectName("bins start")
bins_start.setStepType(QAbstractSpinBox.AdaptiveDecimalStepType)
bins_start.setRange(-1e10, 1e10)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure what a reasonable range would be (rather than the default of 0 to 100)?

Comment on lines 151 to 162
# Only allow integer bins for integer data
# And only allow values greater than 0 for unsigned integers
n_decimals = 0 if np.issubdtype(layer_data.dtype, np.integer) else 2
is_unsigned = layer_data.dtype.kind == "u"
minimum_value = 0 if is_unsigned else -1e10

bins_start = self.findChild(QDoubleSpinBox, name="bins start")
bins_stop = self.findChild(QDoubleSpinBox, name="bins stop")
bins_start.setDecimals(n_decimals)
bins_stop.setDecimals(n_decimals)
bins_start.setMinimum(minimum_value)
bins_stop.setMinimum(minimum_value)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's necessary to set the minimum bin values to 0 for unsigned integers - if negative bin limits are selected for data with unsigned integers, plt.hist complains that bins must be monotonically increasing (as there's an integer underflow in the bins produced bynp.linspace)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not necessary to set the decimals to 0 for integers, but makes it clear to the users that the data are integers and float bin limits are not appropriate

@dstansby dstansby added New feature New feature or request Changelog needed labels Jan 11, 2024
@dstansby dstansby modified the milestones: 2.0, 2.1 Jan 15, 2024
@p-j-smith p-j-smith marked this pull request as ready for review January 15, 2024 17:10
@p-j-smith p-j-smith marked this pull request as draft January 15, 2024 17:12
Comment on lines 125 to 135
# Disable callbacks whilst widget values might change
for widget in self._bin_widgets.values():
widget.blockSignals(True)

self._bin_widgets["start"].setDecimals(n_decimals)
self._bin_widgets["stop"].setDecimals(n_decimals)
self._bin_widgets["start"].setMinimum(minimum_value)
self._bin_widgets["stop"].setMinimum(minimum_value)

for widget in self._bin_widgets.values():
widget.blockSignals(False)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

temporarily disable the callbacks otherwise the plot is re-drawn each time the widget value changes

@p-j-smith p-j-smith marked this pull request as ready for review January 15, 2024 17:14
Comment on lines 213 to 217
if data.dtype.kind in {"i", "u"}:
# Make sure integer data types have integer sized bins
step = abs(self.bins_stop - self.bins_start) // (self.bins_num)
step = max(1, step)
bins = np.arange(self.bins_start, self.bins_stop + step, step)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to show a notification when the actual number of bins used differs from that requested in the widgets, but perhaps this could be a different PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the notification now, but happy to remove it and add separately if it's easier

@p-j-smith p-j-smith marked this pull request as draft January 15, 2024 17:26
@p-j-smith p-j-smith marked this pull request as ready for review February 14, 2024 11:24
@dstansby
Copy link
Member

I am finally thinking about this (sorry it took so long!), and my current thoughts are to keep things simple we should just have a setting for the number of bins, and show the full range of data without being able to control the start/stop. I am open to adding confiurable start/stop in the future if there's a compelling use case, but for now I think configuring the number of bins is a nice feature that isn't too complicated by itself.

Would you be able to update this PR (or open a new one) to just have the number of bins configurable? Obviously no rush at all 😄, but let me know if it isn't likely to be soon in case I get the bug to implement it

@p-j-smith
Copy link
Contributor Author

Yeah good idea, it became surprisingly complicated! I've removed the notification of requested vs actual bins that I previously added (you can see it in the video above) , do you want it added back?

@dstansby dstansby removed this from the 2.1 milestone Jul 12, 2024
Copy link
Member

@dstansby dstansby left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry this has taken so long to get to, but I gave it a try and it looks 👍👍👍👍 . I've merged main into here, and will update the changelog entry, then get this in a release 😄

@dstansby dstansby enabled auto-merge July 12, 2024 14:25
@dstansby dstansby merged commit 251d333 into matplotlib:main Jul 12, 2024
13 checks passed
@p-j-smith
Copy link
Contributor Author

Sorry this has taken so long to get to,

no worries 😄 Thanks for the reviews and for merging it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
New feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow adjustment of histogram bins
2 participants