Plotly:如何为标准偏差制作具有多条线和阴影区域的图形?
Posted
技术标签:
【中文标题】Plotly:如何为标准偏差制作具有多条线和阴影区域的图形?【英文标题】:Plotly: How to make a figure with multiple lines and shaded area for standard deviations? 【发布时间】:2020-08-13 02:20:26 【问题描述】:如何使用 Plotly 生成带有阴影标准差的线图?我正在尝试实现类似于 seaborn.tsplot 的东西。任何帮助表示赞赏。
【问题讨论】:
【参考方案1】:我能够想出类似的东西。我在这里发布代码供其他人使用或提供任何改进建议。
import matplotlib
import random
import plotly.graph_objects as go
import numpy as np
#random color generation in plotly
hex_colors_dic =
rgb_colors_dic =
hex_colors_only = []
for name, hex in matplotlib.colors.cnames.items():
hex_colors_only.append(hex)
hex_colors_dic[name] = hex
rgb_colors_dic[name] = matplotlib.colors.to_rgb(hex)
data = [[1, 3, 5, 4],
[2, 3, 5, 4],
[1, 1, 4, 5],
[2, 3, 5, 4]]
#calculating mean and standard deviation
mean=np.mean(data,axis=0)
std=np.std(data,axis=0)
#draw figure
fig = go.Figure()
c = random.choice(hex_colors_only)
fig.add_trace(go.Scatter(x=np.arange(4), y=mean+std,
mode='lines',
line=dict(color=c,width =0.1),
name='upper bound'))
fig.add_trace(go.Scatter(x=np.arange(4), y=mean,
mode='lines',
line=dict(color=c),
fill='tonexty',
name='mean'))
fig.add_trace(go.Scatter(x=np.arange(4), y=mean-std,
mode='lines',
line=dict(color=c, width =0.1),
fill='tonexty',
name='lower bound'))
fig.show()
【讨论】:
【参考方案2】:以下方法对于 pandas 数据框中的列数是完全灵活的,并使用 default color cycle of plotly。如果行数超过颜色数,颜色将从一开始就被重新使用。截至目前,px.colors.qualitative.Plotly
可以替换为您可以使用px.colors.qualitative
找到的任何十六进制颜色序列:
Alphabet = ['#AA0DFE', '#3283FE', '#85660D', '#782AB6', '#565656', '#1...
Alphabet_r = ['#FA0087', '#FBE426', '#B00068', '#FC1CBF', '#C075A6', '...
[...]
完整代码:
# imports
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
import numpy as np
# sample data in a pandas dataframe
np.random.seed(1)
df=pd.DataFrame(dict(A=np.random.uniform(low=-1, high=2, size=25).tolist(),
B=np.random.uniform(low=-4, high=3, size=25).tolist(),
C=np.random.uniform(low=-1, high=3, size=25).tolist(),
))
df = df.cumsum()
# define colors as a list
colors = px.colors.qualitative.Plotly
# convert plotly hex colors to rgba to enable transparency adjustments
def hex_rgba(hex, transparency):
col_hex = hex.lstrip('#')
col_rgb = list(int(col_hex[i:i+2], 16) for i in (0, 2, 4))
col_rgb.extend([transparency])
areacol = tuple(col_rgb)
return areacol
rgba = [hex_rgba(c, transparency=0.2) for c in colors]
colCycle = ['rgba'+str(elem) for elem in rgba]
# Make sure the colors run in cycles if there are more lines than colors
def next_col(cols):
while True:
for col in cols:
yield col
line_color=next_col(cols=colCycle)
# plotly figure
fig = go.Figure()
# add line and shaded area for each series and standards deviation
for i, col in enumerate(df):
new_col = next(line_color)
x = list(df.index.values+1)
y1 = df[col]
y1_upper = [(y + np.std(df[col])) for y in df[col]]
y1_lower = [(y - np.std(df[col])) for y in df[col]]
y1_lower = y1_lower[::-1]
# standard deviation area
fig.add_traces(go.Scatter(x=x+x[::-1],
y=y1_upper+y1_lower,
fill='tozerox',
fillcolor=new_col,
line=dict(color='rgba(255,255,255,0)'),
showlegend=False,
name=col))
# line trace
fig.add_traces(go.Scatter(x=x,
y=y1,
line=dict(color=new_col, width=2.5),
mode='lines',
name=col)
)
# set x-axis
fig.update_layout(xaxis=dict(range=[1,len(df)]))
fig.show()
【讨论】:
这看起来很棒。谢谢 你能解释一下'tozerox'填充模式是怎么回事吗?这给出的效果与我认为 tozerox 的效果完全不同。 @Jarrad AFK。明天提醒我。但首先,你认为tozerox
会做什么?
使用数字索引,它可以工作,但我不能让它与日期时间索引一起工作;如何做到这一点?
@Thomas 太棒了!有时间我去看看【参考方案3】:
我写了一个函数来扩展plotly.express.line
与 Plotly Express 相同的高级接口。 line
函数(源代码如下)的使用方式与 plotly.express.line
完全相同,但允许使用标志参数 error_y_mode
(可以是 'band'
或 'bar'
)连续错误带。在第二种情况下,它产生与原始plotly.express.line
相同的结果。这是一个使用示例:
import plotly.express as px
df = px.data.gapminder().query('continent=="Americas"')
df = df[df['country'].isin('Argentina','Brazil','Colombia')]
df['lifeExp std'] = df['lifeExp']*.1 # Invent some error data...
for error_y_mode in 'band', 'bar':
fig = line(
data_frame = df,
x = 'year',
y = 'lifeExp',
error_y = 'lifeExp std',
error_y_mode = error_y_mode, # Here you say `band` or `bar`.
color = 'country',
title = f'Using error error_y_mode',
markers = '.',
)
fig.show()
产生以下两个图:
扩展plotly.express.line
的line
函数的源代码是这样的:
import plotly.express as px
import plotly.graph_objs as go
def line(error_y_mode=None, **kwargs):
"""Extension of `plotly.express.line` to use error bands."""
ERROR_MODES = 'bar','band','bars','bands',None
if error_y_mode not in ERROR_MODES:
raise ValueError(f"'error_y_mode' must be one of ERROR_MODES, received repr(error_y_mode).")
if error_y_mode in 'bar','bars',None:
fig = px.line(**kwargs)
elif error_y_mode in 'band','bands':
if 'error_y' not in kwargs:
raise ValueError(f"If you provide argument 'error_y_mode' you must also provide 'error_y'.")
figure_with_error_bars = px.line(**kwargs)
fig = px.line(**arg: val for arg,val in kwargs.items() if arg != 'error_y')
for data in figure_with_error_bars.data:
x = list(data['x'])
y_upper = list(data['y'] + data['error_y']['array'])
y_lower = list(data['y'] - data['error_y']['array'] if data['error_y']['arrayminus'] is None else data['y'] - data['error_y']['arrayminus'])
color = f"rgba(tuple(int(data['line']['color'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)),.3)".replace('((','(').replace('),',',').replace(' ','')
fig.add_trace(
go.Scatter(
x = x+x[::-1],
y = y_upper+y_lower[::-1],
fill = 'toself',
fillcolor = color,
line = dict(
color = 'rgba(255,255,255,0)'
),
hoverinfo = "skip",
showlegend = False,
legendgroup = data['legendgroup'],
xaxis = data['xaxis'],
yaxis = data['yaxis'],
)
)
# Reorder data as said here: https://***.com/a/66854398/8849755
reordered_data = []
for i in range(int(len(fig.data)/2)):
reordered_data.append(fig.data[i+int(len(fig.data)/2)])
reordered_data.append(fig.data[i])
fig.data = tuple(reordered_data)
return fig
【讨论】:
【参考方案4】:其他人发布的很棒的自定义回复。如果有人对 plotly 官方网站上的代码感兴趣,请参见此处:https://plotly.com/python/continuous-error-bars/
【讨论】:
以上是关于Plotly:如何为标准偏差制作具有多条线和阴影区域的图形?的主要内容,如果未能解决你的问题,请参考以下文章