2

Took some guidance from this question to create my bar-plot at the bottom; Matplotlib - Finance volume overlay

But the problem I can't seem to solve is the empty spaces for the bar-plot. As you can see in the code, the list y3 has length=21, and it is the same for x, y1, y2. The days that are empty are weekends, but these days are removed from the list x before I create any plot. I can't see how and why they leave a gap, even after I've removed them from the list of my x-axis.

EDIT: I shortened the question.

]

from datetime import datetime,timedelta
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

d = datetime.strptime('2019-02-01','%Y-%m-%d')
#create x-axis which consists of all days in february except weekdays, plus the first day in march
x = []
for i in range(0,29):
    if((d + timedelta(days=i)).date().weekday() > 4):
        continue
    x.append((d + timedelta(days=i)).date())

y1 = [317.92, 319.1, 322.73, 324.22, 322.05, 321.06, 323.79, 325.29, 325.55, 327.9, 329.99, 330.92, 331.33, 332.75, 331.41, 333.22, 332.58, 333.64, 331.19, 329.83, 332.46]
y2 = [-0.377507469, -0.3411700881, 0.055641283900000005, 0.44570105590000003, 0.10930618490000005, -0.2948038151, 0.09190098490000004, 0.12858223490000004, 0.09559385990000004, 0.4806987649, 0.11333709890000004, 0.5247366639000001, 0.11605396190000006, -0.30122159309999996, -0.7405398680999999, -0.7053236033999999, -0.33368165239999986, -0.8210733183999999, -1.2753887724, -1.3106836659999999, -1.3450585547999998]
y3 = [27, 15, 12, 4, 5, 11, 4, 14, 18, 19, 13, 17, 28, 22, 4, 15, 26, 21, 21, 21, 9]

fig, ax1 = plt.subplots()
ax1.plot(x, y1, 'b')
ax1.tick_params('y', colors='b')
#create space at the bottom for the bar-plot
pad = 0.25
yl = ax1.get_ylim()
ax1.set_ylim(yl[0]-(yl[1]-yl[0])*pad,yl[1])

fig.suptitle('Some title', fontsize=16)
ax2 = ax1.twinx()

ax2.plot(x, y2,'r')
ax2.tick_params('y', colors='r')
#create space at the bottom for the bar-plot
pad = 0.25
yl = ax2.get_ylim()
ax2.set_ylim(yl[0]-(yl[1]-yl[0])*pad,yl[1])
#create barplot and make it small by adding a (in this case, this is not a modular solution) max-limit
ax3 = ax1.twinx()
ax3.set_ylim(0,250)
ax3.bar(x, y3, color='green', width=1, alpha=0.5)
ax3.set_xlim(min(x),max(x))
ax3.get_yaxis().set_ticks([])

ax1.set_ylabel('1st Value', color='b')
ax2.set_ylabel('2nd Value', color='r')
plt.gcf().autofmt_xdate()
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%d-%B'))

