【问题标题】:Add vertical line to multi horizontal bar-chart向多水平条形图添加垂直线
【发布时间】:2019-09-07 14:50:09
【问题描述】:

我正在生成一个多条形图作为水平条形图,我现在需要做的是在特定位置的每个水平条中注释(基本上创建一条垂直线)(基于x轴值)对于每个 y 轴,其中 y 轴是分类(名称),x 轴是数字(整数)s。

我查看了axis.vlines,但无法正常工作。

import seaborn as sns
import matplotlib.pyplot as plt
crashes = sns.load_dataset("car_crashes").sort_values("total", ascending=False)
crashes['max_range'] = crashes['total'] * 0.85
sns.set_color_codes("muted")
sns.set(style="whitegrid")
sns.barplot(x="total", y="abbrev", data=crashes, label="", color="r")
sns.barplot(x="max_range", y="abbrev", data=crashes, label="", color="y")
sns.barplot(x="alcohol", y="abbrev", data=crashes,label="normal range", color="g")

#dummy data for the "vertical lines" i want to plot
crashes['actual'] = crashes['alcohol'] * 1.85

上面的代码创建了一个这样的图:

https://seaborn.pydata.org/examples/horizontal_barplot.html

现在我基本上想从底层数据框的另一列在绘图的每一行(因此对于绘图中的每个条形图)添加一条垂直线。

【问题讨论】:

    标签: python pandas seaborn


    【解决方案1】:

    axis.vlines 足以胜任这项工作。为此,我首先提取条形图标签的 y 点。比我为这些点制作一个 x 值的字典。比我使用axis.vlines 在条上画一条红线。

    import seaborn as sns
    import matplotlib.pyplot as plt
    
    crashes = sns.load_dataset("car_crashes").sort_values("total", ascending=False)
    crashes['max_range'] = crashes['total'] * 0.85
    sns.set_color_codes("muted")
    sns.set(style="whitegrid")
    # Store the returned axes in a variable
    ax = sns.barplot(x="total", y="abbrev", data=crashes, label="", color="r")
    ax = sns.barplot(x="max_range", y="abbrev", data=crashes, label="", color="y")
    ax = sns.barplot(x="alcohol", y="abbrev", data=crashes,label="normal range", color="g")
    
    #dummy data for the "vertical lines" i want to plot
    crashes['actual'] = crashes['alcohol'] * 1.85
    
    
    #### MY ADDITIONS ####
    
    # Form dictionary of bar chart keys (i.e. Y axis data, here it is "abbrev") to
    # corresponding y and x points
    y_labs = list(ax.get_yticklabels())
    y_tic_pos = list(ax.get_yticks())
    y_tick_vals = {}
    for i in range(len(y_tic_pos)):
        y_tick_vals[y_labs[i].get_text()] = y_tic_pos[i]
    x_points = {lab:crashes[crashes["abbrev"] == lab]["actual"].values[0] for lab in y_tick_vals}
    
    # for each of the relevant y axis, draw a vertical line
    for key in y_tick_vals:
        c_y = y_tick_vals[key]
        c_x = x_points[key]
        # I just did some trial and error to find out that each bar is 0.5 wide;
        # this may not be the case for other plots.
        c_ymin = c_y - 0.25
        c_ymax = c_y + 0.25
    
        ax.vlines(c_x, c_ymin, c_ymax, colors="r")
    
    plt.show()
    

    【讨论】: