簡體   English   中英

Plotly 快遞線帶連續色標

[英]Plotly Express line with continuous color scale

我有以下一段代碼

import plotly.express as px
import pandas as pd
import numpy as np

x = [1,2,3,4,5,6]

df = pd.DataFrame(
    {
        'x': x*3,
        'y': list(np.array(x)) + list(np.array(x)**2) + list(np.array(x)**.5),
        'color': list(np.array(x)*0) + list(np.array(x)*0+1) + list(np.array(x)*0+2),
    }
)

for plotting_function in [px.scatter, px.line]:
    fig = plotting_function(
        df,
        x = 'x',
        y = 'y',
        color = 'color',
        title = f'Using {plotting_function.__name__}',
    )
    fig.show()

這會產生以下兩個圖:

在此處輸入圖像描述

在此處輸入圖像描述

由於某種原因px.line沒有產生我想要的連續色階,並且在px.scatter的文檔中我找不到如何將點與線連接起來。 我怎樣才能產生一個 plot 具有連續的色階和連接每個跟蹤點的線?

這是我要生產的 plot: 在此處輸入圖像描述

我不確定僅使用plotly.express是否可行。 如果您使用px.line ,那么您可以按照本答案中的描述傳遞參數markers=True ,但從 px.line 文檔來看,它看起來不支持連續色階。

你的問題的一個解決辦法是使用添加點之間的線路go.Scatter從plotly.graph_objects與參數mode='lines'和隱藏圖例項。

但是,您將需要一些函數來從連續色標中檢索線條的顏色,因為除非您指定它們,否則 go.Scatter 不會知道您的線條應該是什么顏色 - 幸好已經在這里回答

將所有這些放在一起:

import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np

x = [1,2,3,4,5,6]

df = pd.DataFrame(
    {
        'x': x*3,
        'y': list(np.array(x)) + list(np.array(x)**2) + list(np.array(x)**.5),
        'color': list(np.array(x)*0) + list(np.array(x)*0+1) + list(np.array(x)*0+2),
    }
)

# This function allows you to retrieve colors from a continuous color scale
# by providing the name of the color scale, and the normalized location between 0 and 1
# Reference: https://stackoverflow.com/questions/62710057/access-color-from-plotly-color-scale

def get_color(colorscale_name, loc):
    from _plotly_utils.basevalidators import ColorscaleValidator
    # first parameter: Name of the property being validated
    # second parameter: a string, doesn't really matter in our use case
    cv = ColorscaleValidator("colorscale", "")
    # colorscale will be a list of lists: [[loc1, "rgb1"], [loc2, "rgb2"], ...] 
    colorscale = cv.validate_coerce(colorscale_name)
    
    if hasattr(loc, "__iter__"):
        return [get_continuous_color(colorscale, x) for x in loc]
    return get_continuous_color(colorscale, loc)
        

# Identical to Adam's answer
import plotly.colors
from PIL import ImageColor

def get_continuous_color(colorscale, intermed):
    """
    Plotly continuous colorscales assign colors to the range [0, 1]. This function computes the intermediate
    color for any value in that range.

    Plotly doesn't make the colorscales directly accessible in a common format.
    Some are ready to use:
    
        colorscale = plotly.colors.PLOTLY_SCALES["Greens"]

    Others are just swatches that need to be constructed into a colorscale:

        viridis_colors, scale = plotly.colors.convert_colors_to_same_type(plotly.colors.sequential.Viridis)
        colorscale = plotly.colors.make_colorscale(viridis_colors, scale=scale)

    :param colorscale: A plotly continuous colorscale defined with RGB string colors.
    :param intermed: value in the range [0, 1]
    :return: color in rgb string format
    :rtype: str
    """
    if len(colorscale) < 1:
        raise ValueError("colorscale must have at least one color")

    hex_to_rgb = lambda c: "rgb" + str(ImageColor.getcolor(c, "RGB"))

    if intermed <= 0 or len(colorscale) == 1:
        c = colorscale[0][1]
        return c if c[0] != "#" else hex_to_rgb(c)
    if intermed >= 1:
        c = colorscale[-1][1]
        return c if c[0] != "#" else hex_to_rgb(c)

    for cutoff, color in colorscale:
        if intermed > cutoff:
            low_cutoff, low_color = cutoff, color
        else:
            high_cutoff, high_color = cutoff, color
            break

    if (low_color[0] == "#") or (high_color[0] == "#"):
        # some color scale names (such as cividis) returns:
        # [[loc1, "hex1"], [loc2, "hex2"], ...]
        low_color = hex_to_rgb(low_color)
        high_color = hex_to_rgb(high_color)

    return plotly.colors.find_intermediate_color(
        lowcolor=low_color,
        highcolor=high_color,
        intermed=((intermed - low_cutoff) / (high_cutoff - low_cutoff)),
        colortype="rgb",
    )

fig = px.scatter(
    df,
    x = 'x',
    y = 'y',
    color = 'color',
    color_continuous_scale = px.colors.sequential.Plasma,
    title = f'Using scatter',
)

for color_val in df.color.unique():
    color_val_normalized = (color_val - min(df.color)) / (max(df.color) - min(df.color))
    # print(f"color_val={color_val}, color_val_normalized={color_val_normalized}")
    df_subset = df[df['color'] == color_val]
    fig.add_trace(go.Scatter(
        x=df_subset['x'],
        y=df_subset['y'],
        mode='lines',
        marker=dict(color=get_color('Plasma', color_val_normalized)),
        showlegend=False
    ))

fig.show()

在此處輸入圖片說明

您可以在px.line中僅使用另外 2 個參數來實現此目的:

  • markers=True
  • color_discrete_sequence=my_plotly_continuous_sequence

完整的代碼看起來像這樣(注意列表切片[::4]以便 colors 間隔良好):

import plotly.express as px
import pandas as pd
import numpy as np

x = [1, 2, 3, 4, 5, 6]

df = pd.DataFrame(
    {
        'x': x * 3,
        'y': list(np.array(x)) + list(np.array(x) ** 2) + list(np.array(x) ** .5),
        'color': list(np.array(x) * 0) + list(np.array(x) * 0 + 1) + list(np.array(x) * 0 + 2),
    }
)

fig = px.line(
    df,
    x='x',
    y='y',
    color='color',
    color_discrete_sequence=px.colors.sequential.Plasma[::4],
    markers=True,
    template='plotly'
)
fig.show()

這將產生以下 output。

陰謀

如果您的行數多於顏色圖中的 colors,您可以構建自定義色標,以便獲得一個完整的序列而不是循環序列:

rgb = px.colors.convert_colors_to_same_type(px.colors.sequential.RdBu)[0]

colorscale = []
n_steps = 4  # Control the number of colors in the final colorscale
for i in range(len(rgb) - 1):
    for step in np.linspace(0, 1, n_steps):
        colorscale.append(px.colors.find_intermediate_color(rgb[i], rgb[i + 1], step, colortype='rgb'))

fig = px.line(df_e, x='temperature', y='probability', color='year', color_discrete_sequence=colorscale, height=900)
fig.show()

情節 2

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM