跳至主要内容

Plotly 形状:注释与样式美化图表指南

学习如何使用 Plotly 形状提升数据叙事。本指南全面讲解在 Python 中添加与美化注释,从基础矩形与直线到高级交互几何体。
· 12分钟 阅读

使用 AI 探索

Plotly 是创建交互式图表最强大且最受欢迎的 Python 库之一。用 Plotly 绘制基础图表并不复杂,但要实现真正有影响力的数据可视化,往往需要添加一些能引导读者注意力并提供重要背景的信息元素。这正是 Plotly 形状大显身手的地方。

形状是矩形、线条、圆等图形元素,您可以将其叠加到 Plotly 图形上,用于注释、突出显示并添加关键信息。它们是将标准图表提升为信息丰富、见解深刻且可发表质量可视化的关键。

plotly shapes

图片来源:作者

在本文中,我们将从基础实现到高级自定义技术,全面介绍 plotly 形状。对于刚接触 Plotly 的读者,先熟悉其高级接口是很好的第一步,这门Python 中使用 Plotly 进行数据可视化入门课程可帮助您在深入形状等自定义内容前打好基础。

什么是 Plotly 形状?

Plotly 形状是绘制在图形上的矢量图,用于提供额外上下文或突出特定区域。这类注释有助于构建既美观又信息丰富的图表。

形状在数据可视化中的重要性

在数据可视化中,清晰至关重要。散点图或柱状图等图表呈现数据,而形状则帮助讲清数据背后的故事。它们主要有两大作用:

  • 突出数据趋势: 形状可以吸引读者注意数据中的关键时期或事件。例如,您可以在 GDP 的时间序列图上用矩形阴影标注经济衰退期,或用一条线标出重要的政策变化。这样的视觉提示能让读者立刻理解外部因素对数据的影响。
  • 提供语境化注释: 形状可以圈出或指向特定数据点或簇,如离群点、关注群组或关键阈值。想象一个质量控制图,您用圆圈标记超出可接受范围的测量值。这样能更快、更直观地解读数据。

如果您想快速浏览最常见的数据可视化、使用时机及常见用例,请查看我们的数据可视化速查表。

Plotly 中的形状类型概览

Plotly 支持在图形布局中添加多种几何形状。每种形状由其 type 和特定坐标参数定义。

以下是主要形状的简要介绍:

  • 矩形(type: 'rect'):由两个对角点(x0、y0)和(x1、y1)定义。矩形非常适合为关注区域着色或突出特定的数据窗口。
  • 直线(type: 'line'):由起点(x0、y0)和终点(x1、y1)定义。直线非常适合创建趋势线、阈值线或参考标记。
  • 圆形(type: 'circle'):由中心(x0、y0)和半径定义。圆形非常适合强调单个数据点或小型簇。注意,为确保圆不会看起来像椭圆,通常需要为坐标轴设置等比例纵横比(fig.update_layout(yaxis_scaleanchor="x"))。
  • 路径(type: 'path'):由 SVG 路径字符串定义。路径允许绘制复杂的自由形状,包括多边形。您可以提供一系列命令(如 M 表示移动、L 表示连线到、Z 表示闭合路径)来绘制所需的任意形状。这是创建定制几何注释最灵活的选项。

理解这些基本类型是掌握在 Plotly 图形中进行可视化注释的第一步。

向 Plotly 图表添加形状

在可视化中实现 plotly 形状主要有两种方式:用于单个形状的 add_shape() 方法,以及用于多个形状的 update_layout() 方式。两种方法各有优势,取决于您的具体用例和工作流偏好。下面先看看如何使用 add_shape() 方法添加形状。

如何使用 add_shape() 添加形状?

向 Plotly 图形添加单个形状的主要方法是 fig.add_shape()。add_shape() 是 plotly.graph_objects.Figure 对象的方法。您先创建基础图(例如散点图或折线图),然后调用该方法将形状叠加其上。

当您需要根据特定条件或数据值以编程方式添加形状时,此方法尤为有用。下面通过一个基础示例,在时间序列图上高亮某一特定区域。

import plotly.graph_objects as go
import numpy as np

# Create sample data
x = np.linspace(0, 10, 100)
y = np.sin(x) + np.random.normal(0, 0.1, 100)

# Create base figure
fig = go.Figure()
fig.add_trace(go.Scatter(x=x, y=y, mode='lines', name='Signal'))

# Add a shape using add_shape method
fig.add_shape(
    type="rect",           # Shape type
    x0=2, x1=4,           # X coordinates
    y0=-2, y1=2,          # Y coordinates
    fillcolor="rgba(255, 0, 0, 0.3)",  # Fill color with transparency
    line=dict(color="red", width=2)     # Border styling
)

fig.show()

输出:

Plotly add shapes using add_shape()

当您理解坐标系统后,plotly 的 add_shape() 功能会尤其强大。形状可以通过 xref 和 yref 参数引用不同的坐标系统。它们指定坐标框架:使用 'x'/'y' 以数据单位解释数值,或使用 'paper' 应用归一化的绘图区(0–1 从左下到右上覆盖完整宽/高)。下面按所示参数修改上述图表:

# Shape referenced to data coordinates (default)
fig.add_shape(type="line", x0=1, x1=9, y0=0, y1=0,
              line=dict(color="green", width=3))

# Shape referenced to paper coordinates (0-1 scale)
fig.add_shape(type="rect", xref="paper", yref="paper",
              x0=0.1, x1=0.9, y0=0.1, y1=0.9,
              fillcolor="rgba(0, 0, 255, 0.1)")

输出:

自定义矩形与直线

矩形和直线是最常用于注释的形状。Plotly 提供了广泛的自定义选项来控制它们的外观。若需快速参考常见 Plotly 语法,Plotly Express 速查表非常有用。下面看看如何自定义这些形状。

矩形形状自定义

矩形由两个点(x0、y0 和 x1、y1)定义。您可以分别设置填充与边框样式。

# Advanced rectangle customization
fig.add_shape(
    type="rect",
    x0=3, x1=7,
    y0=-1.5, y1=1.5,
    # Fill properties
    fillcolor="rgba(50, 171, 96, 0.4)",
    # Line properties
    line=dict(
        color="darkgreen",
        width=3,
        dash="dashdot"  # Options: solid, dot, dash, longdash, dashdot
    ),
    # Layer control
    layer="below"  # Options: above, below
)

输出:

Plotly Rectangle Shape Customization

直线形状自定义

对于跨越整个图形的水平或垂直线,您可以使用专用的 “add_hline” 和 “add_vline” 方法;若需更精细控制,可通过通用的 “add_shape” 方法添加。请看示例:

# Horizontal threshold lines
fig.add_hline(y=1.0, line_dash="dash", line_color="red", 
              annotation_text="Upper Threshold")
fig.add_hline(y=-1.0, line_dash="dash", line_color="red", 
              annotation_text="Lower Threshold")

# Custom diagonal line
fig.add_shape(
    type="line",
    x0=0, x1=10,
    y0=-2, y1=2,
    line=dict(
        color="purple",
        width=4,
        dash="longdashdot"
    )
)

输出:

Plotly Line shape customization

这些示例展示了如何轻松添加并美化基础的 Plotly 形状,使图表更具信息性。

高级配置与自定义

除了添加基础形状,Plotly 还提供了强大的工具来管理多个形状并控制其视觉层级。这些高级特性对于创建复杂、分层且动态的可视化至关重要。下面看看一些配置与自定义的方法。

使用 plotly.update_layout 进行动态更新

虽然 add_shape() 非常适合逐个添加形状,但当形状是以编程方式生成时,update_layout() 对管理一组形状更高效。您可以将形状字典列表直接传递给 update_layout() 中的 shapes 参数,而无需为每个形状调用函数。

下面是该方法的示例:

import plotly.graph_objects as go
import numpy as np

# Sample scatter plot data
x_data = np.linspace(0, 10, 50)
y_data = np.sin(x_data) + np.random.normal(0, 0.1, 50)

fig = go.Figure(data=go.Scatter(x=x_data, y=y_data, mode='markers', name='Data Points'))

# Define a list of shapes to add
shapes_to_add = [
    # A rectangle highlighting a peak area
    dict(
        type="rect",
        x0=1, x1=2.5, y0=0.8, y1=1.2,
        fillcolor="rgba(255, 165, 0, 0.4)",
        line_width=0
    ),
    # A vertical line marking an event
    dict(
        type="line",
        x0=7.5, x1=7.5, y0=0, y1=1,
        yref="paper", # Span the full plot height
        line=dict(color="red", width=2, dash="dot")
    )
]

# Add all shapes at once using update_layout
fig.update_layout(
    shapes=shapes_to_add
)

fig.show()

输出:

Using plotly.update_layout for dynamic updates

这种方式对动态应用尤为强大,例如在 Dash 仪表板中,形状需要根据用户输入变化。您可以生成新的形状对象列表,并用一次干净的布局更新来替换。这种方法能使代码更有条理,并且在一次性添加大量形状时通常更高效。

图层与 z-index 控制

向图表添加形状时,控制它们是在数据之上还是之下非常重要。Plotly 通过 layer 属性来管理。虽然它不像 CSS 中的精细 z-index,但提供了必要的视觉堆叠控制。

layer 属性可设置为以下两种值:

  • 'above':形状绘制在数据轨迹之上。默认设置,适用于必须清晰可见的注释。
  • 'below':形状绘制在数据轨迹与网格线之下。适合用于背景着色或高亮区域而不遮挡数据点。

在同一层内,shapes 列表中形状的顺序也很重要:列表中后定义的形状会绘制在先前定义的形状之上。

下面通过示例演示图层效果:

import plotly.graph_objects as go

fig = go.Figure(data=go.Scatter(x=[1, 2, 3, 4, 5], y=[5, 3, 4, 2, 6], mode='markers', marker_size=20, name='Data'))

# Add a shape BELOW the data points
fig.add_shape(
    type="rect",
    x0=2.5, y0=2.5, x1=4.5, y1=4.5,
    fillcolor="LightPink",
    opacity=0.8,
    layer="below", # Key parameter
    line_width=0
)

# Add a shape ABOVE the data points
fig.add_shape(
    type="circle",
    x0=0.5, y0=4.5, x1=1.5, y1=5.5,
    fillcolor="LightSeaGreen",
    opacity=0.6,
    layer="above", # Key parameter
    line_width=0
)

fig.update_layout(
    xaxis=dict(showgrid=False), # Turn off gridlines to see effect clearly
    yaxis=dict(showgrid=False)
)

fig.show()

输出:

Layering and z-index control

如您所见,粉色矩形位于标记点之后,而绿色圆形覆盖在数据点之上。

掌握这些布局与图层技巧,是用 Plotly 创建更高级、可交互可视化的关键。对于使用 R 的读者,类似概念同样适用,可参见R 中使用 Plotly 的交互式数据可视化进阶。

交互式形状编辑

Plotly 的强大之处在于其交互性。您可以让 Plotly 形状可编辑,使用户可在图上直接拖拽、调整大小并旋转。通过在形状定义中设置 editable=True 即可启用此功能。下面示例展示了如何实现:

import plotly.graph_objects as go
import numpy as np

# Create a scatter plot
fig = go.Figure(go.Scatter(
    x=np.random.rand(100),
    y=np.random.rand(100),
    mode='markers'
))

# Add a draggable rectangle
fig.add_shape(
    type="rect",
    x0=0.2, y0=0.2, x1=0.5, y1=0.5,
    line=dict(color="RoyalBlue", width=2),
    fillcolor="LightSkyBlue",
    opacity=0.5,
    editable=True # This makes the shape interactive
)

fig.update_layout(
    xaxis=dict(range=[0, 1]),
    yaxis=dict(range=[0, 1]),
    # The 'newshape' button in the modebar allows drawing new shapes
    # The config dictionary enables editing of existing shapes
    dragmode='select'
)

# To enable editing, the modebar must be visible (default) which you will see when hovering over the graph with the mouse.

# and the plot's config can ensure editing tools are available.
fig.show(config={'edits': {'shapePosition': True}})

输出:

交互式形状对探索性数据分析非常有用。例如,用户可以在 Dash 应用中拖动矩形覆盖不同时间段,实时查看对应的汇总统计值;或者通过调整圆的大小来选择不同的点簇以便进一步分析。

虽然功能强大,但在复杂的 Web 应用中大量使用可编辑形状可能影响性能。不过,若要构建真正动态、以用户为中心的工具,它们不可或缺。

探索交互性是现代数据可视化的重要组成部分,该主题在R 中使用 Plotly 进行交互式数据可视化等课程中也有深入讲解,与 Python 版本原理相通。

将 Plotly 与其他库集成

虽然 Plotly 内置形状功能强大,但有时您需要创建高度复杂或自定义的几何图形。通过与 Shapely 等专业库集成,您可以定义复杂多边形,并将其作为自定义 Plotly 形状添加到可视化中。

使用 Shapely 创建高级几何形状

Shapely 是一个强大的 Python 库,用于处理与分析平面几何对象。它是计算几何的首选工具,常用于地理空间分析。您可以用它创建复杂形状,如两个重叠圆的并集或带有孔洞的多边形,然后在 Plotly 中进行可视化。

该过程分为两步:

  1. 使用 Shapely 定义复杂形状。
  2. 从 Shapely 对象中提取坐标,并格式化为 SVG 路径字符串,Plotly 可使用 type: 'path' 渲染。

SVG 路径字符串是一种绘图迷你语言。它使用诸如 M(moveto)设置起点,L(lineto)绘制到新点的线段,Z 闭合路径等命令。

下面看看如何创建一个带镂空的多边形,并将其添加到 Plotly 图形中。

import plotly.graph_objects as go
from shapely.geometry import Polygon

# 1. Create a complex shape using Shapely
# An outer rectangle
outer_coords = [(1, 1), (1, 5), (8, 5), (8, 1)]
# An inner rectangle (this will be the "hole")
inner_coords = [(3, 2), (3, 4), (6, 4), (6, 2)]

# Define the polygon with a hole
polygon_with_hole = Polygon(outer_coords, [inner_coords])

# 2. Extract coordinates and build the SVG path string
# The exterior path
exterior_x, exterior_y = polygon_with_hole.exterior.xy
path = f"M {exterior_x[0]} {exterior_y[0]}"
for x, y in zip(exterior_x[1:], exterior_y[1:]):
    path += f" L {x} {y}"
path += " Z" # Close the exterior path

# The interior path (the hole)
interior_x, interior_y = polygon_with_hole.interiors[0].xy
path += f" M {interior_x[0]} {interior_y[0]}"
for x, y in zip(interior_x[1:], interior_y[1:]):
    path += f" L {x} {y}"
path += " Z" # Close the interior path

# Create a figure
fig = go.Figure()

# Add the complex shape to the figure
fig.add_shape(
    type="path",
    path=path,
    fillcolor="LightSeaGreen",
    opacity=0.7,
    line_color="DarkSlateGray"
)

# You can add data to see how the shape interacts with it
fig.add_trace(go.Scatter(
    x=[2, 7, 4.5], 
    y=[3, 3, 1.5], 
    mode='markers', 
    marker=dict(size=15, color='DarkRed')
))

# Use scaleanchor to ensure the shape's aspect ratio is preserved
fig.update_yaxes(scaleanchor="x", scaleratio=1)
fig.show()

输出:

Using Shapely for advanced geometric shapes

该技巧在地理空间应用中十分有用,例如绘制自定义销售区域,或在科研场景中高亮不规则兴趣区域。

了解不同类型数据图的创建方式,以及如何用这类工具增强图表,是每位数据从业者的基础技能。您可在本指南中进一步了解如何在 Python 中创建这些图表。

样式与美学自定义

Plotly 形状的默认外观是实用的,但为了打造精致、专业的可视化,自定义样式很重要。对颜色、不透明度和填充的巧妙运用能显著提升可读性与美观度。

