3

使用 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()

在此处输入图像描述

如何将填充区域一分为二?特别是用红色 wherey < 0和绿色 where填充y > 0

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

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

4

1 回答 1

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])

在此处输入图像描述

现在,对于警告-

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

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

  3. 最重要的是,当传递的数组中的任何点为 时,图形不会按预期工作0。我确信它可以被修改为它工作,但我没有用它,问题也没有要求它。

于 2021-08-02T12:26:18.053 回答