Skip to content

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

Closed

Description

@johan162

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

Activity

  1. jklymak commented on Feb 21, 2022

    @jklymak
    Member

    Are dates actually needed to trigger this?

  2. johan162 commented on Feb 21, 2022

    @johan162
    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.

  3. mylasem commented on Apr 11, 2022

    @mylasem

    @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?

  4. tacaswell commented on Apr 11, 2022

    @tacaswell
    Member

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

  5. timhoffm commented on Apr 12, 2022

    @timhoffm
    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().

  6. jklymak commented on Apr 4, 2023

    @jklymak
    Member

    Call fig.draw_without_rendering before rotating the ticks?

  7. scpsc commented on Jan 17, 2024

    @scpsc

    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!

  8. timhoffm commented on Dec 9, 2024

    @timhoffm
    Member

    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.

  9. added this to the v3.11.0 milestone on Dec 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions