1

I have a data like this:

Group   yq        Value1    Value2
G       2014Q1     0.07        1.1
G       2014Q2     0.06        1.09
G       2014Q3     0.09        1.11
G       2014Q4     0.04        1.13
I       2014Q1     0.10        1.2
I       2014Q2     0.13        1.25
I       2014Q3     0.15        1.23
I       2014Q4     0.18        1.4

I want to plot line and bar chart in one graph.
I tried to plot bar first, but it output two graphs (2 groups, G and I):

import matplotlib.pyplot as plt
ax = dataset.groupby('Group')[['yq', 'Value1']].plot(x = 'yq', kind='bar')

After that, I tried to draw line chart with it.

fig, ax1 = plt.subplots(figsize=(7, 5))
ax2 = ax1.twinx()
dataset[['Value1', 'yq', 'Group']].groupby('Group').plot(x = 'yq', kind='bar', color='y', ax=ax1)
dataset[['Value2', 'yq', 'Group']].groupby('Group').plot(x = 'yq', kind='line', marker='d', ax=ax2)
ax1.yaxis.tick_right()
ax2.yaxis.tick_left()

However, the plot is weird. It does not proper show all labels on x-axis. To be concise. it just show year rather than year and quarter.
Moreover, the plot does not plot bar chart on it either.

Any suggestion?

I also tried:

fig, ax = plt.subplots(figsize=(10, 5))
dataset[['Value1', 'yq', 'Group']].plot(x = 'yq', kind='bar', stacked=False, title='get_title', color='grey', ax=ax, grid=False)
ax2 = ax.twinx()
ax2.plot(ax.get_xticks(), dataset[['Value2']].values, linestyle='-', marker='o', color='k', linewidth=1.0, label='percentage')
lines, labels = ax.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax.legend(lines + lines2, labels + labels2, loc='best')
ax.yaxis.set_ticks_position("right")
ax2.yaxis.set_ticks_position("left")
fig.autofmt_xdate()
plt.show()

This plot is incorrect but can plot line and bar on same graph.

Peter Chen
  • 1,464
  • 3
  • 21
  • 48

1 Answers1

3

The problem is bar plot sets the x-axis to range(len(dataset)), and use the corresponding labels, while line plot doesn't do so. So you can change the yq to string and use seaborn:

dataset.yq = dataset.yq.astype(str)

fig, ax1 = plt.subplots(figsize=(7,5))
ax2=ax1.twinx()
sns.barplot(x='yq', y='Value1', data=dataset, hue='Group',ax=ax1)
sns.lineplot(x='yq',y='Value2', data=dataset, hue='Group', marker='d', ax=ax2)
plt.show()

gives:

enter image description here

Quang Hoang
  • 146,074
  • 10
  • 56
  • 74
  • great! Is it possible to set the label of x-axis to vertical or 45 angle and set bar chart y-axis to percentage and show it on each bar? – Peter Chen May 30 '19 at 20:14
  • `seaborn` is awesome. But why `matplotlib` cannot complete this? – Peter Chen May 30 '19 at 20:21
  • 1
    percent label is possible with: `ax1.set_yticklabels(['{:.1f}%'.format(a*100) for a in ax1.get_yticks()])`. Annotate bar plot is tricky, you can search this site for solution. `matplotlib` can, but needs a lot of tweaking, which is what `seaborn` does, because (I think) `seaborn` is just an wrapper for `matplotlib`. – Quang Hoang May 30 '19 at 20:25
  • And is it possible to make x-axis's label to vertical because it is a little bit crowded – Peter Chen May 30 '19 at 20:38
  • 1
    `ax1.set_xticklabels(ax1.get_xticks(), rotation=90)` – Quang Hoang May 30 '19 at 21:44