如何复制此维基百科图?

时间:2018-12-05 08:08:14

标签: python matplotlib

我想复制使用Python和熊猫链接的剧情。

enter image description here

Pandas DF在下面。

df = pd.DataFrame(
             {"Sex":["Male"]*8+["Female"]*6,
            "Metabolic Rates":[525.8,605.7,843.3,1195.5,1945.6,2135.6,2308.7,
             2950,727.7,1086.5,1091,1361.3,1490.5,1956.1]})

我尝试使用matplotlib的错误栏进行操作,但似乎无法正常工作。

import numpy as np
x = [1,2,3,4,5,6,7,8]
dy = 894.372699158466
y = df.loc[df["Sex"]=="Male"]["Metabolic Rates"]
plt.errorbar(x, y, yerr=dy, fmt='o');

我只能得到这个情节:

enter image description here

2 个答案:

答案 0 :(得分:1)

您可以这样绘制它:

mean_male = df[df['Sex'] == 'Male'].mean().iloc[0]
mean_female = df[df['Sex'] == 'Female'].mean().iloc[0]
std_male = df[df['Sex'] == 'Male'].std().iloc[0]
std_female = df[df['Sex'] == 'Female'].std().iloc[0]

fig = plt.figure()
ax = fig.gca()
plt.plot(df.Sex, df['Metabolic Rates'], marker='.', linestyle='', color='black', markersize=12)
plt.errorbar(['Male', 'Female'], [mean_male, mean_female], yerr=[std_male, std_female], fmt='o', color='red')

更多格式当然是可选的。例如,绘制红色箭头需要使用plt.annotate之类的东西。

要完全使用pandas功能,建议重新格式化df。使用列或索引是在熊猫中聚合数据的好方法。 例如,您可以像这样格式化df:

df_new = pd.DataFrame({'Male': df[df.Sex == 'Male'].iloc[:, 1], 'Female': df[df.Sex == 'Female'].reset_index(drop=True).iloc[:, 1]})

(我想还有一种使用groupbyaggregate的简便方法。)
现在,对于包含stdmean的所有列,您可以轻松获取所需信息,例如df.std()df.mean()。也可以使用熊猫绘图前端。

答案 1 :(得分:1)

import numpy as np
import matplotlib.pyplot as plt

# Create the data
mr_m = [525.8, 605.7, 843.3, 1195.5, 1945.6, 2135.6, 2308.7, 2950]
mr_f = [727.7, 1086.5, 1091, 1361.3, 1490.5, 1956.1]
mean_f = np.mean(mr_f)
mean_m = np.mean(mr_m)
std_f = np.std(mr_f)
std_m = np.std(mr_m)

# Create a figure
fig = plt.figure()
ax = fig.add_subplot(111)

# Set Layout
ax.set_xlim([0.4, 2.6])
ax.set_xticks([1, 2])
ax.set_xticklabels(['Female', 'Male'])
ax.set_ylabel('Metabolic Rate')

# Plot the data
ax.plot(np.ones_like(mr_f), mr_f, 'ko') #  k -> blacK, o-> plot just the datapoints
ax.plot(2 * np.ones_like(mr_m), mr_m, 'ko')
ax.plot(1, mean_f, 'ro')
ax.plot(2, mean_m, 'ro')

# Plot the arrows and the text with *annotate()*, some tuning on the values
# necessary to get the right offsets
# *annotate()* calls *FancyArrowPatch* to plot the arrows, could be used directly 
ax.annotate('', xy=(1.1, mean_f - std_f / 2),
            xytext=(1.1, mean_f + std_f / 2),
            arrowprops=dict(arrowstyle='<->', color='r'))
ax.annotate('Female\nStd. Dev.={}'.format(int(std_f)), xy=(1.15, mean_f -100))

ax.annotate('', xy=(2.1, mean_m - std_m / 2),
            xytext=(2.1, mean_m + std_m / 2),
            arrowprops=dict(arrowstyle='<->', color='r'))
ax.annotate('Male\nStd. Dev.={}'.format(int(std_m)), xy=(2.15, mean_m -100))