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()技术支持
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 areadict(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 eventdict(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()技术支持
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}})技术支持
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 inzip(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 inzip(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()技术支持
defcreate_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 stringsdefparse_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)ifisinstance(start_color,str)else start_color
end_rgb = parse_rgb(end_color)ifisinstance(end_color,str)else end_color
band_height =(y1 - y0)/ num_bands
for i inrange(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()技术支持
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()技术支持
Plotly 是创建交互式图表最强大且最受欢迎的 Python 库之一。用 Plotly 绘制基础图表并不复杂,但要实现真正有影响力的数据可视化,往往需要添加一些能引导读者注意力并提供重要背景的信息元素。这正是 Plotly 形状大显身手的地方。
形状是矩形、线条、圆等图形元素,您可以将其叠加到 Plotly 图形上,用于注释、突出显示并添加关键信息。它们是将标准图表提升为信息丰富、见解深刻且可发表质量可视化的关键。
图片来源:作者
在本文中,我们将从基础实现到高级自定义技术,全面介绍 plotly 形状。对于刚接触 Plotly 的读者,先熟悉其高级接口是很好的第一步,这门Python 中使用 Plotly 进行数据可视化入门课程可帮助您在深入形状等自定义内容前打好基础。
什么是 Plotly 形状?
Plotly 形状是绘制在图形上的矢量图,用于提供额外上下文或突出特定区域。这类注释有助于构建既美观又信息丰富的图表。
形状在数据可视化中的重要性
在数据可视化中,清晰至关重要。散点图或柱状图等图表呈现数据,而形状则帮助讲清数据背后的故事。它们主要有两大作用:
如果您想快速浏览最常见的数据可视化、使用时机及常见用例,请查看我们的数据可视化速查表。
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对象的方法。您先创建基础图(例如散点图或折线图),然后调用该方法将形状叠加其上。当您需要根据特定条件或数据值以编程方式添加形状时,此方法尤为有用。下面通过一个基础示例,在时间序列图上高亮某一特定区域。
输出:
当您理解坐标系统后,plotly 的
add_shape()功能会尤其强大。形状可以通过xref和yref参数引用不同的坐标系统。它们指定坐标框架:使用'x'/'y'以数据单位解释数值,或使用'paper'应用归一化的绘图区(0–1 从左下到右上覆盖完整宽/高)。下面按所示参数修改上述图表:输出:
自定义矩形与直线
矩形和直线是最常用于注释的形状。Plotly 提供了广泛的自定义选项来控制它们的外观。若需快速参考常见 Plotly 语法,Plotly Express 速查表非常有用。下面看看如何自定义这些形状。
矩形形状自定义
矩形由两个点(
x0、y0和x1、y1)定义。您可以分别设置填充与边框样式。输出:
直线形状自定义
对于跨越整个图形的水平或垂直线,您可以使用专用的 “add_hline” 和 “add_vline” 方法;若需更精细控制,可通过通用的 “add_shape” 方法添加。请看示例:
输出:
这些示例展示了如何轻松添加并美化基础的 Plotly 形状,使图表更具信息性。
高级配置与自定义
除了添加基础形状,Plotly 还提供了强大的工具来管理多个形状并控制其视觉层级。这些高级特性对于创建复杂、分层且动态的可视化至关重要。下面看看一些配置与自定义的方法。
使用 plotly.update_layout 进行动态更新
虽然
add_shape()非常适合逐个添加形状,但当形状是以编程方式生成时,update_layout()对管理一组形状更高效。您可以将形状字典列表直接传递给update_layout()中的shapes参数,而无需为每个形状调用函数。下面是该方法的示例:
输出:
这种方式对动态应用尤为强大,例如在 Dash 仪表板中,形状需要根据用户输入变化。您可以生成新的形状对象列表,并用一次干净的布局更新来替换。这种方法能使代码更有条理,并且在一次性添加大量形状时通常更高效。
图层与 z-index 控制
向图表添加形状时,控制它们是在数据之上还是之下非常重要。Plotly 通过 layer 属性来管理。虽然它不像 CSS 中的精细
z-index,但提供了必要的视觉堆叠控制。layer属性可设置为以下两种值:'above':形状绘制在数据轨迹之上。默认设置,适用于必须清晰可见的注释。'below':形状绘制在数据轨迹与网格线之下。适合用于背景着色或高亮区域而不遮挡数据点。在同一层内,shapes 列表中形状的顺序也很重要:列表中后定义的形状会绘制在先前定义的形状之上。
下面通过示例演示图层效果:
输出:
如您所见,粉色矩形位于标记点之后,而绿色圆形覆盖在数据点之上。
掌握这些布局与图层技巧,是用 Plotly 创建更高级、可交互可视化的关键。对于使用 R 的读者,类似概念同样适用,可参见R 中使用 Plotly 的交互式数据可视化进阶。
交互式形状编辑
Plotly 的强大之处在于其交互性。您可以让 Plotly 形状可编辑,使用户可在图上直接拖拽、调整大小并旋转。通过在形状定义中设置
editable=True即可启用此功能。下面示例展示了如何实现:输出:
交互式形状对探索性数据分析非常有用。例如,用户可以在 Dash 应用中拖动矩形覆盖不同时间段,实时查看对应的汇总统计值;或者通过调整圆的大小来选择不同的点簇以便进一步分析。
虽然功能强大,但在复杂的 Web 应用中大量使用可编辑形状可能影响性能。不过,若要构建真正动态、以用户为中心的工具,它们不可或缺。
探索交互性是现代数据可视化的重要组成部分,该主题在R 中使用 Plotly 进行交互式数据可视化等课程中也有深入讲解,与 Python 版本原理相通。
将 Plotly 与其他库集成
虽然 Plotly 内置形状功能强大,但有时您需要创建高度复杂或自定义的几何图形。通过与 Shapely 等专业库集成,您可以定义复杂多边形,并将其作为自定义 Plotly 形状添加到可视化中。
使用 Shapely 创建高级几何形状
Shapely 是一个强大的 Python 库,用于处理与分析平面几何对象。它是计算几何的首选工具,常用于地理空间分析。您可以用它创建复杂形状,如两个重叠圆的并集或带有孔洞的多边形,然后在 Plotly 中进行可视化。
该过程分为两步:
type: 'path'渲染。SVG 路径字符串是一种绘图迷你语言。它使用诸如
M(moveto)设置起点,L(lineto)绘制到新点的线段,Z闭合路径等命令。下面看看如何创建一个带镂空的多边形,并将其添加到 Plotly 图形中。
输出:
该技巧在地理空间应用中十分有用,例如绘制自定义销售区域,或在科研场景中高亮不规则兴趣区域。
了解不同类型数据图的创建方式,以及如何用这类工具增强图表,是每位数据从业者的基础技能。您可在本指南中进一步了解如何在 Python 中创建这些图表。
样式与美学自定义
Plotly 形状的默认外观是实用的,但为了打造精致、专业的可视化,自定义样式很重要。对颜色、不透明度和填充的巧妙运用能显著提升可读性与美观度。
颜色、不透明度与图案填充
Plotly 为形状外观提供了精细控制,使您能够与图表的配色与设计语言保持一致。
若需精准控制颜色与透明度,强烈建议使用 RGBA(红、绿、蓝、透明度)颜色规范。
a(alpha)通道控制不透明度,1为完全不透明,0为完全透明。这对于创建不干扰的高亮区域尤为关键,使形状在添加上下文的同时不完全遮挡下方数据。您可以用字符串形式提供 RGBA 值,如
'rgba(255, 99, 71, 0.5)'。请看示例:输出:
图案填充的模拟策略
虽然 Plotly 原生不支持图案填充,但数据从业者可以通过巧妙技巧模拟复杂填充图案。例如,我们可以通过函数在图中创建图案,如下所示:
渐变效果的模拟
创建类似渐变的效果需要对多个具有不同不透明度的形状进行策略性分层。我们可以沿用创建图案时的策略来实现,如下所示:
输出:
排错与优化
尽管添加 Plotly 形状通常很直接,但在复杂图表中您可能会遇到对齐或性能问题。了解这些常见陷阱及其应对方法将为您节省大量时间与精力。
形状对齐的常见问题
最常见的挑战之一是让形状准确出现在您期望的位置。本应横跨整个图宽的直线可能会短一截,或矩形与网格线未如预期对齐。这些问题几乎总是源于坐标引用不正确。
Plotly 用两种坐标系统来放置形状:
xref: 'x', yref: 'y'):默认选项。形状位置与 x、y 轴上的数值绑定。例如,x0=50表示位于 x 轴 50 处。xref: 'paper', yref: 'paper'):位置相对于绘图区本身,0 为起点(左/下边缘),1 为终点(右/上边缘)。该系统独立于数据值或轴范围。问题: 您想在
y=10处绘制一条横跨整个图的水平线。如果用数据坐标定义x0和x1,它只会跨越当前的轴范围。若用户缩放或平移,直线不会延伸到新的边界。解决方案: 若要让形状跨越绘图区的完整宽度或高度,请在要跨越的轴上使用
'paper'坐标。输出:
在涉及用户交互(如缩放、平移)时,请务必再次检查
xref与yref属性,确保形状按预期表现。性能注意事项
向图中添加少量形状时,性能影响可以忽略不计。但若添加数百或数千个形状,会显著拖慢渲染与交互。每个形状都是添加到网页 DOM 的独立 SVG 元素,过多的 DOM 元素会给浏览器带来压力。
以下是优化性能的策略:
go.Heatmap)更高效地表示,将信息作为单个轨迹而非数千个形状对象。update_layout进行批量添加: 如前所述,通过fig.update_layout(shapes=...)添加形状列表比在循环中多次调用fig.add_shape()更高效。go.Scattergl)来提升复杂图表的整体性能。这样可将数据渲染交给 GPU 处理,从而释放 CPU,更顺畅地处理 SVG 形状。当您同时拥有海量数据点和适量形状时尤其有用。在大多数用例中,关键是注意您创建的独立形状元素数量。在循环中添加数千个 Plotly 形状之前,不妨停下来思考是否存在更高性能的可视化策略。
结语
熟练掌握 Plotly 形状,能将图表从简单的数据呈现,升华为引人入胜、语境丰富的故事。我们从绘制定基础的直线与矩形,到分层复杂、可交互的几何图形,都一一探讨。
通过应用这些技巧,您可以引导受众的关注点,突出关键洞见,并构建更直观、沟通清晰且有冲击力的可视化。
准备好应用这些技能了吗?立即开始构建更强大的可视化,探索 Python 中使用 Plotly 进行数据可视化入门 课程,并将您的所学付诸实践。