如何使用Plotly Graph Objects和Plotly Express在图形中定义颜色

32

有许多问题和答案涉及到这个主题。通过这篇文章,我想清楚地展示为什么像marker = {'color' : 'red'}这样的简单方法可以适用于plotly.graph_objects (go),但是对于plotly.express (px)来说,color='red'则不行,尽管颜色是px.Linepx.Scatter的属性。而且我想展示为什么它不可思议。


如果 px 应该是制作 Plotly 图表的最简单方法,那么为什么明显如color='red'这样的东西会返回错误

ValueError:'color'的值不是'data_frame'中列的名称。

简而言之,这是因为在px中的color 不接受任意颜色名称或代码,而是需要一个数据集中的变量名来为唯一值分配颜色循环并以不同颜色显示为线条。

让我通过应用gapminder数据集来演示,并展示2007年全球所有(至少是大多数)国家的预期寿命人均GDP的散点图。像下面这样的基本设置将产生以下绘图

图1,使用go绘制的图表:

enter image description here

颜色由一个名为plotly的循环设置,但在这里使用 marker = {'color' : 'red'}来指定。

图2,代码:

import plotly.graph_objects as go

df = px.data.gapminder()
df=df.query("year==2007")

fig = go.Figure()
fig.add_traces(go.Scatter(x=df['gdpPercap'], y=df["lifeExp"],
                          mode = 'markers',
                          marker = {'color' : 'red'}
                         ))
fig.show()

让我们试试使用 px,并假设 color='red' 可以解决问题:

代码二,尝试使用 px 定义颜色的散点图:

# imports
import plotly.express as px
import pandas as pd

# dataframe
df = px.data.gapminder()
df=df.query("year==2007")

# plotly express scatter plot
px.scatter(df, x="gdpPercap", y="lifeExp",
           color = 'red',
          )

结果:

值错误:'color' 的值不是 'data_frame' 中的列名。期望的列名之一为 ['country', 'continent', 'year', 'lifeExp', 'pop', 'gdpPercap', 'iso_alpha', 'iso_num'],但接收到的值为:red

那么这里发生了什么?

1个回答

55

首先,如果需要解释gopx之间更广泛的区别,请看这里这里。如果绝对不需要任何解释,您将在本答案末尾找到一个完整的代码片段,其中包含使用plotly.express进行颜色处理的许多功能。


第一部分:实质:

乍一看,color='red'可能并不像您预期的那样在使用px时起作用,但其实有非常好的理由。但首先,如果您只想手动设置所有标记的特定颜色,则可以使用.update_traces(marker=dict(color='red')),感谢Python的链式方法。但首先,让我们来看看默认设置:

1.1 Plotly express 默认值

图1:使用px.Scatter的px默认散点图

enter image description here

代码1:使用px.Scatter的px默认散点图

# imports
import plotly.express as px
import pandas as pd

# dataframe
df = px.data.gapminder()
df=df.query("year==2007")

# plotly express scatter plot
px.scatter(df, x="gdpPercap", y="lifeExp")

如问题中已经提到的,颜色被设置为默认 plotly 序列中可通过 px.colors.qualitative.Plotly 获取的第一种颜色:

['#636EFA', # the plotly blue you can see above
 '#EF553B',
 '#00CC96',
 '#AB63FA',
 '#FFA15A',
 '#19D3F3',
 '#FF6692',
 '#B6E880',
 '#FF97FF',
 '#FECB52']

这看起来相当不错。但是如果你想同时改变事物并添加更多信息呢?

1.2:如何覆盖默认设置并使用px颜色做到精确

正如我们之前提到的那样,px.scatter中的color属性不接受像red这样的颜色作为参数。相反,您可以例如使用color='continent'在数据集中轻松区分不同的变量。但是在px中有更多关于颜色的内容:


以下六种方法的组合将让您使用plotly express精确地处理颜色。请注意,您甚至不必选择。您可以同时使用以下方法中的一个一些全部方法。其中一种特别有用的方法是13的组合。但稍后我们会详细介绍这一点。这是您需要知道的:

1.使用以下方式更改px使用的颜色序列:

color_discrete_sequence=px.colors.qualitative.Alphabet

2. 使用 color 参数为不同的变量指定不同的颜色

color = 'continent'

3. 使用 customize 可以自定义一个或多个变量颜色。

color_discrete_map={"Asia": 'red'}

4. 使用字典推导和color_discrete_map轻松地对更大的变量子集进行分组。

subset = {"Asia", "Africa", "Oceania"}
group_color = {i: 'red' for i in subset}

5. 使用rgba()颜色代码设置不透明度。

color_discrete_map={"Asia": 'rgba(255,0,0,0.4)'}

6. 使用以下设置覆盖所有设置:

.update_traces(marker=dict(color='red'))

第二部分:细节和情节

以下代码片段将生成下面的图表,显示各个大陆在不同GDP水平下的预期寿命。标记的大小代表不同人口水平,从一开始就使事情更有趣。

图表2:

enter image description here

代码2:

import plotly.express as px
import pandas as pd

# dataframe, input
df = px.data.gapminder()
df=df.query("year==2007")

px.scatter(df, x="gdpPercap", y="lifeExp",
           color = 'continent',
           size='pop',
          )

为了说明上述方法的灵活性,让我们首先仅仅改变颜色序列。由于我们起初只展示了一种类别和一种颜色,您需要等待后续步骤以查看实际效果。但是这里是相同的图表,现在使用color_discrete_sequence=px.colors.qualitative.Alphabet ,如步骤1所示:

1. 使用以下内容更改 px 使用的颜色序列

color_discrete_sequence=px.colors.qualitative.Alphabet

输入图片说明

现在,让我们应用来自Alphabet颜色序列的颜色到不同的大陆上:

2. 使用 color 参数为不同的变量分配不同的颜色

color = 'continent'

输入图像描述 here

如果您和我一样认为这种颜色组合很舒适,但可能有些难以区分,您可以像这样为一个或多个大陆分配您选择的颜色:

3. 使用以下方法自定义一个或多个变量颜色:

color_discrete_map={"Asia": 'red'}

图片描述文字

这很棒:现在您可以更改顺序并选择任何颜色,以用于特别有趣的变量。但是,如果您想将特定颜色分配给较大的子集,则上述方法可能会有点繁琐。因此,您也可以使用字典推导式来执行此操作:

4. 使用字典推导和color_discrete_map为组分配颜色。

# imports
import plotly.express as px
import pandas as pd

# dataframe
df = px.data.gapminder()
df=df.query("year==2007")

subset = {"Asia", "Europe", "Oceania"}
group_color = {i: 'red' for i in subset}

# plotly express scatter plot
px.scatter(df, x="gdpPercap", y="lifeExp",
           size='pop',
           color='continent',
           color_discrete_sequence=px.colors.qualitative.Alphabet,
           color_discrete_map=group_color
          )

在此输入图片描述

5. 使用rgba()颜色代码设置透明度。

现在让我们退一步。如果你认为红色非常适合亚洲,但可能有点太强烈了,您可以使用一个rgba颜色如'rgba(255,0,0,0.4)'来调整不透明度,以获得以下效果:

在此输入图片描述

最后一个图的完整代码:

import plotly.express as px
import pandas as pd

# dataframe, input
df = px.data.gapminder()
df=df.query("year==2007")

px.scatter(df, x="gdpPercap", y="lifeExp",
           color_discrete_sequence=px.colors.qualitative.Alphabet,
           color = 'continent',
           size='pop',
           color_discrete_map={"Asia": 'rgba(255,0,0,0.4)'}
          )

如果您觉得现在我们有点太复杂了,您可以再次使用以下方式覆盖所有设置:

6. 使用以下方式覆盖所有设置:

.update_traces(marker=dict(color='red'))

enter image description here

这让我们回到了最初的地方。希望您会发现这个有用!

可用所有选项的完整代码片段:

# imports
import plotly.express as px
import pandas as pd

# dataframe
df = px.data.gapminder()
df=df.query("year==2007")

subset = {"Asia", "Europe", "Oceania"}
group_color = {i: 'red' for i in subset}

# plotly express scatter plot
px.scatter(df, x="gdpPercap", y="lifeExp",
           size='pop',
           color='continent',
           color_discrete_sequence=px.colors.qualitative.Alphabet,
           #color_discrete_map=group_color
           color_discrete_map={"Asia": 'rgba(255,0,0,0.4)'}
          )#.update_traces(marker=dict(color='red'))

2
太棒了的回答! - Dr. H. Lecter
3
关于如何覆盖默认设置并使用像素颜色实现自己想要的效果这个更大的问题/答案,我在文档中没有很快或容易地找到我需要的信息。 - Dr. H. Lecter
1
@Dr.H.Lecter 感谢您的反馈!我会考虑将标题更改为“如何覆盖默认设置并使用px颜色实现您想要的效果”。 - vestland
2
这是一个很好的答案,也是手册的一个不错的要点。我想提出一个修改建议。我认为在你的例子中强调离散着色仅适用于分类变量或字符串(例如示例中的continent)非常重要。即使您只有一组有限的整数,它也会被解释为颜色的连续比例尺。因此,像color_map = {1: "red", 2: "white"}这样的字典将无法工作,但是在将着色变量转换为字符串后,color_map = {"1": "red", "2": "white"}就可以了。 - malvoisen
2
@vestland,如果您是plotly团队的一员,我也想建议在手册中更突出地展示这一点。也许是我漏看了什么,但在阅读plotly.express.bar的手册时,离散和连续比例尺之间的切换对我来说并不清晰。我通过您的示例进行试错才弄清楚。最终,我偶然发现了plotly.com上名为“Python中的离散颜色”的页面,但在函数文档中找到所有内容会更好。 - malvoisen
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接