Plotly:如何创建具有多色标签的时间序列变量的线图?
Plotly: How to create a line plot of a time series variable that has a multiple-color label?
我有 datframe 作为 df,它有一列我在 y 下作为 'parameter' 传递,如下所示,它是针对变量 'time' 绘制的。此变量在颜色下传递的 'labels' 列下有 2 个标签。
import plotly.express as px
fig= px.line(data_frame= df, x='time', y='parameter', color='labels')
请找到我为图表附加的图片。两幅图像具有相同的变量,但第二幅图像是第一幅图像的缩放版本,以便更好地理解。
如您所见,我正在绘制一个变量与时间的关系图,并期望 2 个标签使用不同的颜色,plotly 在图表中以蓝色和红色给出了 2 条单独的线,这看起来非常混乱和错误。我应该做哪些更改才能使一个连续图形具有 2 种不同的颜色?
更多解释:我不希望蓝线 运行 穿过红色图表(请参阅所附图片),反之亦然,因为我只绘制了一张图表。我想要如图 3 所示的图表。提前谢谢你。
如果我没理解错的话,您是在尝试绘制具有两个不同颜色标签的单个时间序列数据。在同一张图中绘制多条线会导致一些重叠,因为它们共享时间轴。
为什么不使用 散点图(不连接点)?根据数据的密度,这在视觉上看起来类似于连接 lines/curves.
您也可以尝试绘制蓝线和红线并进行一些垂直偏移以减少重叠。
第二条建议
(请进一步阅读我的第一个建议,了解一些假设和条件)
我已经设法建立了一种方法,几乎应该涵盖您在这里要求的所有内容。提供真正挑战的唯一细节是如何可视化迹线之间的间隙,因为我的第二个建议建立在为每个 label
添加唯一迹线的基础上。您可能怀疑这可能会在图例中填充一堆重复的名称,但可以通过按相关标签对跟踪名称进行分组来解决这个问题。我还设置了一个字典,您可以在其中为每个标签指定颜色。这是结果:
绘图 2.1 - 标签定义的颜色
注意到灰线了吗?这是我之前描述的“连通性”问题的结果。您可以通过在 color='rgba(200,200,200,0.2)'
中设置不透明度参数(最后一个数字)来选择隐藏或显示该行。您将在下面找到一个完整的代码片段来重现此图。那里有很多事情要调整整个事情,所以如果有任何不清楚的地方,请不要犹豫询问细节。
完整代码:
# imports
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np
import random
# settings
observations = 100
np.random.seed(5)
value = np.random.uniform(low=-1, high=1, size=observations).tolist()
time = [t for t in pd.date_range('2020', freq='D', periods=observations)]#.format()]
df=pd.DataFrame({'time': time,
'value':value})
df['value']=df['value'].cumsum()
df1 = df.copy()
df1=df1.set_index('time')
# custom function to build labels as conditions of parameter values
def classify(e):
if e > 0.75: return 'high'
if e > 0.25: return 'medium'
if e >= 0: return 'low'
# custom function to set mode = line or marker, given data length
def modes(df):
if len(df) > 1: return 'lines'
else: return 'markers'
# dictionary to specify marker or line color
# this will depend on your real world labels !!!
cols = {'high': 'green',
'medium': 'blue',
'low': 'red'}
df['label1'] = [(elem-df['value'].min())/(df['value'].max()-df['value'].min()) for elem in df['value']]
df['label'] = [classify(elem) for elem in df['label1']]
df = df.drop('label1', 1)
df['group'] = df['label'].ne(df['label'].shift()).cumsum()
df = df.groupby('group')
dfs = []
for name, data in df:
dfs.append(data)
fig = go.Figure()
# one line to connect them all
fig=go.Figure((go.Scatter(x=df1.index, y=df1['value'],
name = 'all data',
line=dict(color='rgba(200,200,200,0.7)'))))
showed = []
for frame in dfs:
if frame['label'].iloc[0] not in showed:
fig.add_trace(go.Scatter(x=frame['time'], y = frame['value'],
mode = modes(frame),
marker_color = cols[frame['label'].iloc[0]],
legendgroup=frame['label'].iloc[0],
name=frame['label'].iloc[0]))
showed.append(frame['label'].iloc[0])
else:
fig.add_trace(go.Scatter(x=frame['time'], y = frame['value'],
mode = modes(frame),
marker_color = cols[frame['label'].iloc[0]],
legendgroup=frame['label'].iloc[0],
name=frame['label'].iloc[0],
showlegend=False
))
fig.update_layout(template='plotly_dark')
fig.update_xaxes(showgrid=False)
fig.update_layout(uirevision='constant')
fig.show()
第一个建议
您应该如何执行此操作在很大程度上取决于数据集的结构。根据你的问题,我只能猜测它看起来像这样:
time param label
0 2020-01-01 -0.556014 medium
1 2020-01-02 0.185451 high
2 2020-01-03 -0.401111 medium
3 2020-01-04 0.436111 high
4 2020-01-05 0.412933 high
5 2020-01-06 0.636421 peak
6 2020-01-07 1.168237 peak
7 2020-01-08 1.205073 peak
8 2020-01-09 0.798674 peak
9 2020-01-10 0.174116 high
如果是这样,那么您可以很快 运行 解决数据点之间奇怪的连接问题,如果您想显示 param
不同颜色的线条轨迹。首先想到的是将 一种 颜色的线与 多种 颜色的标记组合在一起,如下所示:
这将为您提供良好的交互性,您可以在其中打开和关闭所有元素,也许只研究数据中 label=='peak
:
的部分
让我知道这对您来说效果如何,我们可以讨论更多细节。您将在此处找到数据示例和所有详细信息:
完整代码:
# imports
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np
import random
# settings
observations = 100
np.random.seed(5); cols = list('a')
param = np.random.uniform(low=-1, high=1, size=observations).tolist()
time = [t for t in pd.date_range('2020', freq='D', periods=observations).format()]
df=pd.DataFrame({'time': time,
'param':param})
df['param']=df['param'].cumsum()
def classify(e):
if e > 0.9: return 'peak'
if e > 0.75: return 'high'
if e > 0.25: return 'medium'
if e > 0.9: return 'low'
if e >= 0: return 'bottom'
df['label1'] = [(elem-df['param'].min())/(df['param'].max()-df['param'].min()) for elem in df['param']]
df['label'] = [classify(elem) for elem in df['label1']]
df = df.drop('label1', 1)
fig=go.Figure((go.Scatter(x=df['time'], y=df['param'],
mode='lines',
line=dict(color='rgba(0,0,200,0.7)'))))
fig.add_traces(px.scatter(df, x='time', y='param', color='label').data)
fig.update_layout(template='plotly_dark')
fig.update_xaxes(showgrid=False)
fig.show()
我有 datframe 作为 df,它有一列我在 y 下作为 'parameter' 传递,如下所示,它是针对变量 'time' 绘制的。此变量在颜色下传递的 'labels' 列下有 2 个标签。
import plotly.express as px
fig= px.line(data_frame= df, x='time', y='parameter', color='labels')
请找到我为图表附加的图片。两幅图像具有相同的变量,但第二幅图像是第一幅图像的缩放版本,以便更好地理解。
如您所见,我正在绘制一个变量与时间的关系图,并期望 2 个标签使用不同的颜色,plotly 在图表中以蓝色和红色给出了 2 条单独的线,这看起来非常混乱和错误。我应该做哪些更改才能使一个连续图形具有 2 种不同的颜色?
更多解释:我不希望蓝线 运行 穿过红色图表(请参阅所附图片),反之亦然,因为我只绘制了一张图表。我想要如图 3 所示的图表。提前谢谢你。
如果我没理解错的话,您是在尝试绘制具有两个不同颜色标签的单个时间序列数据。在同一张图中绘制多条线会导致一些重叠,因为它们共享时间轴。
为什么不使用 散点图(不连接点)?根据数据的密度,这在视觉上看起来类似于连接 lines/curves.
您也可以尝试绘制蓝线和红线并进行一些垂直偏移以减少重叠。
第二条建议
(请进一步阅读我的第一个建议,了解一些假设和条件)
我已经设法建立了一种方法,几乎应该涵盖您在这里要求的所有内容。提供真正挑战的唯一细节是如何可视化迹线之间的间隙,因为我的第二个建议建立在为每个 label
添加唯一迹线的基础上。您可能怀疑这可能会在图例中填充一堆重复的名称,但可以通过按相关标签对跟踪名称进行分组来解决这个问题。我还设置了一个字典,您可以在其中为每个标签指定颜色。这是结果:
绘图 2.1 - 标签定义的颜色
注意到灰线了吗?这是我之前描述的“连通性”问题的结果。您可以通过在 color='rgba(200,200,200,0.2)'
中设置不透明度参数(最后一个数字)来选择隐藏或显示该行。您将在下面找到一个完整的代码片段来重现此图。那里有很多事情要调整整个事情,所以如果有任何不清楚的地方,请不要犹豫询问细节。
完整代码:
# imports
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np
import random
# settings
observations = 100
np.random.seed(5)
value = np.random.uniform(low=-1, high=1, size=observations).tolist()
time = [t for t in pd.date_range('2020', freq='D', periods=observations)]#.format()]
df=pd.DataFrame({'time': time,
'value':value})
df['value']=df['value'].cumsum()
df1 = df.copy()
df1=df1.set_index('time')
# custom function to build labels as conditions of parameter values
def classify(e):
if e > 0.75: return 'high'
if e > 0.25: return 'medium'
if e >= 0: return 'low'
# custom function to set mode = line or marker, given data length
def modes(df):
if len(df) > 1: return 'lines'
else: return 'markers'
# dictionary to specify marker or line color
# this will depend on your real world labels !!!
cols = {'high': 'green',
'medium': 'blue',
'low': 'red'}
df['label1'] = [(elem-df['value'].min())/(df['value'].max()-df['value'].min()) for elem in df['value']]
df['label'] = [classify(elem) for elem in df['label1']]
df = df.drop('label1', 1)
df['group'] = df['label'].ne(df['label'].shift()).cumsum()
df = df.groupby('group')
dfs = []
for name, data in df:
dfs.append(data)
fig = go.Figure()
# one line to connect them all
fig=go.Figure((go.Scatter(x=df1.index, y=df1['value'],
name = 'all data',
line=dict(color='rgba(200,200,200,0.7)'))))
showed = []
for frame in dfs:
if frame['label'].iloc[0] not in showed:
fig.add_trace(go.Scatter(x=frame['time'], y = frame['value'],
mode = modes(frame),
marker_color = cols[frame['label'].iloc[0]],
legendgroup=frame['label'].iloc[0],
name=frame['label'].iloc[0]))
showed.append(frame['label'].iloc[0])
else:
fig.add_trace(go.Scatter(x=frame['time'], y = frame['value'],
mode = modes(frame),
marker_color = cols[frame['label'].iloc[0]],
legendgroup=frame['label'].iloc[0],
name=frame['label'].iloc[0],
showlegend=False
))
fig.update_layout(template='plotly_dark')
fig.update_xaxes(showgrid=False)
fig.update_layout(uirevision='constant')
fig.show()
第一个建议
您应该如何执行此操作在很大程度上取决于数据集的结构。根据你的问题,我只能猜测它看起来像这样:
time param label
0 2020-01-01 -0.556014 medium
1 2020-01-02 0.185451 high
2 2020-01-03 -0.401111 medium
3 2020-01-04 0.436111 high
4 2020-01-05 0.412933 high
5 2020-01-06 0.636421 peak
6 2020-01-07 1.168237 peak
7 2020-01-08 1.205073 peak
8 2020-01-09 0.798674 peak
9 2020-01-10 0.174116 high
如果是这样,那么您可以很快 运行 解决数据点之间奇怪的连接问题,如果您想显示 param
不同颜色的线条轨迹。首先想到的是将 一种 颜色的线与 多种 颜色的标记组合在一起,如下所示:
这将为您提供良好的交互性,您可以在其中打开和关闭所有元素,也许只研究数据中 label=='peak
:
让我知道这对您来说效果如何,我们可以讨论更多细节。您将在此处找到数据示例和所有详细信息:
完整代码:
# imports
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np
import random
# settings
observations = 100
np.random.seed(5); cols = list('a')
param = np.random.uniform(low=-1, high=1, size=observations).tolist()
time = [t for t in pd.date_range('2020', freq='D', periods=observations).format()]
df=pd.DataFrame({'time': time,
'param':param})
df['param']=df['param'].cumsum()
def classify(e):
if e > 0.9: return 'peak'
if e > 0.75: return 'high'
if e > 0.25: return 'medium'
if e > 0.9: return 'low'
if e >= 0: return 'bottom'
df['label1'] = [(elem-df['param'].min())/(df['param'].max()-df['param'].min()) for elem in df['param']]
df['label'] = [classify(elem) for elem in df['label1']]
df = df.drop('label1', 1)
fig=go.Figure((go.Scatter(x=df['time'], y=df['param'],
mode='lines',
line=dict(color='rgba(0,0,200,0.7)'))))
fig.add_traces(px.scatter(df, x='time', y='param', color='label').data)
fig.update_layout(template='plotly_dark')
fig.update_xaxes(showgrid=False)
fig.show()