如何将颜色条添加到已经存在的绘图图形中?

问题描述

我有以下图表,其数据(位置和颜色值)来自外部来源:

import plotly.graph_objs as go
from plotly.offline import init_notebook_mode, iplot

data = go.Scatter({
    'hoverinfo': 'text',
    'marker': {'color': ['rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(30,136,229,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(30,136,229,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(101,103,181,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(101,103,181,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(101,103,181,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(101,103,181,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(101,103,181,1.0)', 'rgba(173,71,134,1.0)', 'rgba(101,103,181,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(101,103,181,1.0)', 'rgba(101,103,181,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(30,136,229,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(30,136,229,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(30,136,229,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(101,103,181,1.0)', 'rgba(101,103,181,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)'],
               'line': {'color': ['rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(30,136,229,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(30,136,229,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(101,103,181,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(101,103,181,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(101,103,181,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(101,103,181,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(101,103,181,1.0)', 'rgba(173,71,134,1.0)', 'rgba(101,103,181,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(101,103,181,1.0)', 'rgba(101,103,181,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(30,136,229,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(30,136,229,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(30,136,229,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(101,103,181,1.0)', 'rgba(101,103,181,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)', 'rgba(245,39,87,1.0)', 'rgba(245,39,87,1.0)', 'rgba(173,71,134,1.0)'],
                        'width': 0},
               'size': 4.0,
               'symbol': 'circle'},
    'mode': 'markers',
    'name': '',
    'text': 'some hover text',
    'x': [-0.003959869034588337, 0.005061251576989889, 0.006703123915940523, 0.0019563836976885796, -0.0034903099294751883, 0.01550869271159172, 0.0034700739197432995, -0.0018220042111352086, 0.010076701641082764, 0.005893221125006676, 0.006880240514874458, 0.008371046744287014, -0.011258691549301147, 0.006205271929502487, 0.006518206559121609, 0.0006746328435838223, 0.003603707766160369, 0.006014757324010134, 0.00443321093916893, 0.003568103536963463, -0.003682805225253105, -0.00819386076182127, -0.004438681993633509, -0.005338573828339577, -0.003959869034588337, 0.009993263520300388, -0.003959869034588337, -0.0022754939272999763, -0.006901460234075785, 0.004212438594549894, 0.0055755432695150375, 0.00879394169896841, 0.00341446022503078, -0.003105803159996867, -0.0017424229299649596, -0.003959869034588337, 0.003894187044352293, 0.00497738691046834, 0.007604200392961502, -0.002378312638029456, -0.003682805225253105, 0.006995890289545059, -0.0009093930711969733, -0.006481392774730921, -0.0005934620276093483, 0.000962280435487628, -0.005434616934508085, 0.007020855322480202, 0.003565214341506362, 0.0007076506153680384, -0.0010657859966158867, -0.004246561788022518, 0.004018908832222223, 0.00341446022503078, 0.008702066726982594, 0.003824896179139614, 0.005599078722298145, 0.001925327000208199, 0.00950327143073082, -0.004803186748176813, -0.004064114764332771, 0.0020236200653016567, -0.00015490801888518035, 0.005108738783746958, -0.0018468756461516023, 0.0026262067258358, -0.0017437718342989683, 0.003807958448305726, 0.006813774351030588, -0.009644323959946632, -0.009730380959808826, -0.0022573473397642374, 0.0046448661014437675, -0.0024109657388180494, 0.008578626438975334, 0.016399644315242767, 0.0031808093190193176, -0.014735744334757328, -0.001668736687861383, -0.0010972967138513923, 0.006214889232069254, -0.004786754958331585, 0.00018462195293977857, -0.003240009071305394, -0.008156259544193745, -0.0032861116342246532, -0.005193014163523912, -0.005338573828339577, 0.006094215903431177, 0.004020459949970245, -0.002630046335980296, -0.00510041881352663, 0.0034949760884046555, 0.013181162998080254, 0.005493168719112873, -0.0038349907845258713, 0.0087448013946414, -0.00782866682857275, -0.002721679862588644, 0.007046200335025787],
    'xaxis': 'x',
    'y': [-0.22, -0.12, -0.06, -0.06, 0.1, 0.01, -0.09, 0.07, -0.03, 0.0, 0.11, -0.07, 0.02, 0.13, -0.12, -0.09, 0.12, 0.01, -0.11, 0.1, -0.01, 0.02, -0.11, -0.05, 0.06, 0.02, 0.0, -0.11, 0.05, 0.08, -0.07, -0.03, 0.05, -0.1, -0.06, -0.04, -0.05, 0.15, -0.11, -0.12, 0.3, 0.05, 0.05, 0.0, -0.04, 0.02, -0.12, 0.17, 0.13, -0.01, 0.08, 0.02, 0.04, 0.0, -0.06, 0.04, -0.1, 0.02, 0.05, -0.04, 0.35, 0.05, -0.1, -0.05, -0.02, -0.03, 0.0, 0.02, -0.14, 0.04, 0.03, 0.1, 0.01, 0.15, -0.09, 0.01, -0.02, -0.01, -0.14, -0.08, -0.01, -0.06, 0.09, 0.03, -0.04, -0.05, -0.08, 0.0, 0.05, -0.01, -0.07, -0.1, -0.12, 0.01, 0.01, 0.15, -0.02, 0.04, -0.16, -0.07],
    'yaxis': 'y'
})

