【问题标题】:How can a plot a 5 grouped bars bar chart in matplotlib?如何在 matplotlib 中绘制 5 个分组条形图?
【发布时间】:2020-03-22 19:25:44
【问题描述】:

我有以下数据框:

meteo = [["January", 9.2, 13.6, 4.7, 37, 70],
["February",9.9, 14.3, 5.4, 35, 70],
["March", 11.8, 16.1, 7.4, 36, 70],
["April", 13.7, 18.0, 9.4, 40, 69],
["May", 16.9, 21.1, 12.8, 47, 70],
["June", 20.9, 24.9, 16.8, 30, 68],
["July", 23.9, 28.0, 19.8, 21, 67],
["August", 24.4, 28.5, 20.2, 62, 68],
["September", 21.7, 26.0, 17.4, 81, 70],
["October", 17.8, 22.1, 13.5, 91, 73],
["November", 13.0, 17.3, 8.6, 59, 71],
["December", 10.0, 14.3, 5.7, 40, 69]]

import pandas as pd

# Create dataframe with above data

df = pd.DataFrame(meteo)

# Drop useless column

df.drop(0, inplace = True, axis = 1)

# Rename columns

df.rename(columns = {1: "Temp_media_anual_mes", 2: "Temp_máxima_media", 3: "Temp_mínima_media", 4: "Media_lluvias_mensual", 5:"Humedad_media_rel"}, inplace = True)
df["mes"] = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]

现在,我想绘制一个分组条形图。我希望每月有 5 个分组酒吧。我已经尝试过了,但是我对条形之间的空格有一点问题:

# Setting the positions and width for the bars
pos = list(range(len(df.mes))) 
width = 0.25 
    
# Plotting the bars
fig, ax = plt.subplots(figsize=(16,10))

# Create a bar with pre_score data,
# in position pos,
plt.bar(pos, 
        #using df['pre_score'] data,
        df['Temp_media_anual_mes'], 
        # of width
        width, 
        # with alpha 0.5
        alpha=0.5, 
        # with color
        color='red')
        # with label the first value in first_name
        #label=df['first_name'][0]) 

# Create a bar with mid_score data,
# in position pos + some width buffer,
plt.bar([p + width for p in pos], 
        #using df['mid_score'] data,
        df['Temp_máxima_media'],
        # of width
        width, 
        # with alpha 0.5
        alpha=0.5, 
        # with color
        color='green')
        # with label the second value in first_name
        #label=df['first_name'][1]) 

# Create a bar with post_score data,
# in position pos + some width buffer,
plt.bar([p + width*2 for p in pos], 
        #using df['post_score'] data,
        df['Temp_mínima_media'], 
        # of width
        width, 
        # with alpha 0.5
        alpha=0.5, 
        # with color
        color='blue')
        # with label the third value in first_name
        #label=df['first_name'][2]) 
           
plt.bar([p + width*2 for p in pos], 
        #using df['post_score'] data,
        df['Media_lluvias_mensual'], 
        # of width
        width, 
        # with alpha 0.5
        alpha=0.5, 
        # with color
        color='orange')
        # with label the third value in first_name
        #label=df['first_name'][2]) 
           
plt.bar([p + width*2 for p in pos], 
        #using df['post_score'] data,
        df['Humedad_media_rel'], 
        # of width
        width, 
        # with alpha 0.5
        alpha=0.5, 
        # with color
        color='purple')
        # with label the third value in first_name
        #label=df['first_name'][2]) 

# Set the y axis label
ax.set_ylabel('Amount')

# Set the chart's title
ax.set_title('Rain and temperature')

# Set the position of the x ticks
ax.set_xticks([p + 1.5 * width for p in pos])

# Set the labels for the x ticks
ax.set_xticklabels(df['mes'])

# Setting the x-axis and y-axis limits
plt.xlim(min(pos)-width, max(pos)+width*4)
plt.ylim([0, max(df['Temp_media_anual_mes'] + df['Temp_máxima_media'] + df['Temp_mínima_media'] + df["Media_lluvias_mensual"] + df["Humedad_media_rel"])] )

plt.grid()
plt.show()

这是我得到的情节

如您所见,它显示了 3 个单独的条,在第三个中,有 3 个条一个接一个。我知道问题在于条形之间的间距,但我不知道如何解决。有人能指出我正确的方向吗?

编辑:

我还想在每个条形图的上方显示每个绘制值的测量单位。它们是:

  • 摄氏温度
  • mm 为降水量
  • % 相对湿度

非常感谢您

