datetime x-axis matplotlib labels causing uncontrolled overlap

前端 未结 2 1310
攒了一身酷
攒了一身酷 2020-12-03 16:19

I\'m trying to plot a pandas series with a \'pandas.tseries.index.DatetimeIndex\'. The x-axis label stubbornly overlap, and I cannot make them p

相关标签:
2条回答
  • 2020-12-03 17:09

    In your situation, the easiest would be to manually create labels and spacing, and apply that using ax.xaxis.set_major_formatter.

    Here's a possible solution:

    Since no sample data was provided, I tried to mimic the structure of your dataset in a dataframe with some random numbers.

    The setup:

    # imports
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.dates as mdates
    import matplotlib.ticker as ticker
    
    # A dataframe with random numbers ro run tests on
    np.random.seed(123456)
    rows = 100
    df = pd.DataFrame(np.random.randint(-10,10,size=(rows, 1)), columns=['error'])
    datelist = pd.date_range(pd.datetime(2017, 1, 1).strftime('%Y-%m-%d'), periods=rows).tolist()
    df['dates'] = datelist 
    df = df.set_index(['dates'])
    df.index = pd.to_datetime(df.index)
    
    test_df = df.copy(deep = True)
    
    # Plot of data that mimics the structure of your dataset
    ax = test_df[(test_df.index.year ==2017) ]['error'].plot(kind="bar")
    ax.figure.autofmt_xdate()
    plt.figure(figsize=(15,8))
    

    A possible solution:

    test_df = df.copy(deep = True)
    ax = test_df[(test_df.index.year ==2017) ]['error'].plot(kind="bar")
    plt.figure(figsize=(15,8))
    
    # Make a list of empty myLabels
    myLabels = ['']*len(test_df.index)
    
    # Set labels on every 20th element in myLabels
    myLabels[::20] = [item.strftime('%Y - %m') for item in test_df.index[::20]]
    ax.xaxis.set_major_formatter(ticker.FixedFormatter(myLabels))
    plt.gcf().autofmt_xdate()
    
    # Tilt the labels
    plt.setp(ax.get_xticklabels(), rotation=30, fontsize=10)
    plt.show()
    

    You can easily change the formatting of labels by checking strftime.org

    0 讨论(0)
  • 2020-12-03 17:23

    A pandas bar plot is a categorical plot. It shows one bar for each index at integer positions on the scale. Hence the first bar is at position 0, the next at 1 etc. The labels correspond to the dataframes' index. If you have 100 bars, you'll end up with 100 labels. This makes sense because pandas cannot know if those should be treated as categories or ordinal/numeric data.

    If instead you use a normal matplotlib bar plot, it will treat the dataframe index numerically. This means the bars have their position according to the actual dates and labels are placed according to the automatic ticker.

    import pandas as pd
    import numpy as np; np.random.seed(42)
    import matplotlib.pyplot as plt
    
    datelist = pd.date_range(pd.datetime(2017, 1, 1).strftime('%Y-%m-%d'), periods=42).tolist()
    df = pd.DataFrame(np.cumsum(np.random.randn(42)), 
                      columns=['error'], index=pd.to_datetime(datelist))
    
    plt.bar(df.index, df["error"].values)
    plt.gcf().autofmt_xdate()
    plt.show()
    

    The advantage is then in addition that matplotlib.dates locators and formatters can be used. E.g. to label each first and fifteenth of a month with a custom format,

    import pandas as pd
    import numpy as np; np.random.seed(42)
    import matplotlib.pyplot as plt
    import matplotlib.dates as mdates
    
    datelist = pd.date_range(pd.datetime(2017, 1, 1).strftime('%Y-%m-%d'), periods=93).tolist()
    df = pd.DataFrame(np.cumsum(np.random.randn(93)), 
                      columns=['error'], index=pd.to_datetime(datelist))
    
    plt.bar(df.index, df["error"].values)
    plt.gca().xaxis.set_major_locator(mdates.DayLocator((1,15)))
    plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%d %b %Y"))
    plt.gcf().autofmt_xdate()
    plt.show()
    

    0 讨论(0)
提交回复
热议问题