Skip to content

[Bug]: Redundant month in ConciseDateFormatter offset text when it displays days and months #24982

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

Open
persep opened this issue Jan 14, 2023 · 9 comments

Comments

@persep
Copy link

persep commented Jan 14, 2023

Bug summary

When you make a plot with the ConciseDateFormatter that shows on the x axis days and months the offset_string also shows the month (with the year) which I think is redundant because you only need the year

Code for reproduction

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime

fig, ax = plt.subplots()

d1 = datetime.datetime(1997, 1, 1)
d2 = d1 + datetime.timedelta(weeks=520)

locator = mdates.AutoDateLocator()
formatter = mdates.ConciseDateFormatter(locator)
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)

ax.plot([d1, d2], [0, 0])

ax.set_xlim(d1, d1 + datetime.timedelta(weeks=3))
ax.set_xlim(d1 + datetime.timedelta(weeks=1),
                d1 + datetime.timedelta(weeks=10))

plt.show()

Actual outcome

image

Expected outcome

image

Additional information

When the ConciseDateFormatter was proposed here you can see the same expected behavior:

image

Operating system

Ubuntu 22.04.1 LTS

Matplotlib Version

3.6.2

Matplotlib Backend

agg

Python version

3.10.6

Jupyter version

No response

Installation

pip

@rcomer
Copy link
Member

rcomer commented Jan 15, 2023

According to the milestone, the ConciseDateFormatter went in at v3.1, and the example in the v3.1 gallery shows “2005-Apr” on the offset even though “Apr” is also an axes tick lebel. So I think it has always been this way.
https://matplotlib.org/3.1.0/gallery/ticks_and_spines/date_concise_formatter.html#sphx-glr-gallery-ticks-and-spines-date-concise-formatter-py

@jklymak
Copy link
Member

jklymak commented Jan 15, 2023

This is expected behaviour - if you had another month in your date range, I think it would change to just showing the year. If you want to change the formats for the different levels there is an offset_formats kwarg to ConciseFormatter, however, I think there are cases in this level where you would want the month to show up as well, so it probably should stay the same. If you want, you can also manually change the offset text ax.xaxis.offsetText.set_string('2009').

It would be hard to argue that we should change the default, because that would require a whole deprecation cycle, which is difficult for kwargs, and I'd say not worth the pain in this case.

@oscargus
Copy link
Member

I contemplated this when working on #22871

There a special casing was added for the year and I was thinking about the other cases as well. IIRC it really comes down to what the format strings include and if the first day of the month is hit or not. Although I agree that conceptually, the month should not be in your example, one would simply need another formatter for that, as combining modifiable static formatting and dynamic adaptation of the formatting is not really possible (either we always guess or never guess, sort of, the current solution never guesses).

I think that another formatter that prints the ticks at a suitable level and then print all remaining date information in the offset, as long as it is not already in the ticks would be doable though, possibly with an argument for "highest" level to be shown in the offset.

(Finally, one could question if it actually should be Mar in the example. It seems like maybe Jan is a more natural choice for offset?)

@persep
Copy link
Author

persep commented Jan 15, 2023

This is expected behaviour - if you had another month in your date range, I think it would change to just showing the year.

The month and year offset always shows up no matter how many months and days you have like in the first image I posted

@jklymak
Copy link
Member

jklymak commented Jan 15, 2023

Again, this is not a bug, just a disagreement about what the defaults should be. Changing the defaults is a breaking API change, so there would have to be a pretty strong reason to do that song and dance. We did go back and forth a fair bit on what the default labels should be and arrived at this as reasonable.

@persep
Copy link
Author

persep commented Jan 16, 2023

You can't use the offset_formats argument because the level 2 is used for formatting days and months, and only days, So if I use
offset_formats=['', '%Y', '%Y', '%Y-%b-%d', '%Y-%b-%d', '%Y-%b-%d %H:%M']
when plotting days and months the offset will be the year offset_formats[2] which is ok.
But when you plot days you only get the year when you really need '%Y-%b'.
The way to solve this would be that if there is a month in the axis then to use %Y and if there isn't any month in the axis to use %Y-%b.
I think you need one more level to use it this way or a way to detect months, I'm not very good at understanding the matplotlib code.
But if you all think there is no need to change the code then feel free to close this issue.

@oscargus
Copy link
Member

The thing is that you would need to do that at every level. If you plot hours, then you will need to check a day is printed and in that case select a different string. It is not possible to implement it like that, just an alternative_offset_format. But then there will be a case where not only the day, but the month is plotted and then the month should not be there so a second_alternative_offset_format is required and so on.

Another example: say that you set the tick format for month as "%Y-%b", then you do not want offset to print year either.

So either one goes with a static mechanism (as now) or one can write a fully automatic version. (Or a third version that parses the format strings and then removes any format markers from the offset that are printed in the ticks.)

I think we all agree that there are cases where the current defaults are not ideal in all cases (there are no defaults that are ideal in all cases), but one can change the format as required and there are no "surprises".

I think this can be kept open as it clearly indicates a need for another formatter that guesses more (and probably is less configurable).

@oscargus
Copy link
Member

Actually, what we can do is to change the logic so that if the zero_formats string is used, the level is changed by one. At least optionally. Not sure that it fully makes sense for all the default value levels, but I guess that is more or less the request.

(Still it will need a deprecation period if we change the default behavior.)

@persep
Copy link
Author

persep commented Jan 16, 2023

Yes I think that might work

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

No branches or pull requests

4 participants