Plotly.py:填充为零,用不同的颜色表示正/负

时间:2019-08-08 22:45:57

标签: python plotly plotly-python

借助Plotly,我可以轻松地绘制一条直线,并填充直线和y == 0之间的区域:

import plotly.graph_objects as go

fig = go.Figure()
fig.add_trace(go.Scatter(
    x=[1, 2, 3, 4],
    y=[-2, -1.5, 1, 2.5],
    fill='tozeroy',
    mode='lines',
))
fig.show()

enter image description here

如何将填充区域一分为二?特别是,在y < 0处用红色填充,在y > 0处用绿色填充。

我想保持这条线连续。这意味着,我对仅绘制两个单独的填充多边形不感兴趣。

请注意,该行不一定具有y == 0处的值。

1 个答案:

答案 0 :(得分:0)

我需要这样的图表所以我写了一个函数。

def resid_fig(resid, tickvalues):
    """
    resid:      The y-axis points to be plotted. x-axis is assumed to be linearly increasing
    tickvalues: The values you want to be displayed as ticklabels on x-axis. Works for hoverlabels too. Has to be
                same length as `resid`. (This is necessary to ignore 'gaps' in graph where two polygons meet.)
    """
    #Adjusting array with paddings to connect polygons at zero line on x-axis
    index_array = []
    start_digit = 0
    split_array = np.split(resid,np.where(np.abs(np.diff(np.sign(resid)))==2)[0]+1)
    split_array = [np.append(x,0) for x in split_array]
    split_array = [np.insert(x,0,0) for x in split_array]
    split_array[0] = np.delete(split_array[0],0)
    split_array[-1] = np.delete(split_array[-1],-1)
    for x in split_array:
        index_array.append(np.arange(start_digit,start_digit+len(x)))
        start_digit += len(x)-1
        
    #Making an array for ticklabels
    flat = []
    for x in index_array:
        for y in x:
            flat.append(y)
    flat_counter = Counter(flat)
    none_indices = np.where([(flat_counter[x]>1) for x in flat_counter])[0]
    custom_tickdata = []
    neg_padding = 0
    start_pos = 0
    for y in range(len(flat)):
        for x in range(start_pos,flat[-1]+1):
            if x in none_indices:
                custom_tickdata.append('')
                break
            custom_tickdata.append(tickvalues[x-neg_padding])
        neg_padding +=1
        start_pos = 1+x

    #Making an array for hoverlabels
    custom_hoverdata=[]
    sublist = []
    for x in custom_tickdata:
        if x == '':
            custom_hoverdata.append(sublist)
            sublist = []
            sublist.append(x)
            continue
        sublist.append(x)
        sublist2 = sublist.copy()
    custom_hoverdata.append(sublist2)
    
    #Creating figure
    fig = go.Figure()
    idx = 0
    for x,y in zip(split_array,index_array):
        color = 'rgba(219,43,57,0.8)' if x[1]<0 else 'rgba(47,191,113,0.8)'
        if (idx==0 and x[0] < 0):
            color= 'rgba(219,43,57,0.8)'
        fig.add_scatter(y=x, x=y, fill='tozeroy', fillcolor=color, line_color=color, customdata=custom_hoverdata[idx],
                        hovertemplate='%{customdata}<extra></extra>',legendgroup='mytrace',
                       showlegend=False if idx>0 else True)
        idx += 1
    fig.update_layout()
    fig.update_xaxes(tickformat='', hoverformat='',tickmode = 'array',
                tickvals = np.arange(index_array[-1][-1]+1),
                ticktext = custom_tickdata)
    fig.update_traces(mode='lines')
    fig.show()

示例-

resid_fig([-2,-5,7,11,3,2,-1,1,-1,1], [1,2,3,4,5,6,7,8,9,10])

enter image description here

现在,注意事项-

  1. 它确实使用了单独的多边形,但我已将所有轨迹合并到一个 legendgroup 中,因此单击图例可打开或关闭所有轨迹。关于图例颜色,一种方法是在 0 调用中将 1 中的 showlegend=False if idx>0 更改为 fig.add_scatter()。然后它会显示两个图例,红色和绿色仍然在同一个图例组中,因此它们仍然一起打开和关闭。

  2. 该函数的工作原理是首先将连续的正值和负值分隔成数组,将 0 添加到每个数组的末尾和开头,以便多边形可以在 x 轴相交。这意味着该数字也不会按比例缩放,但根据用例,它可能没有那么重要。这不会影响悬停标签或刻度标签,因为它们在这些会聚点上是空白的。

  3. 最重要的一点是,当传递的数组中的任何点为 0 时,图形无法按预期工作。我确定可以对其进行修改以使其适用,但我对它没有用,问题也没有要求。