-
Notifications
You must be signed in to change notification settings - Fork 1
added ChoiceLocator #8
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -283,6 +283,48 @@ def view_limits(self, vmin, vmax): | |
| return np.deg2rad(self.base.view_limits(vmin, vmax)) | ||
|
|
||
|
|
||
| class ChoiceLocator(mticker.Locator): | ||
| def __init__(self, base=None, choices=None): | ||
| if choices is None: | ||
| choices = [ | ||
| np.arange(-360, 360, 30.0), | ||
| np.arange(-360, 360, 45.0), | ||
| np.arange(-360, 360, 60.0), | ||
| np.arange(-360, 360, 90.0), | ||
| ] | ||
| if base is None: | ||
| base = mticker.AutoLocator() | ||
| self.choices = choices | ||
| self.base = base | ||
| self.axis = self.base.axis = _AxisWrapper(self.base.axis) | ||
|
|
||
| def set_axis(self, axis): | ||
| self.axis = _AxisWrapper(axis) | ||
| self.base.set_axis(self.axis) | ||
|
|
||
| def __call__(self): | ||
| lim = self.axis.get_view_interval() | ||
| vmin = min(lim[0], lim[1]) | ||
| vmax = max(lim[0], lim[1]) | ||
| max_ticks = self.axis.get_tick_space() | ||
| tol = 1e-12 | ||
| if (vmax - vmin > 60): | ||
| for ticks in self.choices: | ||
| in_range = (ticks >= vmin - tol) & (ticks <= vmax + tol) | ||
| ticks = ticks[in_range] | ||
| if len(ticks) <= max_ticks: | ||
| return np.deg2rad(ticks) | ||
| else: | ||
| return np.deg2rad(self.base()) | ||
| ticks = self.choices[-1] | ||
| ticks = ticks[(ticks >= vmin - tol) & (ticks <= vmax + tol)] | ||
| return ticks | ||
|
|
||
| def view_limits(self, vmin, vmax): | ||
| vmin, vmax = np.rad2deg((vmin, vmax)) | ||
| return np.deg2rad(self.base.view_limits(vmin, vmax)) | ||
|
|
||
|
|
||
| class ThetaTick(maxis.XTick): | ||
| """ | ||
| A theta-axis tick. | ||
|
|
@@ -387,7 +429,7 @@ class ThetaAxis(maxis.XAxis): | |
| _tick_class = ThetaTick | ||
|
|
||
| def _wrap_locator_formatter(self): | ||
| self.set_major_locator(ThetaLocator(self.get_major_locator())) | ||
| self.set_major_locator(ChoiceLocator(self.get_major_locator())) | ||
| self.set_major_formatter(ThetaFormatter()) | ||
| self.isDefault_majloc = True | ||
| self.isDefault_majfmt = True | ||
|
|
@@ -406,7 +448,6 @@ def _set_scale(self, value, **kwargs): | |
| # LinearScale.set_default_locators_and_formatters just set the major | ||
| # locator to be an AutoLocator, so we customize it here to have ticks | ||
| # at sensible degree multiples. | ||
| self.get_major_locator().set_params(steps=[1, 1.5, 3, 4.5, 9, 10]) | ||
| self._wrap_locator_formatter() | ||
|
|
||
| def _copy_tick_props(self, src, dest): | ||
|
|
@@ -421,6 +462,23 @@ def _copy_tick_props(self, src, dest): | |
| trans = dest._get_text2_transform()[0] | ||
| dest.label2.set_transform(trans + dest._text2_translate) | ||
|
|
||
| def get_tick_space(self): | ||
| ends = mtransforms.Bbox.unit().transformed( | ||
| self.axes.transAxes - self.get_figure(root=False).dpi_scale_trans) | ||
|
|
||
| thetamin, thetamax = self.axes._realViewLim.intervalx | ||
| radius = min(ends.height, ends.width) * 72 | ||
| if abs(thetamax - thetamin) > np.pi / 2: | ||
| radius /=2 | ||
| angle = abs(thetamax - thetamin) | ||
| arc_length = radius * angle | ||
| size = self._get_tick_label_size('x') * 3 | ||
| if size > 0: | ||
| return int(np.floor(arc_length / size)) | ||
| else: | ||
| return 2**31 - 1 | ||
|
|
||
|
|
||
|
|
||
| class RadialLocator(mticker.Locator): | ||
| """ | ||
|
|
@@ -690,6 +748,23 @@ def clear(self): | |
| super().clear() | ||
| self.set_ticks_position('none') | ||
|
|
||
| def get_tick_space(self): | ||
| ends = mtransforms.Bbox.unit().transformed( | ||
| self.axes.transAxes - self.get_figure(root=False).dpi_scale_trans) | ||
| thetamin, thetamax = self.axes._realViewLim.intervalx | ||
| rmin, rmax = self.axes._realViewLim.intervaly | ||
| rorigin = self.axes.get_rorigin() | ||
| radius = min(ends.height, ends.width) * 72 | ||
| actual_ratio = rmax / (rmax - rorigin) | ||
| if abs(thetamax - thetamin) > np.pi / 2: | ||
| radius /=2 | ||
| # Having a spacing of at least 3 just looks good | ||
| size = self._get_tick_label_size('y') * 3 | ||
| if size > 0: | ||
| return int(np.floor(radius * actual_ratio / size)) | ||
| else: | ||
| return 2**31 - 1 | ||
r3kste marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
|
Comment on lines
+751
to
+767
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changing the behavior of radial ticks causes a lot of tests to fail. Now that I think about it, the issue doesn't really expect us to change Radial Ticks. It only mentions about the issue with Theta ticks. So I think it would be better if we stick to just Theta Ticks for this PR. |
||
|
|
||
| def _is_full_circle_deg(thetamin, thetamax): | ||
| """ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using 30 degree steps as first priority causes a lot of tests in
test_polar.pyto fail. It looks like the previous behavior was to use 45 degree intervals. So, it would be better to remove 30 degree intervals.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previous behavior uses 45 degree intervals only for full circle. for other arcs with angles (< 360),
30 degree intervals are also used. I think adding a check for full circle might be better.