-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix for overlapping datetime intervals #10779
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
Conversation
… tests cases to fit, added next_api_changes
lib/matplotlib/dates.py
Outdated
font_ratio = (rcParams['font.size'])/10 | ||
|
||
# a ratio of 10 date characters per inch is 'estimated' | ||
maxwid = rcParams["figure.figsize"][0] * 10 |
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.
I think you need to get the width of the axes, not the figure. I'd also expect 10-pt font characters to be about 72 points-per-inch / 10 points-per-character = 7.2 characters-per-inch wide.
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.
Font size generally refers to the height, not the width (i.e., 10pt monospace, sans, serif are not all the same width).
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.
Understood, but IMO, the new ticks are too spread out. 1) because using the wrong width to work over and 2) because the fontwidth is too wide.
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.
I agree with that; almost all the test images that changed appear mostly okay before.
In general I'm not in favour of this PR, simply because it seems that it creates not enough labels for the general case and the determination of the spacing seems to be rather arbitrary. Adding this either as a different Else, I would argue that the spreading needs to take into account the actual fontsize (not the one from rcParams) and also the rotation of the labels - but that may be rather difficult, because those are not know before drawtime, right? |
I think tick locators are determned at draw time, so thats OK, but you are correct that it should use the actual fontsize of the tick labels, not the one from rcParams! |
I think the trouble with estimating the actual size would require the Text objects. Due to the order in which we use the locators in Axis's iter_ticks() there will be no text when we determine the number of ticks, which is the main cause of this issue. Also, any suggestions on retrieving the width of the axis? Rotation: Font size of tick labels: Not enough labels: AutoDateLocator with parameter: I will try to implement DateLocator with this parameter. |
…or.spacing to rcparams' as an option
To make some progress and ensure previous image tests are preserved, I added rcParams["autodatelocator.spacing"] and I am using the axis's label for font and axis's figure for figsize. However I do have some concerns: |
@shadidsh the width of the axes can be got from |
There seem to be several test image changes with imperceptible differences, leading me to think these images should not be changing at all. |
I removed the unnecessary images, after changes to the PR I did not check them out properly. The code now uses the axes width transformed from the axes's position. Please note the reason I added the parameter to RcParams is because rotation of label at this point does not seem to be set, thus spacing would be problematic. Any feedback and suggestions would be greatly appreciated, thanks. |
@@ -1314,11 +1332,34 @@ def get_locator(self, dmin, dmax): | |||
# bysecond, unused (for microseconds)] | |||
byranges = [None, 1, 1, 0, 0, 0, None] | |||
|
|||
# Required attributes to get width from figure's normal points |
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.
I think this should all be wrapped in if spacing:
I don't get why you are using getattr for all these. If these attributes don't exist, you might as well error here because you weren't passed an axis...
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.
If we raise exceptions it would break existing tests using mock classes that might have aaxis attributes as none.
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.
Which tests? I don't understand what a test would be doing down in here w/o the axes being set (for instance).
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.
for example test_dates.py::def test_auto_date_locator(), this uses dummy axis to specifically check values returned from autodatelocator. It has a few none axis attributes
https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/tests/test_dates.py#L320
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, well I'd just check if whichever one of these is None and set spacing=False if that happens
if label is not None: | ||
font_ratio = label.get_fontsize() / 10 | ||
else: | ||
font_ratio = rcParams['font.size'] / 10 |
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.
I'm pretty sure the ticks have a fontsize associated with them beyond the label fontsize. THats the fontsize you should querry, and I'm pretty sure it exists.
@@ -1328,11 +1369,24 @@ def get_locator(self, dmin, dmax): | |||
byranges[i] = None | |||
continue | |||
|
|||
# Compute at runtime the size of date label with given format |
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.
again, this should only happen if spacing is on.
((num/interval) * datelen_ratio) <= maxwid) | ||
if (num <= interval * (self.maxticks[freq] - 1)): | ||
if (apply_spread): | ||
break |
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.
??? I don't understand why you only break if apply_spread=True here.
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.
When users have rotated labels we shouldn't apply spread, it applies too much spacing. Unfortunately this is why i added to Rcparams in the first place
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.
But you need "interval" to be correct for byranges
, below.
@@ -352,6 +352,8 @@ backend : $TEMPLATE_BACKEND | |||
#date.autoformatter.second : %H:%M:%S | |||
#date.autoformatter.microsecond : %M:%S.%f | |||
|
|||
#autodatelocator.spacing : tight ## if generous, add extra spacing to avoid overlap, otherwise tight |
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.
Maybe autodatelocator.generousspacing : False
True/False would be a cleaner API?
Some comments provided. I'm 50/50 on the PR as a whole. The issue is that most of the time dates on the xaxis are too long. What'll happen here is that there will just be too few ticks. The real solution is making the ticklabels shorter (i.e. #10841) and rotating the ticklabels. |
@jklymak Thanks so much for the feedback, when i get the chance I will add the fixes for experience so I am fine if the PR is closed after the update. |
@shadidsh thanks so much for the PR. Sorry that it didn't make it in, but it was a good idea. We are curretnly discussing tick-related issues, with an idea to completely overhaul them in 3.0. Now that you have some development experience under your belt, please feel free to contribute to that discussion. @timhoffm is leading it, though for the life of me, I can't remember or find what the issue is. @timhoffm can we open a modern issue, w/ you as the author, to keep track of tick-related things... @shadidsh hopefully we see more of you! Thanks again. |
PR Summary
Fix for issue #7712
This PR addresses the overlapping date intervals that can still be found. I noticed PR #8251 just changed the hard coded data table, yet it still resulted in overlaps when dealing with minutely changes. Without changing the data table, I used rcParam's figsize and fontsize to make a conservative estimation of characters that can fit per inch.
Although the solution requires more information I believe this makes it less dependent on future changes to the table. I have modified all image tests required, added coverage, and added to next_api_changes to inform users that image outputs have changed. Thanks in advance for any feedback on this PR.
PR Checklist