# Matplotlib: Multiple Y-Axis Scales

Matplotlib's flexibility allows you to show a second scale on the y-axis. This example allows us to show monthly data with the corresponding annual total at those monthly rates.

The Matplotlib Axes.twinx method creates a new y-axis that shares the same x-axis. First we create an axis for the monthly and yearly scales:

mm = ax.twinx()
yy = ax.twinx()


Let's label the monthly and yearly scales:

mm.set_ylabel('Monthly Hours')
yy.set_ylabel('Yearly Hours')


Finally, we set the position of the yearly scale to the far right, and scale it based on the axis limits to be an annual total:

yy.spines["right"].set_position(("axes", 1.2))
yy.set_ylim(mm.get_ylim()[0]*12, mm.get_ylim()[1]*12)


The full code to generate this plot is given in matplotlib-twin-axes.py:

Click to expand...
import pandas as pd

# --------------------------------------------------------------------------------------------------------
def plot(df, title):

import matplotlib.pyplot as plt

plt.style.use('mag')
fig, ax = plt.subplots()
fig.subplots_adjust(right=0.75)

mm = ax.twinx()
yy = ax.twinx()
for col in df.columns:
mm.plot(df.index,df[[col]],label=col)
mm.set_ylabel('Monthly Hours')
yy.set_ylabel('Yearly Hours')
yy.spines["right"].set_position(("axes", 1.2))
yy.set_ylim(mm.get_ylim()[0]*12, mm.get_ylim()[1]*12)

mm.tick_params(axis='y',labelsize=16) # set monthly labelsize (not global)

# format
ax.xaxis.grid(False)
mm.yaxis.grid(False)
yy.yaxis.grid(False)
ax.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, loc: "{:,}".format(int(x))))
plt.title(title, fontsize=16, x=.65, y=1.05)

# format x-axis ticks as dates
import matplotlib.dates as mdates
years = mdates.YearLocator()    # every year
months = mdates.MonthLocator()  # every month
yearsFmt = mdates.DateFormatter('\n%Y')
moFmt = mdates.DateFormatter('%m') # (%b for Jan, Feb Mar; %m for 01 02 03)
ax.xaxis.set_major_locator(years)
ax.xaxis.set_minor_locator(months)
ax.xaxis.set_major_formatter(yearsFmt)
ax.xaxis.set_minor_formatter(moFmt)
for label in ax.xaxis.get_minorticklabels()[::2]: # show every other minor label
label.set_visible(False)

# turn off x-axis
x_axis = ax.axes.get_xaxis()
x_label = x_axis.get_label()
x_label.set_visible(False)

# turn-off left y-axis
ax.yaxis.set_visible(False)

# adjust fontsize
plt.tick_params(axis='both', which='major', labelsize=16)

handles, labels = mm.get_legend_handles_labels()
mm.legend(fontsize=14, loc=6)

plt.savefig('matplotlib-twin-axes.png', bbox_inches='tight', dpi=150)

def main():

df = pd.read_excel('data.xlsx').set_index('Date')
plot(df, title='Multi Y-Axis Scales')

if __name__ == '__main__':
main()


Versions:

Python      3.6.3
pandas      0.23.4
matplotlib  3.0.0


© 2005 Matthew Kudija | Source