Plotly:如何为每个变量创建具有不同样式和颜色的线图?
Posted
技术标签:
【中文标题】Plotly:如何为每个变量创建具有不同样式和颜色的线图?【英文标题】:Plotly: How to create a line plot with different style and color for each variable? 【发布时间】:2021-02-28 22:18:24 【问题描述】:我正在尝试使用 Plotly express 创建一个包含 10 条不同颜色和标记的不同线条的图表。类似的东西:
我可以使用文档建议的px.line
函数创建具有不同颜色的漂亮图形。我的代码如下所示:
import plotly.express as px
import numpy as np
import pandas as pd
rand_elems = []
for i in range(10):
rand_elems.append(np.random.randn(25))
data = pd.DataFrame(rand_elems)
px.line(data_frame=data.T)
我的折线图是这样的:
其中每个变量都是一个 (25,) numpy 数组,其中包含来自标准正态分布的随机值(使用 np.random.randn(25)
创建)。
有没有办法可以为每一行添加不同的样式?也欢迎使用其他绘图库,因为我在 Plotly 的文档中找不到解决方案。
我知道我可以使用的线条样式是有限的。也许我可以循环浏览它们和颜色?对此有什么好的解决方案?
编辑:图表的目的仅仅是为了表明信号是随机的并且在标准正态分布范围内。
【问题讨论】:
@Mr.T 感谢 matplotlib 资源!我添加了一个编辑,说明我想用这个图表实现什么。 查看Plotly docs 的有关折线图的页面。这里有几个不同的例子。 【参考方案1】:我知道的方法是为您要绘制的每条线创建单独的图形对象(每个都有自己的样式)。然后创建所有图形对象的列表并将其传递给 go.Figure() 函数的data
参数。
有关示例,请参阅 this blog。
【讨论】:
【参考方案2】:px.line
非常适合高度多样性的数据集,例如跨越几大洲的一系列国家/地区的不同类别,因为您可以使用 color = 'country
、line_dash = 'continent
等参数来区分类别,从而为它们分配颜色和形状。这是一个使用内置数据集px.data.gapminder()
子集的示例
情节 1
代码 1
import plotly.express as px
from plotly.validators.scatter.marker import SymbolValidator
# data
df = px.data.gapminder()
df = df[df['country'].isin(['Canada', 'USA', 'Norway', 'Sweden', 'Germany'])]
# plotly
fig = px.line(df, x='year', y='lifeExp',
color='country',
line_dash = 'continent')
fig.show()
但您似乎也对标记的不同形状感兴趣,而且似乎没有像color
和line_shape
。因此,接下来是一种循环使用可用标记形状并将其应用于不同国家的方法。您当然可以通过从marker styles 中挑选形状来定义自己的序列,例如:
['arrow-bar-left', 'asterisk', 'arrow-right', 'line-ne', 'circle-cross', 'y-left']
但您也可以根据raw_symbols = SymbolValidator().values
获取一堆样式,稍微改进这些发现并将其添加到例如国家名称中。
这是结果
你是这样做的:
import plotly.express as px
from itertools import cycle
# data
df = px.data.gapminder()
df = df[df['country'].isin(['Canada', 'USA', 'Norway', 'Sweden', 'Germany'])]
# plotly
fig = px.line(df, x='year', y='lifeExp',
color='country',
line_dash = 'continent')
# retrieve a bunch of markers
raw_symbols = SymbolValidator().values
namestems = []
namevariants = []
symbols = []
for i in range(0,len(raw_symbols),3):
name = raw_symbols[i+2]
symbols.append(raw_symbols[i])
namestems.append(name.replace("-open", "").replace("-dot", ""))
namevariants.append(name[len(namestems[-1]):])
markers = cycle(list(set(namestems)))
# set unique marker style for different countries
fig.update_traces(mode='lines+markers')
for d in fig.data:
d.marker.symbol = next(markers)
d.marker.size = 10
fig.show()
【讨论】:
您的解决方案对我来说看起来很棒!正是我想要的!我很快就会用我的数据试一试(你不需要这样做)并接受你的回答!非常感谢@vestland 很抱歉@vesland 你的代码有一些错误。我已经修复了它,但我找到了一种更简单的方法来实现我想要的。您的代码非常直观,让我找到了解决方案。再次感谢!我会将我的版本发布在对这篇文章的回答中。 @GabrielZiegler 你说得对,from plotly.validators.scatter.marker import SymbolValidator
不见了。现在运行良好。【参考方案3】:
我采用了@vestland 的代码,并调整并修复了一个更简单的版本,可以完全满足我的需要。
这个想法是使用plotly.validators.scatter.marker
中的SymbolValidator()
,如@vestland 的回答中所述。也可以在此列表中添加一个随机因素以获得更明显的结果。
示例运行代码:
import plotly.express as px
from itertools import cycle
from plotly.validators.scatter.marker import SymbolValidator
# data
df = px.data.gapminder()
df = df[df['country'].isin(['Canada', 'USA', 'Norway', 'Sweden', 'Germany'])]
# plotly
fig = px.line(df, x='year', y='lifeExp',
color='country',
line_dash = 'continent')
raw_symbols = SymbolValidator().values
# Take only the string values which are in this order.
symbols_names = raw_symbols[::-2]
markers = cycle(symbols_names)
# set unique marker style for different countries
fig.update_traces(mode='lines+markers')
for d in fig.data:
d.marker.symbol = next(markers)
d.marker.size = 10
fig.show()
此代码生成以下图表: 非常感谢@vestland 的见解,我想知道 Plotly 是否可以在下一个版本中将此作为参数选项。
更新:
如果您的 DataFrame 没有像我这样用于 line_dash
参数的聚合列,您还可以循环浏览带有线条样式的列表并使用 `fig.data.line["dash"] 覆盖它们下面:
import numpy as np
import random
import plotly.express as px
import numpy as np
import pandas as pd
from itertools import cycle
from random import shuffle
from plotly.validators.scatter.marker import SymbolValidator
from plotly.validators.scatter.line import DashValidator
rand_elems = []
for i in range(10):
rand_elems.append(np.random.randn(25))
data = pd.DataFrame(rand_elems)
data.index = [f"Signal i" for i in range(10)]
为 DataFrame 中的每一列生成不同的标记和线条样式的代码。
line_styles_names = ['solid', 'dot', 'dash', 'longdash', 'dashdot', 'longdashdot']
line_styles = cycle(line_styles_names)
fig = (px.line(data_frame=data.T,
color_discrete_sequence=px.colors.qualitative.Bold_r,
title="First 10 Signals Visualization",
))
symbols_names = list(set([i.replace("-open", "").replace("-dot", "") for i in SymbolValidator().values[::-2]]))
shuffle(symbols_names)
markers = cycle(symbols_names)
_ = fig.update_traces(mode='lines+markers')
for d in fig.data:
d.line["dash"] = next(line_styles)
d.marker.symbol = next(markers)
d.marker.size = 10
fig.show()
有了这个,结果应该和这个类似,这正是我想要的。
【讨论】:
以上是关于Plotly:如何为每个变量创建具有不同样式和颜色的线图?的主要内容,如果未能解决你的问题,请参考以下文章
Plotly:如何为标准偏差制作具有多条线和阴影区域的图形?
DiagrammeR:我如何为流程图的某些节点使用不同的颜色?