Clustered Column Line with Mathplotlib

Question:

I am trying to make a Clustered Column Line with Mathplotlib. Below you can see data

import pandas as pd
import numpy as np
pd.set_option('max_columns', None)
import matplotlib.pyplot as plt 
    
  
data = {
         'year':[2005,2006,2007,2008,2009,2010,2011,2012,2013,2014],
          'open':[70,20,24,150,80,90,60,90,20,20],
         'closed':[30,14,20,10,20,40,10,10,10,10],
        }

df = pd.DataFrame(data, columns = [
                                   'year',
                                   'open',
                                   'closed',
                                   ])

Now I want to plot chart as the chart shown below:

enter image description here

I tried with those lines below but is not working, because I plotted only bars without line.

df.plot(x='year', kind='bar', title='Comparison',legend=True,ylabel='open',xlabel='')
plt.grid()
plt.legend(loc='upper left', shadow=True)

So can anybody help me how to solve this problem and make plot same as the plot from the picture above?

Asked By: silent_hunter

||

Answers:

You have to use two different y axis, one for the barplot and the other for the line, with matplotlib.axes.Axes.twinx:

fig, ax_1 = plt.subplots(figsize = (8, 5))
ax_2 = ax_1.twinx()

Then you can plot bars and lines on the respective axis:

cmap = get_cmap('tab10')
ax_1.bar(df['year'], df['open'], label = 'open', color = cmap(0))
ax_2.plot(df['year'], df['closed'], label = 'closed', color = cmap(0.1))

In order to have a unique legend with label of both bars and line, you can use:

handles_1, labels_1 = ax_1.get_legend_handles_labels()
handles_2, labels_2 = ax_2.get_legend_handles_labels()

ax_1.legend(handles = handles_1 + handles_2, labels = labels_1 + labels_2, loc = 'upper left', shadow = True)

Complete Code

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.cm import get_cmap


data = {'year': [2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014],
        'open': [70, 20, 24, 150, 80, 90, 60, 90, 20, 20],
        'closed': [30, 14, 20, 10, 20, 40, 10, 10, 10, 10]}

df = pd.DataFrame(data, columns = ['year',
                                   'open',
                                   'closed'])


fig, ax_1 = plt.subplots(figsize = (8, 5))
ax_2 = ax_1.twinx()
cmap = get_cmap('tab10')

ax_1.bar(df['year'], df['open'], label = 'open', color = cmap(0))
ax_2.plot(df['year'], df['closed'], label = 'closed', color = cmap(0.1))

handles_1, labels_1 = ax_1.get_legend_handles_labels()
handles_2, labels_2 = ax_2.get_legend_handles_labels()

ax_1.set_ylim(0, 160)
ax_2.set_ylim(0, 45)
ax_1.legend(handles = handles_1 + handles_2, labels = labels_1 + labels_2, loc = 'upper left', shadow = True)
ax_1.grid(axis = 'y')
ax_1.set_title('Comparison')

plt.show()

Plot

enter image description here

Answered By: Zephyr

Using twinx() you can share the x-axis but get 2 y axes. Plot a bar plot and line plot, then add the legend.

fig, ax1 = plt.subplots(figsize=(10, 5), tight_layout=True)
ax2 = ax1.twinx()
bar=ax1.bar(df['year'], df['open'], width=0.35, label='open')
line=ax2.plot(df['year'], df['closed'], color='orange', label='closed')

legend=[bar] + line
labels=[l.get_label() for l in myl]
ax1.legend(legend, labels, loc='upper left')
plt.title("Comparison")

plt.show()

enter image description here

Answered By: viggnah