通过整数(计数器)从颜色图中迭代颜色

Posted

技术标签:

【中文标题】通过整数(计数器)从颜色图中迭代颜色【英文标题】:Iterate color from colormap by integer (counter) 【发布时间】:2022-01-13 08:49:31 【问题描述】:

我尝试通过整数从颜色图中获取颜色,就像从列表中获取值一样:

list[1]

我想使用的颜色图可以在此处的“定性('tab20')”下找到:

https://matplotlib.org/stable/tutorials/colors/colormaps.html

我的代码简化了:

import plotly.graph_objs as go
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

plt.style.use('seaborn')

df = pd.DataFrame(np.random.randint(0,100,size=(100, 5)), columns=list('ABCDF'))

count=1

fig = go.Figure()

for i in df.columns:
    fig.add_trace(go.Scatter(x=df['A'], y=df[i], line_color=plt.plot_color_gradients['Qualitative']['tab20'][count]))
    count+=1

fig.show()

这部分是上面示例的伪代码和我的核心问题,我不知道如何正确实现颜色图以及如何通过整数访问其中的颜色:

line_color=plt.plot_color_gradients['Qualitative']['tab20'][count]

我希望每条轨迹都能通过整数(计数)从颜色图中获得漂亮的颜色,并且颜色的给出顺序是可复制的。跟踪的数量是可变的,但很可能永远不会超过 20。

【问题讨论】:

代码的当前(错误)行为是什么? 伪代码行。我不知道如何正确实现颜色图以及如何通过整数访问其中的颜色。 【参考方案1】:

fig.for_each_trace()count() 一起从itertools 使用,您可以将其缩小为:

col_list = px.colors.qualitative.Alphabet*10
counter = count(start = 0, step = 1)

fig = px.line(df, x=df.index, y=df.columns, template = 'plotly_dark')
fig.for_each_trace(lambda t: t.update(line_color = col_list[next(counter)]))

情节

一个潜在的缺点是您可能会在用完痕迹之前用完颜色。解决这个问题的一个hacky方法是让列表重复多次:

col_list = px.colors.qualitative.Alphabet*10

或者您可以使用itertoolscycle() 中的另一种方法,如下所示:

col_cycle = cycle(px.colors.qualitative.Alphabet)
fig = px.line(df, x=df.index, y=df.columns, template = 'plotly_dark')
fig.for_each_trace(lambda t: t.update(line_color = next(col_cycle)))

count() 的完整代码

import pandas as pd
import numpy as np
import plotly.express as px
from itertools import cycle
from itertools import count

# data
np.random.seed(1)
df = pd.DataFrame(np.random.randint(-1,2,size=(100, 5)), columns=list('ABCDF'))
df.iloc[0] = 0
df = df.cumsum()

col_list = px.colors.qualitative.Alphabet*10
counter = count(start = 0, step = 1)

# figure
fig = px.line(df, x=df.index, y=df.columns, template = 'plotly_dark')
fig.for_each_trace(lambda t: t.update(line_color = col_list[next(counter)]))

fig.show()

cycle() 的完整代码

import pandas as pd
import numpy as np
import plotly.express as px
from itertools import cycle
from itertools import count

# data
np.random.seed(1)
df = pd.DataFrame(np.random.randint(-1,2,size=(100, 5)), columns=list('ABCDF'))
df.iloc[0] = 0
df = df.cumsum()

# color cycle and figure
col_cycle = cycle(px.colors.qualitative.Alphabet)
fig = px.line(df, x=df.index, y=df.columns, template = 'plotly_dark')
fig.for_each_trace(lambda t: t.update(line_color = next(col_cycle)))

fig.show()

【讨论】:

谢谢。循环提示非常有用。 请问,使用 plotly.express 还是 plotly.graph_objs 更好? @Veritas_in_Numeris 这在一定程度上取决于您想要做什么。两者都非常有用且用途广泛。大多数时候,我使用px 构建图形结构,并使用fig.add_traces(go.Scatter()) 添加元素。您应该知道的一件事是,这两种方法都创建了相同的绘图对象。【参考方案2】:

如果您要使用的颜色图是在matplotlib中设置的tab20,请将其从matplotlib的颜色图转换为十六进制代码并将其存储在列表中。使用该颜色列表并将其用于循环过程的计数器。另外,plotly 有 seaborn 的风格,所以我指定了。 plotly 的颜色图类似于 tab20,所以 plotly 可能就是你所需要的。更多信息请参见information。

import pandas as pd
import numpy as np
import plotly.graph_objs as go
import matplotlib.pyplot as plt
import matplotlib.colors as cm

df = pd.DataFrame(np.random.randint(0, 100, size=(100, 5)), columns=list('ABCDF'))

colors = [cm.to_hex(plt.cm.tab20(i)) for i in range(20)]

fig = go.Figure()

for i,c in enumerate(df.columns):
    fig.add_trace(go.Scatter(
        x=df.index,
        y=df[c],
        mode='lines',
        marker=dict(color=colors[i])
    ))

fig.update_layout(template='seaborn')
fig.show()

【讨论】:

这是完美的。非常精简和性感的解决方案。谢谢

以上是关于通过整数(计数器)从颜色图中迭代颜色的主要内容,如果未能解决你的问题,请参考以下文章

分类颜色

75. 颜色分类

位于子图中的多个计数图中的Seaborn堆叠条[重复]

LeetCode——75. 颜色分类

排序和搜索----颜色分类

LeetCode 75. 颜色分类