Skip to content

[Bug]: X-Axis date label not rotated #22521

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

Closed
johan162 opened this issue Feb 21, 2022 · 9 comments
Closed

[Bug]: X-Axis date label not rotated #22521

johan162 opened this issue Feb 21, 2022 · 9 comments

Comments

@johan162
Copy link

Bug summary

Using a date x-axis that are being autoscaled outside the initial data range due to the added vline then the first (and only the first) data label gets no rotation.

Code for reproduction

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

dates = [datetime.datetime(2022, 2, 21, 0, 0),
         datetime.datetime(2022, 2, 22, 0, 0),
         datetime.datetime(2022, 2, 27, 0, 0)]
data1 = [5,8,12]

fig, ax = plt.subplots(1, 1, figsize=(20/2.54, 12/2.54))
plt.subplots_adjust(left=0.08, bottom=0.15, right=0.95)
plt.title("Date x-axis label angle bug")

b1 = ax.bar(dates, data1, width=0.7)

# Setup the date x-axis in weeks marking start of each week start
ax.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=mdates.MO))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%a %b %d'))

# The same problem regardless the method to set the angle
#for label in ax.get_xticklabels(which='major'):
#    label.set(rotation=30, horizontalalignment='right')
plt.xticks(rotation=30, ha="right")

# Add a vline to force the auoscaling outside the data range
plt.axvline(x=datetime.datetime(2022, 3, 15, 0, 0))

plt.show()

Actual outcome

As can be seen in the screenshot the Feb 28 label is not rotated.

Screenshot 2022-02-21 at 16 19 12

Expected outcome

That the dates are rotated as in the following screenshot.
Screenshot 2022-02-21 at 16 22 14

Note: As long as the initial dates for the available data extends past Feb 28 then the labels are correctly rotated

Additional information

This seems to occur if the autoscale range is forced outside the initial range (as required by the data) by the addition of annotations and/or vlines outside the original x-axis data span.

Operating system

OSX

Matplotlib Version

3.5.1

Matplotlib Backend

No response

Python version

3.9.10

Jupyter version

No response

Installation

pip

@jklymak
Copy link
Member

jklymak commented Feb 21, 2022

Are dates actually needed to trigger this?

@johan162
Copy link
Author

I cannot be absolutely sure but I haven't been able to recreate it with plain text labels. For example

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

datax = [1,2,3]
labels = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven','Eight', 'Nine']
data1 = [5,8,12]

fig, ax = plt.subplots(1, 1, figsize=(20/2.54, 12/2.54))
plt.subplots_adjust(left=0.08, bottom=0.15, right=0.95)
plt.title("x-axis label angle bug")
b1 = ax.bar(datax, data1, width=0.7)

ax.set_xticklabels(labels, rotation=30, ha='right')

plt.axvline(x=7)
plt.show()

Works as expected.

I actually realized there is a trivial workaround and that is to change the order of the adjustment of the labels and additional graph details. So instead of

plt.xticks(rotation=30, ha="right")
plt.axvline(x=datetime.datetime(2022, 3, 15, 0, 0))

you swap to

plt.axvline(x=datetime.datetime(2022, 3, 15, 0, 0))
plt.xticks(rotation=30, ha="right")

it works since I assume that with the addition of the vline the xmax is adjusted and the full scale range is subjected to the rotation adjustment. So this seems highly likely (but not certain) to be some corner case involving date axis generation.

@mylasem
Copy link

mylasem commented Apr 11, 2022

@jklymak I can work on this if this is still an issue. Just want to make sure i understand the problem correctly, if the xticks method is used before the axvline method, the date should still rotate as shown in the expected outcome. Is this correct?

@tacaswell
Copy link
Member

@mylasem Correct, independently of what plotting is done and in what order, all of the ticks should be rotated the same.

@timhoffm
Copy link
Member

labels = ax.get_xticklabels()
for l in labels:
l._internal_update(kwargs)

is probably the cause. We may have more ticks allocated internally than are returned by get_xticklabels.

That said, we haven't specified the behavior of plt.ticks(**kwargs). Does it only apply to current tick labels (which I think is the cause of the present issue), or does it define a global state similar to plt.tick_params(). If the latter, we probably have to tap into the mechanics used in tick_params(). Note however that parameter names may differ and we'd have to make sure to accept exactly the Text properties.
This might be a bit tedious. Therefore, I could also see an argument for not allowing plt.ticks(**kwargs), and instead refer the user to tick_params().

@ghost
Copy link

ghost commented Apr 4, 2023

Any workarounds ?

@jklymak
Copy link
Member

jklymak commented Apr 4, 2023

Call fig.draw_without_rendering before rotating the ticks?

@scpsc
Copy link

scpsc commented Jan 17, 2024

Call fig.draw_without_rendering before rotating the ticks?

I have the same problem, with the second tick (also a date) being the only one which is not rotated. I am using :
plt.setp(ax.get_xticklabels(), rotation=30, ha='right')

And this workaround works for me, thanks!

@timhoffm
Copy link
Member

timhoffm commented Dec 9, 2024

The recommended solution from 3.11 on will be the new tick rotations modes introduced in #28968, i.e. here

plt.xaxis.set_tick_params(rotation=30, rotation_mode="xtick")

I'm closing this as there is a current workaround (fig.draw_without_rendering()) and a better future tick styling using tick_params.

@timhoffm timhoffm closed this as completed Dec 9, 2024
@QuLogic QuLogic added this to the v3.11.0 milestone Dec 10, 2024
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

8 participants