【问题讨论】:

    标签: python python-3.x matplotlib plot bar-chart


    【解决方案1】:

    你不需要那么多剧情调用。您可以一口气完成。

    >>> ax = df.plot.bar(x='mes', y=list(df.columns[1:6]))
    >>> plt.show()
    

    关于在每个条形上方显示值,您可以参考这篇文章,其中我解释了如何在直方图顶部添加文本。您也可以对条形图执行相同操作。

    How can I add the counts to the histogram plot?

    【讨论】:

      【解决方案2】:

      这是一些放置条形的代码,将月份名称居中,...

      请注意,ylim 的原始计算是错误的,它不应该是最大值的总和,而是最大值的最大值。我还在列上方添加了一些带有单位的文本。我试图找到一些合适的颜色:红黄色代表温度,蓝色代表雨水,蓝绿色代表湿度。

      import pandas as pd
      import matplotlib.pyplot as plt
      import matplotlib.ticker as ticker
      
      meteo = [["January", 9.2, 13.6, 4.7, 37, 70],
               ["February", 9.9, 14.3, 5.4, 35, 70],
               ["March", 11.8, 16.1, 7.4, 36, 70],
               ["April", 13.7, 18.0, 9.4, 40, 69],
               ["May", 16.9, 21.1, 12.8, 47, 70],
               ["June", 20.9, 24.9, 16.8, 30, 68],
               ["July", 23.9, 28.0, 19.8, 21, 67],
               ["August", 24.4, 28.5, 20.2, 62, 68],
               ["September", 21.7, 26.0, 17.4, 81, 70],
               ["October", 17.8, 22.1, 13.5, 91, 73],
               ["November", 13.0, 17.3, 8.6, 59, 71],
               ["December", 10.0, 14.3, 5.7, 40, 69]]
      df = pd.DataFrame(meteo)
      #df.rename(columns = {0:"mes", 1: "Temp. media mes", 2: "Temp. máxima media", 3: "Temp. mínima media", 4: "Media lluvias mensual", 5:"Humedad media rel"}, inplace = True)
      df.rename(columns = {0:"month", 1: "Mean monthly temperature", 2: "Max. monthly temperature", 3: "Min. monthly temperature", 4: "Mean monthly rainfall", 5:"Mean relative humidity"}, inplace = True)
      
      # Setting the positions and width for the bars
      pos = list(range(len(df)))
      num_col = len(df.columns) - 1
      width = 0.95 / num_col
      
      fig, ax = plt.subplots(figsize=(16,10))
      
      bar_colors = ['#feb24c', '#f03b20', '#ffeda0', '#43a2ca', '#a8ddb5']
      bar_labels = df.columns[1:]
      
      for i, (colname, color, lbl) in enumerate(zip(df.columns[1:], bar_colors, bar_labels)):
          delta_p = 0.125 + width*i
          plt.bar([p + delta_p for p in pos],
                  df[colname], width, color=color, label=lbl)
          for j in range(len(df)):
              ax.annotate("°C" if i < 3 else "mm" if i == 3 else "%",
                          xy=(pos[j] + delta_p, df[colname][j] + 1),
                          ha='center')
      
      ax.set_ylabel('Amount')
      ax.set_title('Temperatures, Rain and Humidity')
      ax.set_xticks(pos)
      
      def update_ticks(x, pos):
          return df['month'][pos]
      
      ax.xaxis.set_major_formatter(ticker.NullFormatter())
      ax.xaxis.set_minor_formatter(ticker.FuncFormatter(update_ticks))
      ax.xaxis.set_minor_locator(ticker.FixedLocator([p+0.5 for p in pos]))
      for tick in ax.xaxis.get_minor_ticks():
          tick.tick1line.set_markersize(0)
          tick.tick2line.set_markersize(0)
          tick.label1.set_horizontalalignment('center')
      plt.xlim(min(pos), max(pos)+1)
      plt.ylim([0, 10+max([max(df[colname]) for colname in df.columns[1:]])])
      plt.legend()
      plt.grid()
      plt.show()
      

      【讨论】:

      • 感谢您回答@JohanC。您的代码非常优雅。您知道在条形上方注释测量单位的任何快速方法吗?
      • 我厌倦了使颜色更合适并添加了一些单位。文本栏很窄。
      • 再次非常感谢@JohanC。我会好好研究你的代码,以了解所有这些过程是如何进行的!!非常感激!! :)
      猜你喜欢
      • 1970-01-01
      • 2019-03-10
      • 2020-11-23
      • 2018-01-06
      • 2021-11-25
      • 2013-08-06
      • 1970-01-01
      • 2018-11-29
      相关资源
      最近更新 更多