颜色、不透明度与图案填充

Plotly 为形状外观提供了精细控制,使您能够与图表的配色与设计语言保持一致。

若需精准控制颜色与透明度,强烈建议使用 RGBA(红、绿、蓝、透明度)颜色规范。a(alpha)通道控制不透明度,1 为完全不透明,0 为完全透明。

这对于创建不干扰的高亮区域尤为关键,使形状在添加上下文的同时不完全遮挡下方数据。您可以用字符串形式提供 RGBA 值,如 'rgba(255, 99, 71, 0.5)'。请看示例:

import plotly.graph_objects as go
import numpy as np

# Create sample data for styling demonstration
x = np.linspace(0, 10, 100)
y1 = np.sin(x) + np.random.normal(0, 0.1, 100)
y2 = np.cos(x) + np.random.normal(0, 0.1, 100)

fig = go.Figure()
fig.add_trace(go.Scatter(x=x, y=y1, name='Signal 1', line=dict(color='blue')))
fig.add_trace(go.Scatter(x=x, y=y2, name='Signal 2', line=dict(color='red')))

# RGBA Color Technique 1: Graduated opacity for depth
opacity_levels = [0.15, 0.25, 0.35]
colors = ['255,0,0', '0,255,0', '0,0,255']

for i, (opacity, color) in enumerate(zip(opacity_levels, colors)):
    fig.add_shape(
        type="rect",
        x0=i*2.5, x1=(i+1)*2.5,
        y0=-3, y1=3,
        fillcolor=f"rgba({color},{opacity})",
        line=dict(color=f"rgb({color})", width=2),
        layer="below"
    )

# RGBA Technique 2: Color blending for overlapping regions
fig.add_shape(
    type="circle",
    x0=7.5, x1=9.5,
    y0=-1, y1=1,
    fillcolor="rgba(255, 255, 0, 0.4)",  # Semi-transparent yellow
    line=dict(color="orange", width=3),
    layer="below"
)

fig.update_layout(
    title="Advanced RGBA Color Techniques in Plotly Shapes",
    showlegend=True
)
fig.show()

输出:

Color, opacity, and pattern fills

图案填充的模拟策略

虽然 Plotly 原生不支持图案填充,但数据从业者可以通过巧妙技巧模拟复杂填充图案。例如,我们可以通过函数在图中创建图案,如下所示:

def create_pattern_fill_simulation(fig, x0, x1, y0, y1, pattern_type='diagonal'):
    """Simulate pattern fills using multiple overlapping shapes"""
    
    if pattern_type == 'diagonal':
        # Create diagonal line pattern
        line_spacing = 0.2
        line_width = 1
        
        # Calculate diagonal lines
        range_x = x1 - x0
        range_y = y1 - y0
        num_lines = int((range_x + range_y) / line_spacing)
        
        for i in range(num_lines):
            offset = i * line_spacing
            
            # Calculate line endpoints for diagonal pattern
            start_x = max(x0, x0 + offset - range_y)
            start_y = max(y0, y1 - offset)
            end_x = min(x1, x0 + offset)
            end_y = min(y1, y1 - offset + range_x)
            
            fig.add_shape(
                type="line",
                x0=start_x, x1=end_x,
                y0=start_y, y1=end_y,
                line=dict(color="rgba(0, 0, 0, 0.3)", width=line_width),
                layer="above"
            )
    
    elif pattern_type == 'crosshatch':
        # Create crosshatch pattern
        spacing = 0.3
        
        # Vertical lines
        x_lines = np.arange(x0, x1, spacing)
        for x_line in x_lines:
            fig.add_shape(
                type="line",
                x0=x_line, x1=x_line,
                y0=y0, y1=y1,
                line=dict(color="rgba(100, 100, 100, 0.4)", width=1),
                layer="above"
            )
        
        # Horizontal lines
        y_lines = np.arange(y0, y1, spacing)
        for y_line in y_lines:
            fig.add_shape(
                type="line",
                x0=x0, x1=x1,
                y0=y_line, y1=y_line,
                line=dict(color="rgba(100, 100, 100, 0.4)", width=1),
                layer="above"
            )
    
    return fig

