Beaker
Beaker

Reputation: 67

Plotting two lists of different length matplotlib against same x value

I have two numpy.ndarrays, bcmonthly and dailyavg.

bcmonthly has a length of 12 and shape of (12,)

dailyavg has a length of 364 and shape of (364,)

bcmonthy is the monthly average and dailyavg is the daily average. I want to plot the two variables against the x-axis of 12 months.

Plotting bcmonthly has no issue because its shape is 12. However when I plot dailyavg simultaneously I get this error:

ValueError: x and y must have same first dimension, but have shapes (12,) and (364,)

Below is my code:

fig = plt.figure()  
ax1=fig.add_subplot(111)
ax1.plot(months,bcmonthly,'r') #months is a list months=['jan','feb',..etc]
ax2 = ax1.twinx()
ax2.plot(months, dailyavg)   
plt.show()

Upvotes: 1

Views: 2482

Answers (2)

Ghost
Ghost

Reputation: 248

If you want to plot the daily averages on the same plot with the monthly averages, it may be easier to construct two arrays and plot them both against an array of days and then handle the labeling yourself. Something like this

import matplotlib.pyplot as plt
import numpy as np

bcmonthly = np.random.rand(12)    # Creates some random example data,
dailyavg = np.random.rand(365)    # use your own data in place of this
days = np.linspace(0, 364, 365)
months = ['January', 'February', 'March', 'April', 'May',
          'June', 'July', 'August', 'September',
          'October', 'November', 'December']

lmonths = [0, 2, 4, 6, 7, 9, 11]
smonths = [3, 5, 8, 10]
month_idx = list()
idx = -15      # Puts the month avg and label in the center of the month
for jj in range(len(months)):
    if jj in lmonths:
        idx += 31
        month_idx.append(idx)
    elif jj in smonths:
        idx += 30
        month_idx.append(idx)
    elif jj == 1:
        idx += 28
        month_idx.append(idx)

fig = plt.figure(figsize=(10,4), dpi=300)  
plt.plot(month_idx,bcmonthly,'r')
plt.plot(days, dailyavg, ':', linewidth=1)
plt.xlim([-1,366])
plt.title("Monthly and Daily Averages")
plt.xticks(month_idx, months, rotation=45)
plt.show()

Which gives you Daily and Monthly averages

Alternatively, you can use the object-oriented approach of ax.plot(), but that requires you to specify the tick labels and positions separately,

import matplotlib.pyplot as plt
import numpy as np

bcmonthly = np.random.rand(12)
dailyavg = np.random.rand(365)
days = np.linspace(0, 364, 365)
months = ['January', 'February', 'March', 'April', 'May',
          'June', 'July', 'August', 'September',
          'October', 'November', 'December']

lmonths = [0, 2, 4, 6, 7, 9, 11]
smonths = [3, 5, 8, 10]
month_idx = list()
idx = -15      # Puts the month avg and label in the center of the month
for jj in range(len(months)):
    if jj in lmonths:
        idx += 31
        month_idx.append(idx)
    elif jj in smonths:
        idx += 30
        month_idx.append(idx)
    elif jj == 1:
        idx += 28
        month_idx.append(idx)

fig = plt.figure(figsize=(10,4), dpi=300)  
ax1 = fig.add_subplot(111)
ax1.plot(month_idx,bcmonthly,'r')
ax2 = ax1.twinx()
ax2.plot(days, dailyavg, ':', linewidth=1)
plt.xlim([-1,366])
plt.title("Monthly and Daily Averages")
ax1.set_xticklabels(months, rotation=45)
ax1.set_xticks(month_idx)
plt.show()

Upvotes: 1

mostsquares
mostsquares

Reputation: 933

When plotting months vs dailyavg, you need to extend months to have length 364 -- Matplotlib cannot decide for you which of the 12 x-values in months to assign each of the 364 daily averages to, but you can supply that information yourself by making a list of x-values of the appropriate length.

So, in this case, it seems like that would mean making a list containing "January" 31 times, then "February" 28 times, and so on... until you hit length 364 (depending on which day is missing?)

Upvotes: 0

Related Questions