-
-
Notifications
You must be signed in to change notification settings - Fork 7.5k
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
Enh optional tick deconflict #13826
Enh optional tick deconflict #13826
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 |
---|---|---|
|
@@ -1064,19 +1064,18 @@ def _update_ticks(self): | |
Update ticks (position and labels) using the current data interval of | ||
the axes. Return the list of ticks that will be drawn. | ||
""" | ||
|
||
major_locs = self.major.locator() | ||
major_locs = self.get_majorticklocs() | ||
major_labels = self.major.formatter.format_ticks(major_locs) | ||
major_ticks = self.get_major_ticks(len(major_locs)) | ||
self.major.formatter.set_locs(major_locs) | ||
major_labels = self.major.formatter.format_ticks(major_locs) | ||
for tick, loc, label in zip(major_ticks, major_locs, major_labels): | ||
tick.update_position(loc) | ||
tick.set_label1(label) | ||
tick.set_label2(label) | ||
minor_locs = self.minor.locator() | ||
minor_locs = self.get_minorticklocs() | ||
minor_labels = self.minor.formatter.format_ticks(minor_locs) | ||
minor_ticks = self.get_minor_ticks(len(minor_locs)) | ||
self.minor.formatter.set_locs(minor_locs) | ||
minor_labels = self.minor.formatter.format_ticks(minor_locs) | ||
for tick, loc, label in zip(minor_ticks, minor_locs, minor_labels): | ||
tick.update_position(loc) | ||
tick.set_label1(label) | ||
|
@@ -1317,16 +1316,21 @@ def get_minorticklocs(self): | |
# Remove minor ticks duplicating major ticks. | ||
major_locs = self.major.locator() | ||
minor_locs = self.minor.locator() | ||
# we do check when we set the attribute that this is a Locator | ||
# subclass, use getattr out of an over abundance of caution | ||
remove_overlaps = getattr(self.minor.locator, 'remove_overlaps', True) | ||
transform = self._scale.get_transform() | ||
tr_minor_locs = transform.transform(minor_locs) | ||
tr_major_locs = transform.transform(major_locs) | ||
lo, hi = sorted(transform.transform(self.get_view_interval())) | ||
# Use the transformed view limits as scale. 1e-5 is the default rtol | ||
# for np.isclose. | ||
tol = (hi - lo) * 1e-5 | ||
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. While we are here, I think the tolerance should be smaller here. .... 1.0001 == 1.000001 with this.... I would tend to go w/ something like 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. This is in pixel space though. If the goal is to prevent tick/grid/label collisions shouldn't we make this closer to 1? 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. I don't think this is a visual issue, but rather a math one. If the user wants a major tick at 1.0 and a minor tick at 1.00001 I don't think we should stop them (or make them use a kwarg) short of numerical roundoff. 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. All of the complaints about this have been due to visual overlap. The problem we have is that we can not tell "the user intentionally put a major and minor ticks on top of each other so we should do what we are told" (ex, @ImportanceOfBeingErnest date example) vs "the user accidentally set up locators that collide and we should do the obviously correct thing and de-conflict them" Previously the behavior was the first (which when we made the log minor locator smarter caused problems and @ImportanceOfBeingErnest was relying on) but now we do the second. If we accept that we want to de-conflict the ticks as a primarily a display issue then we should do the filtering based on how close it comes in pixel space. Using this flag the user can pick between the two behavior (by telling us which of the two cases they want) and we chose to default to door number 2 ("do 'the right thing' visually) as I think that is going to be the more common intention. 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. Thats fine, I understand your point. However:
I don't think we should do any deciding of what to send to the renderer in pixel space because that means a 100-dpi figure is different than 200 dpi figure. You will end up with the inconsistent situation that a pdf that has 72 dpi virtual pixels will have fewer ticks than a png with 100 dpi. If your argument were instead to do the deconflict as a fraction of tick width, I'd be fine w/ that. linewidths are in physical units. Anyway, this comment wasn't meant at all to be a blocker on this PR. The overall idea seems fine to me. 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. The DPI dependence is a very good point. I would be comfortable tweaking the exact de-confliction criteria later. |
||
minor_locs = [ | ||
loc for loc, tr_loc in zip(minor_locs, tr_minor_locs) | ||
if not np.isclose(tr_loc, tr_major_locs, atol=tol, rtol=0).any()] | ||
if remove_overlaps: | ||
minor_locs = [ | ||
loc for loc, tr_loc in zip(minor_locs, tr_minor_locs) | ||
if ~(np.isclose(tr_loc, tr_major_locs, atol=tol, rtol=0).any()) | ||
] | ||
return minor_locs | ||
|
||
def get_ticklocs(self, minor=False): | ||
|
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.
OK, so you went w/ the attribute path? So, how does this get set? I guess this PR needs tests and examples...