# Demonstration of pattern fill simulation
pattern_fig = go.Figure()
pattern_fig.add_trace(go.Scatter(x=[1, 2, 3, 4, 5], y=[2, 4, 3, 5, 1], 
                                mode='lines+markers', name='Data'))

# Add base rectangle
pattern_fig.add_shape(
    type="rect",
    x0=1.5, x1=3.5,
    y0=1, y1=5,
    fillcolor="rgba(200, 200, 255, 0.3)",
    line=dict(color="blue", width=2),
    layer="below"
)

# Apply pattern fill simulation
pattern_fig = create_pattern_fill_simulation(pattern_fig, 1.5, 3.5, 1, 5, 'diagonal')
pattern_fig.show()

Pattern fill simulation strategies

渐变效果的模拟

创建类似渐变的效果需要对多个具有不同不透明度的形状进行策略性分层。我们可以沿用创建图案时的策略来实现,如下所示:

def create_gradient_effect(fig, x0, x1, y0, y1, start_color, end_color, num_bands=20):
    """Simulate gradient fill using multiple rectangular bands"""
    
    # Parse RGB values from color strings
    def parse_rgb(color_str):
        if color_str.startswith('rgb('):
            values = color_str[4:-1].split(',')
            return [int(v.strip()) for v in values]
        return [0, 0, 0]  # Default to black if parsing fails
    
    start_rgb = parse_rgb(start_color) if isinstance(start_color, str) else start_color
    end_rgb = parse_rgb(end_color) if isinstance(end_color, str) else end_color
    
    band_height = (y1 - y0) / num_bands
    
    for i in range(num_bands):
        # Calculate interpolated color
        ratio = i / (num_bands - 1)
        r = int(start_rgb[0] + (end_rgb[0] - start_rgb[0]) * ratio)
        g = int(start_rgb[1] + (end_rgb[1] - start_rgb[1]) * ratio)
        b = int(start_rgb[2] + (end_rgb[2] - start_rgb[2]) * ratio)
        
        # Calculate band position
        band_y0 = y0 + i * band_height
        band_y1 = band_y0 + band_height
        
        fig.add_shape(
            type="rect",
            x0=x0, x1=x1,
            y0=band_y0, y1=band_y1,
            fillcolor=f"rgba({r}, {g}, {b}, 0.7)",
            line=dict(width=0),  # No border for seamless gradient
            layer="below"
        )
    
    return fig

# Apply gradient effect
gradient_fig = go.Figure()
gradient_fig.add_trace(go.Scatter(x=list(range(10)), 
                                 y=np.random.randn(10).cumsum(),
                                 mode='lines', name='Time Series'))

gradient_fig = create_gradient_effect(
    gradient_fig, 2, 8, -3, 3, 
    [255, 0, 0], [0, 0, 255],  # Red to blue gradient
    num_bands=30
)
gradient_fig.show()

输出:

Gradient effect simulation

排错与优化

尽管添加 Plotly 形状通常很直接,但在复杂图表中您可能会遇到对齐或性能问题。了解这些常见陷阱及其应对方法将为您节省大量时间与精力。

形状对齐的常见问题

最常见的挑战之一是让形状准确出现在您期望的位置。本应横跨整个图宽的直线可能会短一截,或矩形与网格线未如预期对齐。这些问题几乎总是源于坐标引用不正确。

Plotly 用两种坐标系统来放置形状:

  • 数据坐标(xref: 'x', yref: 'y'):默认选项。形状位置与 x、y 轴上的数值绑定。例如,x0=50 表示位于 x 轴 50 处。
  • 画布坐标(xref: 'paper', yref: 'paper'):位置相对于绘图区本身,0 为起点(左/下边缘),1 为终点(右/上边缘)。该系统独立于数据值或轴范围。

问题: 您想在 y=10 处绘制一条横跨整个图的水平线。如果用数据坐标定义 x0 和 x1,它只会跨越当前的轴范围。若用户缩放或平移,直线不会延伸到新的边界。