layout=go.Layout(title="Some Plot", xaxis={'title':'x-axis label'})

init_notebook_mode(connected=True)
fig = go.Figure(data=[data], layout=layout)
iplot(fig) 

现在,我想在图的右侧添加一个颜色条,以指示颜色的含义。为此,我采用了与绘图中的颜色相似的颜色字典,使用matplotlib函数将它们转换为色彩映射表,并将它们转换为与绘图兼容的色彩映射表,如示例here:

所示
from matplotlib.colors import LinearSegmentedColormap
import matplotlib
import numpy as np


cdict = {
    'red': ((0.0, 0.12, 0.12),
            (1.0, 0.96, 0.96)),

    'green': ((0.0, 0.53, 0.53),
              (1.0, 0.15, 0.15)),

    'blue': ((0.0, 0.90, 0.90),
             (1.0, 0.34, 0.34)),

    'alpha': ((0.0, 1, 1),
              (0.5, 1, 1),
              (1.0, 1, 1))
}

red_blue = LinearSegmentedColormap('RedBlue', cdict)

def matplotlib_to_plotly(cmap, pl_entries):
    h = 1.0/(pl_entries-1)
    pl_colorscale = []

    for k in range(pl_entries):
        C = list(map(np.uint8, np.array(cmap(k*h)[:3])*255))
        pl_colorscale.append([k*h, 'rgb'+str((C[0], C[1], C[2]))])

    return pl_colorscale

red_blue = matplotlib_to_plotly(red_blue, 255)

如果我可以访问用于给数据点着色的实际值,我可以使用它们来绘制颜色栏,如下所示:data['marker'] = dict(color=actual_color_values, colorscale=red_blue)

所以,我尝试从图形本身的data部分提取y值,看看这些值是否用于给点着色。但显然不是,因为结果图的数据点颜色与原始图不同:

y = data['y']
data['marker'] = dict(color=y, colorscale=red_blue, colorbar=dict(thickness=10))
fig = go.Figure(data=[data], layout=layout)
iplot(fig)

然后,我尝试将颜色值指定为data['marker']['color']。但这会产生具有错误颜色栏限制的空白颜色栏:

y = data['marker']['color']
data['marker'] = dict(color=y, colorscale=red_blue, colorbar=dict(thickness=10))
fig = go.Figure(data=[data], layout=layout)
iplot(fig)


所以我试了另一种方法。我使用此颜色映射表创建了一个虚拟轨迹,通过观察原始绘图显示带有x和y的最小值和最大值的颜色条:

min_x = -0.015
max_x = 0.015
min_y = -0.3
max_y = 0.3

dummy_trace=go.Scatter(x=[min_x, max_x],
             y=[min_y, max_y],
             mode='markers',
             marker=dict(
                 size=(max(y)-min(y))/100, 
                 color=[min(y), max(y)], 
                 colorscale=red_blue, 
                 colorbar=dict(thickness=10), 
                 showscale=True
             ),
             hoverinfo='none'
            )

layout = dict(xaxis=dict(visible=False), yaxis=dict(visible=False))
fig = go.Figure([dummy_trace], layout)
iplot(fig)

现在,如果我能以某种方式将这个颜色条显示在实际绘图旁边,它就能做到。有什么办法可以做到这一点吗?如果可能,我还想从颜色栏中删除数字,并在其顶部仅显示高,在底部仅显示低,因为如上所述,最小和最大y值不是用于给数据点着色的实际值的最小值和最大值。


解决方案

我找到了将虚拟跟踪添加到Figure对象的方法;它使用add_trace函数。从颜色栏中删除数字的方法是将虚拟轨迹的colorbar字段中的tickvalsticktext参数替换为所需的值。

colorbar_trace  = go.Scatter(x=[None],
                             y=[None],
                             mode='markers',
                             marker=dict(
                                 colorscale=red_blue, 
                                 showscale=True,
                                 cmin=-5,
                                 cmax=5,
                                 colorbar=dict(thickness=5, tickvals=[-5, 5], ticktext=['Low', 'High'], outlinewidth=0)
                             ),
                             hoverinfo='none'
                            )

fig['layout']['showlegend'] = False
fig.add_trace(colorbar_trace)

iplot(fig)

因为我只需要颜色栏中的2个值(HighLow),所以我在刻度中指定了2个值;假设我使用tickvals=[-5, 0, 5], ticktext=['Low', 'Medium', 'High']colorbar字典中指定了3个值,则如下所示:

相关文章