plt.show()
armara
  • 535
  • 3
  • 17
  • I would suggest to ask 3 questions if you have 3 questions. For the first one, *why* there are weekend gaps: This is the same as when plotting `plt.plot([0,1,2,5,6,7], [...])`, there is simply no data for [3,4,5]. Check [Skip dates where there is no data](https://matplotlib.org/faq/howto_faq.html#skip-dates-where-there-is-no-data) in the matplotlib documentation. – ImportanceOfBeingErnest Mar 18 '19 at 11:40
  • Yeah sorry I thought this would be a better idea since 3 questions would just result in 90% of the question being copied (since they are small but connected questions). Regarding the link you sent, I've already tried using parts of that but couldn't get it to work with my code. Thanks anyways for the tip. – armara Mar 18 '19 at 12:04

1 Answers1

1

Your x axis doesn't have data for weekends

In the following code, you create xs, but don't include the weekends.

x = []
for i in range(0,29):
    if((d + timedelta(days=i)).date().weekday() > 4):
        continue
    x.append((d + timedelta(days=i)).date())

So for example, if February 1st is a Friday, then the first elements of you x array are [0, 3, 4, 5]. You aren't including data for the weekends, but by omitting [1, 2] you are leaving the space they took.

Solution: Remove spots for weekends and handle label formatting

What you should do is create proxy x-axis data that has no gaps, and then rehandle the labels. A complete solution might be the following.

from datetime import datetime,timedelta
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.ticker as ticker

d = datetime.strptime('2019-02-01','%Y-%m-%d')
#create x-axis which consists of all days in february except weekdays, plus the first day in march
x = []
dates = {}
day = 0
for i in range(0,29):
    if((d + timedelta(days=i)).date().weekday() > 4):
        continue
    x.append(day)
    dates[day] = (d + timedelta(days=i)).date()
    day += 1


def format_date(x, pos=None):
    return dates[int(x)].strftime('%d-%B')

y1 = [317.92, 319.1, 322.73, 324.22, 322.05, 321.06, 323.79, 325.29, 325.55, 327.9, 329.99, 330.92, 331.33, 332.75, 331.41, 333.22, 332.58, 333.64, 331.19, 329.83, 332.46]
y2 = [-0.377507469, -0.3411700881, 0.055641283900000005, 0.44570105590000003, 0.10930618490000005, -0.2948038151, 0.09190098490000004, 0.12858223490000004, 0.09559385990000004, 0.4806987649, 0.11333709890000004, 0.5247366639000001, 0.11605396190000006, -0.30122159309999996, -0.7405398680999999, -0.7053236033999999, -0.33368165239999986, -0.8210733183999999, -1.2753887724, -1.3106836659999999, -1.3450585547999998]
y3 = [27, 15, 12, 4, 5, 11, 4, 14, 18, 19, 13, 17, 28, 22, 4, 15, 26, 21, 21, 21, 9]

fig, ax1 = plt.subplots()
ax1.plot(x, y1, 'b')
ax1.tick_params('y', colors='b')
#create space at the bottom for the bar-plot
pad = 0.25
yl = ax1.get_ylim()
ax1.set_ylim(yl[0]-(yl[1]-yl[0])*pad,yl[1])

fig.suptitle('Some title', fontsize=16)
ax2 = ax1.twinx()

ax2.plot(x, y2,'r')
ax2.tick_params('y', colors='r')
#create space at the bottom for the bar-plot
pad = 0.25
yl = ax2.get_ylim()
ax2.set_ylim(yl[0]-(yl[1]-yl[0])*pad,yl[1])
#create barplot and make it small by adding a (in this case, this is not a modular solution) max-limit
ax3 = ax1.twinx()
ax3.set_ylim(0,250)
ax3.bar(x, y3, color='green', width=1, alpha=0.5)
ax3.set_xlim(min(x),max(x))
ax3.get_yaxis().set_ticks([])

ax1.set_ylabel('1st Value', color='b')
ax2.set_ylabel('2nd Value', color='r')
plt.gcf().autofmt_xdate()
plt.gca().xaxis.set_major_formatter(ticker.FuncFormatter(format_date))

plt.show()

This produces the image

Look, no x gaps

which is the same data, but without weekend gaps.

Explanation of differences

There are three aspects I changed for this exercise. Firstly, I set x to represent ultimately the array [0, 1, 2, ..., 20], and created a dictionary dates to track which day x[i] represents.

x = []
dates = {}
day = 0
for i in range(0,29):
    if((d + timedelta(days=i)).date().weekday() > 4):
        continue
    x.append(day)
    dates[day] = (d + timedelta(days=i)).date()
    day += 1

Then I created a function format_date to feed to matplotlib.ticker to handle the labels for the x-axis.

def format_date(x, pos=None):
    return dates[int(x)].strftime('%d-%B')

Finally, I set the x-axis to use this format function. This uses matplotlib.ticker, which must be imported.

# in the imports, add
import matplotlib.ticker as ticker

# when describing the x-axis, use
plt.gca().xaxis.set_major_formatter(ticker.FuncFormatter(format_date))
davidlowryduda
  • 2,404
  • 1
  • 25
  • 29