Search code examples
pythonmatplotlibplotbar-chartweekend

Plotting daily timeseries (x-axis) series stock data (y-axis) produces chats with gaps at weekends. How to remove?


Im downloading end of day data using yahoo and plotting graphs. Here an example of part of a script for plotting a bar chart of the accumulated volume (vs the index on the right axis):

p1 = cum_vol.tail(lookback)
pidx = df_idx.tail(lookback)

fig, ax = plt.subplots(figsize=(15, 5))

ax.bar(p1.index, p1, width=1, color='goldenrod', alpha=0.7, label='Accumulated Volume')
# ax.plot(p1.index, p2, color='lightblue', alpha=0.7, label='Decline/Advance Ratio')
ax.set_xlabel('Date')
ax.set_ylabel('Accumulated Volume', color='black')

# Set y-axis limits to the range of accumulated volume
ax.set_ylim(bottom=min(p1), top=max(p1))

# Plot index
ax1 = ax.twinx()

ax1.plot(pidx.index, pidx, 'black', label=idx)
ax1.set_ylabel(idx, color='black')

lines, labels = ax.get_legend_handles_labels()
lines2, labels2 = ax1.get_legend_handles_labels()
ax1.legend(lines + lines2, labels + labels2, loc='upper left')

plt.show()

My problem is that the chart has 2-bar (or more at holidays) gaps at every weekend. In the dataframe, these weekends dates dont exist, but it seems matplotlib, when it plots the timeseries data on the xaxis, includes them with zero as the data.

I imagine the same thing is happening in line charts too? Although they seem to plot correctly, without dropping to zero on weekends.

How can I eliminate this? I imagine two solutions:

  1. Some parameter that "ignores" weekends and plots friday and monday next to each other. I tried this:

ax.xaxis.set_major_locator(mdates.WeekdayLocator())

but it makes the plot even uglier, bunching up the dates and doing nothing abut the weekend gaps. Without this, the plot looks great (except for the gaps!).

  1. Reset the index, making the timeseries a column. This seems pretty simple, but it would loose the date labels on the x-axis.

Does anyone have a solution for this?

Thanks!


Solution

  • You probably should be using custom x-tick labels. That way you an use the index of your data (pandas, numpy array, etc) as the x-axis and still retain your date information.

    I've attempted to provide an example below however it doesn't reflect your code since I obviously can't utilize your existing code (because it's incomplete):

    import matplotlib.pyplot as plt
    import numpy as np
    from datetime import datetime 
    from datetime import timedelta
    
    date = datetime.today()
    array = np.array([1,2,3,4,5,6,7,8,9,10])
    
    """ This block generates dates that skip 2 days like a weekend - i didn't configure it to work on weekends but the same theory applies."""
    labels = [(date + timedelta(days=int(i))) for i in array]
    
    for i in range(len(labels)) :
        
        if i%5 == 0 :
            
            for j in range(i, len(labels)) :
                
                labels[j] += timedelta(days=2)
            
    labels = [i.strftime("%d/%m/%Y").__str__() for i in labels]
    
    plt.plot(array, array)
    
    """ This is the component that is relevant to you"""
    plt.xticks(array, labels, rotation='vertical')
    
    plt.margins(0.2)
    plt.subplots_adjust(bottom=0.15)
    plt.show()

    The following plot is the result: enter image description here

    Please notice that the x-ticks dates skip certain days without any affect on how the graph is displayed.