解决方案: 若要让形状跨越绘图区的完整宽度或高度,请在要跨越的轴上使用 'paper' 坐标。

import plotly.graph_objects as go

fig = go.Figure(data=go.Scatter(x=[0, 10], y=[0, 20]))

# Incorrect: Vertical line that might not span the full height if the user zooms out.
# This line is drawn from y=0 to y=20 in DATA units.
fig.add_shape(
    type="line",
    x0=5, y0=0, x1=5, y1=20,
    line=dict(color="Red", width=2, dash="dash"),
    name="Incorrect Line" # Name for legend
)

# Correct: Vertical line that ALWAYS spans the full plot height.
# It is drawn from the bottom edge (0) to the top edge (1) of the PLOT area.
fig.add_shape(
    type="line",
    x0=8, y0=0, x1=8, y1=1,
    yref="paper", # The key to spanning the full height
    line=dict(color="Green", width=3),
    name="Correct Line"
)

fig.update_layout(title_text="Correctly Spanning the Plot Area")
fig.show()

输出:

在涉及用户交互(如缩放、平移)时,请务必再次检查 xref 与 yref 属性,确保形状按预期表现。

性能注意事项

向图中添加少量形状时,性能影响可以忽略不计。但若添加数百或数千个形状,会显著拖慢渲染与交互。每个形状都是添加到网页 DOM 的独立 SVG 元素,过多的 DOM 元素会给浏览器带来压力。

以下是优化性能的策略:

  • 限制形状数量: 这是最简单的解决方案。如果需要可视化数千个矩形区域,考虑是否可以用其他图表类型(如 go.Heatmap)更高效地表示,将信息作为单个轨迹而非数千个形状对象。
  • 使用 update_layout 进行批量添加: 如前所述,通过 fig.update_layout(shapes=...) 添加形状列表比在循环中多次调用 fig.add_shape() 更高效。
  • 为数据使用 WebGL 轨迹: 虽然形状本身以 SVG 渲染,但您可以通过为主数据使用基于 WebGL 的轨迹(例如 go.Scattergl)来提升复杂图表的整体性能。这样可将数据渲染交给 GPU 处理,从而释放 CPU,更顺畅地处理 SVG 形状。当您同时拥有海量数据点和适量形状时尤其有用。

在大多数用例中,关键是注意您创建的独立形状元素数量。在循环中添加数千个 Plotly 形状之前,不妨停下来思考是否存在更高性能的可视化策略。

结语

熟练掌握 Plotly 形状,能将图表从简单的数据呈现,升华为引人入胜、语境丰富的故事。我们从绘制定基础的直线与矩形,到分层复杂、可交互的几何图形,都一一探讨。

通过应用这些技巧,您可以引导受众的关注点,突出关键洞见,并构建更直观、沟通清晰且有冲击力的可视化。

准备好应用这些技能了吗?立即开始构建更强大的可视化,探索 Python 中使用 Plotly 进行数据可视化入门 课程,并将您的所学付诸实践。

Plotly 形状常见问答

Plotly 形状的用途是什么?

Plotly 形状用于添加注释,如直线、矩形和圆形,以在图表上突出关键数据区域。

如何在 Plotly 中添加多个形状?

您可以将形状字典列表传递给 fig.update_layout() 的 shapes 属性,以高效地添加多个形状。

如何在 Plotly 中绘制一条垂直线?

您可以通过使用 type='line' 并将 yref='paper' 属性设为跨越整个图表高度,来绘制完整的垂直线。

可以将形状置于 Plotly 数据之后吗?

可以。将形状的 layer 属性设为 'below',即可将形状放在数据轨迹后面。

如何只向 Plotly 的一个子图添加形状?

您可以在形状定义中提供 xref 和 yref 参数,将形状添加到特定子图。

作者

Rajesh Kumar

我是一名数据科学内容写作者,热衷于创作与 AI/ML/DS 相关的内容。我也会探索新的 AI 工具并撰写相关文章。

主题