英文:
How do I turn a time series line plot into a bar plot using data from Pandas?
问题
问题
我有一个包含3个子图的图表,显示了两个数据集的结果。我想让子图A使用柱状图,而其他两个使用折线图。我已经让所有三个子图都使用了折线图,但是尽管尝试了几天,我无法让子图A显示柱状图。如果我使用Pandas内置的绘图函数df.plot(kind="bar")
而不是ax.plot
,则可以绘制柱状图,但这会破坏我的子图自定义,并且与图表的其余部分不一致,因此我希望尽可能使用ax.plot
。
代码(工作示例)
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
data = {}
dlist = ['Data 1', 'Data 2']
data['mean_1'] = [0.5, -0.5, 0.5, -0.5, 0.5]
data['std_1'] = [0.2, -0.2, 0.2, -0.2, 0.2]
data['count_1'] = [50, 200, 50, 200, 50]
data['mean_2'] = [0.4, -0.4, 0.4, -0.4, 0.4]
data['std_2'] = [0.16, -0.16, 0.16, -0.16, 0.16]
data['count_2'] = [70, 160, 40, 240, 40]
df = pd.DataFrame.from_dict(data)
df['time'] = pd.date_range('2000-01-01 00:00:00', '2000-01-02 00:00:00', freq='6H')
df = df.set_index('time')
colors = ['red', 'cornflowerblue']
mean_cols = [col for col in df.columns if 'mean' in col]
std_cols = [col for col in df.columns if 'std' in col]
count_cols = [col for col in df.columns if 'count' in col]
我尝试了两种使用ax.bar
的方法,如下所示。
第一种方法与子图B和C相同,只是使用ax.bar
代替ax.plot
。它会导致错误"TypeError: bar() missing 1 required positional argument: 'height'"。我不知道如何引用数据帧以获取"height"。
第二种方法将时间和y轴值转化为列表,并将它们用作ax.bar
的前两个参数。我得到"ValueError: too many values to unpack (expected 1)"的错误。柱状图确实绘制出来,但它们与数据不匹配。
datelist = list(df.index.values)
col_list = df[df.columns[2]].values.tolist()
# 绘图初始化
fig, (ax1, ax2, ax3) = plt.subplots(3, figsize=(8, 11))
start, end = '2000-01-01', '2000-01-02'
fig.suptitle('Jan 1中的数据', fontsize=27, x=0.5)
# 子图1- 计数
i = 0
for f in dlist:
p, = ax1.plot(df.loc[start:end, count_cols[i]], color=colors[i])
# p, = ax1.bar(df.loc[start:end, count_cols[i]], color=colors[i]) ## 第一种解决方法 ##
# p, = ax1.bar(datelist, col_list, color=colors[0]) ## 第二种解决方法 ##
df[['count_'+str(i+1)]].plot(kind='bar', color=colors[i], alpha=0.5)
i = i + 1
# 子图2- 均值
i = 0
for f in dlist:
p, = ax2.plot(df.loc[start:end, mean_cols[i]], color=colors[i])
i = i + 1
# 子图3- 标准差
i = 0
for f in dlist:
p, = ax3.plot(df.loc[start:end, std_cols[i]], color=colors[i])
i = i + 1
# 调整和保存
fig.autofmt_xdate(rotation=0, ha='center')
plt.show()
问题
如何将上图中的线条转化为柱状图,使用ax.bar
或其他类似的ax
方法?我不想使用Pandas内置的绘图函数。
英文:
The Problem
I have a plot with 3 subplots showing results from two datasets. I want subplot A to use bars and the other two to use lines. I got all three subplots to use lines, but I can't get bars working on subplot A despite fiddling with it for several days. I get bars if I use the Pandas build-in plotting function df.plot(king="bar") instead of ax.plot, but that breaks my subplot customizations and is inconsistent with the rest of the plot, so I want to use ax.plot if possible.
Code (working example)
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
data = {}
dlist = ['Data 1', 'Data 2']
data['mean_1']=[0.5,-0.5,0.5,-0.5,0.5]
data[ 'std_1']=[0.2,-0.2,0.2,-0.2,0.2]
data['count_1']=[50,200,50,200,50]
data['mean_2']=[0.4,-0.4,0.4,-0.4,0.4]
data[ 'std_2']=[0.16,-0.16,0.16,-0.16,0.16]
data['count_2']=[70,160,40,240,40]
df = pd.DataFrame.from_dict(data)
df['time'] = pd.date_range('2000-01-01 00:00:00','2000-01-02 00:00:00',freq='6H')
df = df.set_index('time')
df
colors = ['red', 'cornflowerblue']
mean_cols = [col for col in df.columns if 'mean' in col]
std_cols = [col for col in df.columns if 'std' in col]
count_cols = [col for col in df.columns if 'count' in col]
I've tried two methods using ax.bar, highlighted below.
The first is just the same as subplots B and C but using ax.bar instead of ax.plot. It gives me the error "TypeError: bar() missing 1 required positional argument: 'height'". I can't figure how how to reference the dataframe for the "height".
The second turns the time and y-axis values into lists and uses those for the first two arguments in ax.bar. I get "ValueError: too many values to unpack (expected 1)". Bars do plot, but they don't match the data.
datelist = list(df.index.values)
col_list = df[df.columns[2]].values.tolist()
#Plot initialization
fig, (ax1, ax2, ax3) = plt.subplots(3, figsize=(8, 11))
start, end = '2000-01-01', '2000-01-02'
fig.suptitle('Stuff over Jan 1',fontsize=27,x=0.5)
#Subplot 1- Counts
i = 0
for f in dlist:
p,= ax1.plot(df.loc[start:end, count_cols[i]],color=colors[i])
# p,= ax1.bar(df.loc[start:end, count_cols[i]],color=colors[i]) ##First solution##
# p,= ax1.bar(datelist,col_list,color=colors[0]) ##Second solution##
df[['count_'+str(i+1)]].plot(kind='bar',color=colors[i],alpha=0.5)
i = i+1
#Subplot 2- Means
i = 0
for f in dlist:
p,= ax2.plot(df.loc[start:end, mean_cols[i]],color=colors[i])
i=i+1
#Subplot 3- Stan. Dev.
i = 0
for f in dlist:
p,= ax3.plot(df.loc[start:end,std_cols[i]],color=colors[i])
i=i+1
#Adjustments and save
fig.autofmt_xdate(rotation=0,ha='center')
plt.show()
The Question
How do I turn the lines in the posted image into bars using ax.bar or another similar ax method? I don't want to use the pandas built-in plotting function.
答案1
得分: 1
pandas.DataFrame.plot
使用matplotlib
作为默认后端。- 线性图具有日期时间 xtick 位置,而条形图的 xticks 是从0开始索引的。
英文:
pandas.DataFrame.plot
usesmatplotlib
as the default backend.- The line plots have datetime xtick locations, while the xticks of bar plot are 0 indexed.
import pandas as pd
import matplotlib.pyplot as plt
# sample data
data =\
{pd.Timestamp('2000-01-01 00:00:00'): {'count_1': 50, 'count_2': 70, 'mean_1': 0.5, 'mean_2': 0.4, 'std_1': 0.2, 'std_2': 0.16},
pd.Timestamp('2000-01-01 06:00:00'): {'count_1': 200, 'count_2': 160, 'mean_1': -0.5, 'mean_2': -0.4, 'std_1': -0.2, 'std_2': -0.16},
pd.Timestamp('2000-01-01 12:00:00'): {'count_1': 50, 'count_2': 40, 'mean_1': 0.5, 'mean_2': 0.4, 'std_1': 0.2, 'std_2': 0.16},
pd.Timestamp('2000-01-01 18:00:00'): {'count_1': 200, 'count_2': 240, 'mean_1': -0.5, 'mean_2': -0.4, 'std_1': -0.2, 'std_2': -0.16},
pd.Timestamp('2000-01-02 00:00:00'): {'count_1': 50, 'count_2': 40, 'mean_1': 0.5, 'mean_2': 0.4, 'std_1': 0.2, 'std_2': 0.16}}
df = pd.DataFrame.from_dict(data, orient='index')
colors = ['red', 'cornflowerblue']
#Plot initialization
fig, axes = plt.subplots(3, figsize=(8, 11), sharex=False, tight_layout=True)
axes = axes.flat
fig.suptitle('Stuff over Jan 1', fontsize=27, x=0.5)
# add a H:M time column for the bar x-axis
df = df.assign(time=df.index.strftime('%H:%M'))
# plot the dataframe columns directly to the assigned axes
df.plot(kind='bar', x='time', y=['count_1', 'count_2'], color=colors, rot=0, alpha=0.5, ax=axes[0])
df.plot(y=['mean_1', 'mean_2'], color=colors, alpha=0.5, rot=0, ax=axes[1])
df.plot(y=['std_1', 'std_2'], color=colors, alpha=0.5, rot=0, ax=axes[2])
# move the legends
for ax in axes:
ax.legend(bbox_to_anchor=(1, 0.5), loc='center left', frameon=False)
plt.show()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论