Pandas: Bar-Plot с двумя полосами и двумя y-осями

У меня есть DataFrame, похожий на это:

     amount     price
age
A     40929   4066443
B     93904   9611272
C    188349  19360005
D    248438  24335536
E    205622  18888604
F    140173  12580900
G     76243   6751731
H     36859   3418329
I     29304   2758928
J     39768   3201269
K     30350   2867059

Теперь я хотел бы построить планку с возрастом на оси х в качестве меток. Для каждого x-tick должно быть два бара, один балл для суммы и один для цены. Я могу заставить это работать, просто используя:

df.plot(kind='bar')

Проблема заключается в масштабировании. Цены настолько высоки, что я не могу действительно определить сумму на этом графике, см.:

enter image description here

Таким образом, мне нужна вторая ось y. Я попробовал это, используя:

df.loc[:,'amount'].plot(kind='bar')
df.loc[:,'price'].plot(kind='bar',secondary_y=True)

но это просто перезаписывает бары и НЕ размещает их бок о бок. Есть ли способ сделать это, не имея доступа к нижнему уровню matplotlib (что было бы возможно, если вы разместили бары бок о бок вручную)?

В настоящее время я использую два отдельных графика в подзаголовках:

df.plot(kind='bar',grid=True,subplots=True,sharex=True); 

в результате:

enter image description here

Ответ 1

Используя новый выпуск pandas (0.14.0 или новее), приведенный ниже код будет работать. Чтобы создать две оси, я вручную создал два объекта осей matplotlib (ax и ax2), которые будут использоваться для обоих графиков.

При построении Dataframe вы можете выбрать объект осей с помощью ax=.... Кроме того, чтобы предотвратить перекрытие двух графиков, я изменил, где они совпадают с аргументом ключевого слова position, это значение по умолчанию равно 0.5, но это будет означать перекрытие двух полос.

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from io import StringIO

s = StringIO("""     amount     price
A     40929   4066443
B     93904   9611272
C    188349  19360005
D    248438  24335536
E    205622  18888604
F    140173  12580900
G     76243   6751731
H     36859   3418329
I     29304   2758928
J     39768   3201269
K     30350   2867059""")

df = pd.read_csv(s, index_col=0, delimiter=' ', skipinitialspace=True)

fig = plt.figure() # Create matplotlib figure

ax = fig.add_subplot(111) # Create matplotlib axes
ax2 = ax.twinx() # Create another axes that shares the same x-axis as ax.

width = 0.4

df.amount.plot(kind='bar', color='red', ax=ax, width=width, position=1)
df.price.plot(kind='bar', color='blue', ax=ax2, width=width, position=0)

ax.set_ylabel('Amount')
ax2.set_ylabel('Price')

plt.show()

Plot

Ответ 2

Вам просто нужно написать: df.plot(kind = 'bar' , secondary_y = 'amount')

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from io import StringIO
s = StringIO("""     amount     price
A     40929   4066443
B     93904   9611272
C    188349  19360005
D    248438  24335536
E    205622  18888604
F    140173  12580900
G     76243   6751731
H     36859   3418329
I     29304   2758928
J     39768   3201269
K     30350   2867059""")
df = pd.read_csv(s, index_col=0, delimiter=' ', skipinitialspace=True)

_ = df.plot( kind= 'bar' , secondary_y= 'amount' , rot= 0 )
plt.show()

Secondary_Y_axis

Ответ 3

Вот еще один способ:

  • создать все бары в левых осях
  • переместите некоторые бары в правые оси, изменив атрибут transform

Вот код:

import pylab as pl
df = pd.DataFrame(np.random.rand(10, 2), columns=["left", "right"])
df["left"] *= 100

ax = df.plot(kind="bar")
ax2 = ax.twinx()
for r in ax.patches[len(df):]:
    r.set_transform(ax2.transData)
ax2.set_ylim(0, 2);

вот результат:

enter image description here