【问题标题】:Overlaying the numeric value of median/variance in boxplots在箱线图中叠加中位数/方差的数值
【发布时间】:2013-09-22 13:18:10
【问题描述】:

在 Python 中使用箱线图时,有什么方法可以自动/轻松地将中值和方差叠加在每个框的顶部(或至少是中值的数值)?

例如在下面的箱线图中,我想在每个箱线图上覆盖文本(中位数,+-std)。

                     

【问题讨论】:

    标签: python matplotlib boxplot


    【解决方案1】:

    假设您使用 boxplot 函数来绘制箱线图,它会返回一个包含图形组件的字典。请注意,方框代表内四分位数范围(第 25 至第 75 个百分位数),而不是标准差。

    >>> bp_dict = boxplot(data, vert=False) # draw horizontal boxplot
    >>> bp_dict.keys()
    >>> bp_dict.keys()
    ['medians', 'fliers', 'whiskers', 'boxes', 'caps']
    

    这些包含构成每个绘图元素的 Line2D 对象。您可以使用 Line2D.get_xydata 方法获取中位数和框位置(在数据坐标中),以确定文本的位置。

    from pylab import *
    
    # from http://matplotlib.org/examples/pylab_examples/boxplot_demo.html
    
    # fake up some data
    spread= rand(50) * 100
    center = ones(25) * 50
    flier_high = rand(10) * 100 + 100
    flier_low = rand(10) * -100
    data =concatenate((spread, center, flier_high, flier_low), 0)
    
    # fake up some more data
    spread= rand(50) * 100
    center = ones(25) * 40
    flier_high = rand(10) * 100 + 100
    flier_low = rand(10) * -100
    d2 = concatenate( (spread, center, flier_high, flier_low), 0 )
    data.shape = (-1, 1)
    d2.shape = (-1, 1)
    #data = concatenate( (data, d2), 1 )
    # Making a 2-D array only works if all the columns are the
    # same length.  If they are not, then use a list instead.
    # This is actually more efficient because boxplot converts
    # a 2-D array into a list of vectors internally anyway.
    data = [data, d2, d2[::2,0]]
    
    # multiple box plots on one figure
    figure()
    
    # get dictionary returned from boxplot
    bp_dict = boxplot(data, vert=False)
    
    for line in bp_dict['medians']:
        # get position data for median line
        x, y = line.get_xydata()[1] # top of median line
        # overlay median value
        text(x, y, '%.1f' % x,
             horizontalalignment='center') # draw above, centered
    
    for line in bp_dict['boxes']:
        x, y = line.get_xydata()[0] # bottom of left line
        text(x,y, '%.1f' % x,
             horizontalalignment='center', # centered
             verticalalignment='top')      # below
        x, y = line.get_xydata()[3] # bottom of right line
        text(x,y, '%.1f' % x,
             horizontalalignment='center', # centered
                 verticalalignment='top')      # below
    
    show()
    

    【讨论】:

    • 作为旁注,annotatetext 灵活一点。
    • 谢谢!顺便说一句,我认为代码底部缺少几行。这可能吗?
    • @tcaswell 我对你的评论很感兴趣。在这里如何使用annotate 而不是text?我以前没用过。
    • 抱歉@Josh 被截断的行。我已经添加了它们。 tcaswell 对 annotate 提出了很好的建议。我曾考虑在文本中添加“bbox”参数以填充文本,但没有得到预期的结果。例如,您可以使用 annotate 创建偏移量。 (您也可以在文本的 y 参数中添加一个增量。)
    【解决方案2】:

    一点修正:

    for line in bp_dict['medians']:
      # get position data for median line
      x, y = line.get_xydata()[1]  # top of median line
      # overlay median value
      text(x, y, '%.1f' % x, horizontalalignment='center')  # draw above, centered
    
    for box in bp_dict['boxes']:
      x, y = box.get_path().vertices[0]  # bottom of left line
      text(x, y, '%.1f' % x, horizontalalignment='center',  # centered
      verticalalignment='top')      # below
      x, y = box.get_path().vertices[6]  # bottom of right line
      text(x, y, '%.1f' % x,
        horizontalalignment='center',  # centered
        verticalalignment='top')      # below
    

    【讨论】:

      猜你喜欢
      • 2015-04-12
      • 2018-07-15
      • 1970-01-01
      • 1970-01-01
      • 2016-09-16
      • 2021-05-19
      • 2021-12-05
      • 1970-01-01
      • 2018-05-13
      相关资源
      最近更新 更多