You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Redundant month in ConciseDateFormatter offset text when it displays days and months #24982
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
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.
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?)
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.
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.
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).
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.)
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!
Activity
rcomer commentedon Jan 15, 2023
According to the milestone, the
ConciseDateFormatterwent 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 commentedon 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 textax.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 commentedon Jan 15, 2023
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 commentedon Jan 15, 2023
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 commentedon 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 commentedon Jan 16, 2023
You can't use the
offset_formatsargument because the level 2 is used for formatting days and months, and only days, So if I useoffset_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
%Yand 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 commentedon Jan 16, 2023
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 asecond_alternative_offset_formatis 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 commentedon Jan 16, 2023
Actually, what we can do is to change the logic so that if the
zero_formatsstring 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 commentedon Jan 16, 2023
Yes I think that might work
github-actions commentedon Feb 23, 2026
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!