器→工具, 工具软件, 数据, 术→技巧

Python数据可视化工具Plotly

钱魏Way · · 19 次浏览

Plotly是一个流行的开源图形库,用于创建高质量的交互式数据可视化。它支持多种编程语言,包括Python、R、JavaScript等。Plotly的Python库尤其受欢迎,因为它允许数据科学家和分析师利用Python的强大功能来创建多样化的图表和仪表板。

以下是Plotly的一些核心特点:

  • 交互性。Plotly生成的图表是完全交互式的。用户可以缩放、平移、悬停在数据点上以查看详细信息等,而无需任何额外的编码工作。
  • 多样的图表类型。Plotly提供了广泛的图表类型,包括但不限于:
    • 基本的2D图表,如折线图、柱状图、散点图、饼图;
    • 统计图表,如直方图、箱型图、小提琴图;
    • 科研图表,如等高线图、热力图、3D图表;
    • 地图和地理图表,如散点地图、气泡地图、线图;
    • 金融图表,如K线图、柱形图。
  • 高度可定制和扩展性。使用Plotly,可以高度定制图表的外观和风格,包括颜色、布局和字体等。此外,它可以很容易地与Web框架集成,例如Flask和Django,以便于在网络环境中部署。

Plotly图表基础组件

在使用Plotly创建图表时,了解和理解其基本组件是非常重要的。这些组件有助于传达数据的信息,并使图表更加易懂和美观。以下是Plotly中几个基本图表组件的概述:

  • 坐标轴(Axes)。坐标轴是图表中用来表示数据维度的直线。在二维图表中通常有两个坐标轴:横轴(X轴)和纵轴(Y轴)。在三维图表中还会有一个额外的轴(Z轴)。坐标轴上通常带有刻度(ticks)和刻度标签(tick labels),用于说明数据的量度。在Plotly中,你可以自定义坐标轴的范围、类型(如线性或对数)、标题、以及其它样式设置。
  • 图例(Legend)。图例是用来解释图表中不同数据系列的方框或标记。它通常出现在图表的侧边或角落处。图例帮助观众区分图表中的不同数据系列或分类。在Plotly中,图例的位置、字体、背景色等都是可定制的。
  • 标题(Title)。标题通常位于图表的顶部,用来提供图表的主要信息和上下文。一个好的标题应该简洁明了,能够清楚地描绘出图表的主题。在Plotly中,你可以自定义标题的字体、大小、颜色等。
  • 标签(Labels)。标签通常指的是附加在数据点、坐标轴刻度、图例等元素上的文本,用来提供额外信息。例如,坐标轴标签会告诉我们轴上的数据代表什么;数据点的标签可能会显示具体的数值或其他注释。Plotly允许你自定义这些标签的样式和显示逻辑。
  • 注释(Annotations)。注释是图表中用来突出显示或解释特定部分的文本。你可以用注释来标记图表中的重要点、趋势线或异常值。Plotly中的注释可以自定义文本、箭头样式以及位置等。
  • 网格线(Gridlines)。网格线是图表背景的水平或垂直线条,用来帮助观众准确阅读数据点的位置。网格线可以根据需要添加,也可以自定义其样式。
  • 工具提示(Tooltips)。工具提示是当用户将鼠标悬停在数据点或图表元素上时显示的小文本框,用来提供更多关于该点的信息,如其确切的数值、描述或其他数据。Plotly的工具提示是交互式的,可以定制内容和样式。
  • 轨迹(Trace)。是指图表中的单个数据系列或数据对象。每一个轨迹代表图表中的一组数据及其对应的可视化类型,如柱状图、折线图、散点图、饼图等。换句话说,轨迹是构成图表的基本单元。

了解和运用这些基本组件,你将能够创建更为清晰和专业的Plotly图表,从而有效地传达数据的故事。

plotly.express和plotly.graph_objects的区别

Plotly提供了不同级别的API以适应不同的使用需求和用户熟练程度。plotly.express 和 plotly.graph_objects 是其两个核心模块,它们在创建图表时有不同的用途和特点:

Plotly Express (plotly.express)

  • express 是Plotly中的高级封装接口,它提供了一个更简单、更直观的语法来创建图表。它旨在易于使用,允许用户快速制作标准图表,并且通常只需要一行代码就能完成。Plotly Express的特点包括:
  • 简洁的API:适合快速绘图和数据探索。
  • 内置的样式:默认的样式和布局已经预设得比较好,无需进行大量定制。
  • 一行代码生成图表:整洁的函数调用,传入数据和参数即可生成图表。
  • 有限的自定义能力:虽然一些简单的自定义是可能的,但不适合创建非常复杂或高度定制的图表。

Plotly Graph Objects (plotly.graph_objects)

plotly.graph_objects 是Plotly中的低级接口,它提供了更多的控制和定制选项。使用plotly.graph_objects,用户可以细致地控制图表中的每个元素。这个模块的特点包括:

  • 细粒度控制:允许用户对图表的每个组成部分进行精确控制。
  • 复杂图表的创建:用于构建复杂和高度定制的图表。
  • 详细的层级结构:通过创建图表的各种对象和属性来详细定义图表。
  • 灵活性和扩展性:在创建不规则或非标准图表时,提供了更大的灵活性。

简而言之,如果你需要快速制作一个图表,并且不需要过多的定制,plotly.express 是一个很好的选择。如果你需要创建一个高度定制化的图表,并且想要对图表的每一个小细节都保持控制,那么使用plotly.graph_objects 会更合适。

在实际应用中,你也可以将这两个模块结合使用。例如,你可以用plotly.express 快速生成一个图表,并通过将其转换为plotly.graph_objects.Figure 对象来进行进一步的定制。这样,你就可以利用plotly.express 的简洁性,并在需要时享受plotly.graph_objects 的灵活性。

Plot.ly支持的各类图形

基本的2D图表:

统计图表:

科研图表:

地图和地理图表:

金融图表,如K线图、柱形图:

生物数据图表:

3D图表:

布局和样式

在Plotly中,您可以通过许多方法来调整图表的布局和样式,以便精确地控制其外观。以下是一些基本示例:

调整布局

布局是指图表的全局属性,如标题、图例、坐标轴等。你可以通过修改plotly.graph_objects.Figure对象的layout属性来调整它们。例如:

import plotly.graph_objects as go

fig = go.Figure(
    data=[go.Bar(y=[2, 1, 3])], 
    layout_title_text="A Figure Displayed with fig.show()"
)
fig.show()

调整样式

样式是指颜色、字体、线型、填充等属性。你可以通过修改图形对象的样式属性来调整它们。例如:

import plotly.graph_objects as go

trace0 = go.Scatter(
    x=[1, 2, 3, 4],
    y=[10, 15, 13, 17],
    mode='lines',
    line=dict(width=2, color='blue')
)

fig = go.Figure(data=[trace0])
fig.show()

使用update_layout和update_traces方法

update_layout和update_traces方法是一种方便的方式来批量更新布局和样式属性。例如:

import plotly.graph_objects as go

fig = go.Figure(
    data=[go.Bar(y=[2, 1, 3])], 
    layout_title_text="A Figure Displayed"
)
fig.update_layout(
    autosize=False,
    width=500,
    height=500,
    yaxis=dict(range=[0, 3]),
)
fig.update_traces(marker_color='cyan')

fig.show()

使用模板

Plotly还提供了预定义的图表模板,使得你可以快速调整多个图表的布局和样式。例如:

import plotly.graph_objects as go

fig = go.Figure(
    data=[go.Bar(y=[2, 1, 3])], 
    layout_title_text="A Figure Displayed with template"
)
fig.update_layout(template='plotly_dark')

fig.show()

Plot.ly颜色支持

内置颜色选项

  • RGB或RGBA值:可以使用像CSS那样的RGB或RGBA值来指定颜色,例如rgb(255, 0, 0) 代表红色,rgba(255, 0, 0, 0.5) 代表半透明的红色。
  • 十六进制值:可以使用十六进制颜色代码来定义颜色,例如#FF0000 代表红色。
  • 颜色名:Plotly支持所有的CSS颜色关键字,例如red, blue, green。
  • Plotly颜色缩放:Plotly还内置了一系列的颜色缩放和连续颜色方案,它们在渲染热图、地图和其他连续数据可视化时非常有用。

CSS颜色关键字:

Plotly颜色缩放

Plotly提供了一系列预先定义的颜色缩放器和连续颜色方案,可以用于渲染热图、填充等等。它们可以用于表示不同的数值范围,并且可以使得图表更加直观和易于理解。

以下是一些内置的颜色缩放字符串,可以直接在颜色相关的属性中使用:

  • Sequential(递进)(默认为 “Plasma”):”Greys”, “YlGnBu”, “Greens”, “YlOrRd”, “Bluered”, “RdBu”, “Reds”, “Blues”, “Picnic”, “Rainbow”, “Portland”, “Jet”, “Hot”, “Blackbody”, “Earth”, “Electric”, “Viridis”, “Cividis” 等。
  • Diverging(发散):”RdBu”, “RdYlBu”, “RdYlGn”, “Spectral” 等。
  • Cyclic(循环):”Twilight”, “Twilight_shifted”, “HSV”。

可以通过在 “colorscale” 属性中指定这些字符串来使用相应的颜色缩放。例如:

import plotly.graph_objects as go

fig = go.Figure(data=go.Heatmap(
    z=[[1, 20, 30],
       [20, 1, 60],
       [30, 60, 1]],
    colorscale='Viridis'))

fig.show()

此外,你可以自定义颜色缩放,只需创建一个由 [0-1, ‘color’] 对组成的列表。例如,colorscale = [[0, ‘red’], [1, ‘green’]] 将创建一个从红色到绿色的颜色缩放。

查看内置色阶方法

import plotly.express as px

fig = px.colors.sequential.swatches_continuous()
# fig = px.colors.diverging.swatches_continuous()
# fig = px.colors.cyclical.swatches_continuous()
fig.show()

交互式功能

在Plotly中,交互功能是内建的,许多交互操作如缩放、平移、悬停提示等不需要额外的设置即可使用。但是,你也可以进一步定制这些交互式功能,或者添加新的交互操作。以下是一些常见的定制交互功能的方法:

配置悬停提示(Hover Info)

可以通过设置轨迹的 hoverinfo 属性来定制悬停提示显示的信息:

import plotly.graph_objects as go

trace = go.Scatter(
    x=[1, 2, 3],
    y=[4, 5, 6],
    hoverinfo='x+y'  # 只显示x和y的值
)

fig = go.Figure(data=[trace])
fig.show()

定制悬停提示模板(Hover Template)

可以使用 hovertemplate 属性来提供自定义的悬停文本模板:

trace = go.Scatter(
    x=[1, 2, 3],
    y=[4, 5, 6],
    hovertemplate='<i>Price</i>: $%{y:.2f}'+'<br><b>X</b>: %{x}<br>'
)

fig = go.Figure(data=[trace])
fig.show()

添加滑块和选择按钮

可以为图表添加滑块和选择按钮来控制图表显示的数据:

fig = go.Figure()
fig.add_trace(go.Scatter(x=[1, 2, 3], y=[4, 5, 6]))
fig.update_layout(
    sliders=[
        {
            'currentvalue': {'visible': True},
            'steps': [
                {'method': 'update', 'args': [{'visible': [True, False]}, {'title': 'Slide 1'}]},
                {'method': 'update', 'args': [{'visible': [False, True]}, {'title': 'Slide 2'}]}
            ],
        }
    ]
)
fig.show()

配置布局以启用和禁用某些交互

可以通过调整图表布局中的配置来启用或禁用某些交互式功能:

fig = go.Figure(data=go.Scatter(x=[1, 2, 3], y=[4, 5, 6]))
fig.update_layout(
    dragmode='pan',  # 更改拖动模式为平移
    clickmode='event+select'  # 点击不仅触发事件,也可以选择数据点
)
fig.show()

请注意,对于某些交互功能,如点击事件、滑块、选择按钮等,你可能需要使用 Dash 和其他相关库来实现更高级的交互式操作。Dash使得可以为你的Plotly图表添加回调函数,从而实现更复杂的交互模式。

plot.ly与动画

Plotly支持在图表中添加动画效果,这可以用来显示数据随时间或其他变量的变化。为了创建一个动画效果,你需要指定一个动画帧(frame)序列,每个帧代表图表的一个特定状态,以及一个动画的转换(transition)指令,来指定如何从一个帧转换到另一个帧。

以下是一个在Python中使用Plotly创建一个简单的动画效果的示例:

import plotly.graph_objs as go
from plotly.subplots import make_subplots

# 创建一个简单的散点图
fig = make_subplots(rows=1, cols=1)

# 添加初始数据
fig.add_trace(go.Scatter(x=[0], y=[0], mode='markers'))

# 创建和添加帧
frames = []
for i in range(1, 11):  # 假设我们有10个时间点
    frame = go.Frame(
        data=[go.Scatter(x=[i], y=[i**2])],  # 假设y随时间呈平方增长
        name=str(i)
    )
    frames.append(frame)

fig.frames = frames

# 添加滑动条
sliders = [{
    'steps': [
        {'args': [[frame.name], {'frame': {'duration': 300, 'redraw': False},
                                 'mode': 'immediate',
                                 'transition': {'duration': 300}}],
         'label': frame.name,
         'method': 'animate'}
        for frame in frames
    ],
    'transition': {'duration': 300},
    'x': 0,
    'y': 0,
    'currentvalue': {'font': {'size': 12}, 'prefix': 'Time: ', 'visible': True, 'xanchor': 'center'},
    'len': 1.0
}]

fig.update_layout(
    sliders=sliders,
    updatemenus=[{
        'buttons': [
            {
                'args': [None, {'frame': {'duration': 500, 'redraw': False}, 'fromcurrent': True}],
                'label': 'Play',
                'method': 'animate'
            },
            {
                'args': [[None], {'frame': {'duration': 0, 'redraw': False}, 'mode': 'immediate', 'transition': {'duration': 0}}],
                'label': 'Pause',
                'method': 'animate'
            }
        ],
        'direction': 'left',
        'pad': {'r': 10, 't': 87},
        'showactive': False,
        'type': 'buttons',
        'x': 0.1,
        'xanchor': 'right',
        'y': 0,
        'yanchor': 'top'
    }]
)

# 添加动画控制按钮
fig.update_layout(
    title='Animated Plot',
    xaxis=dict(range=[0, 10], autorange=False),
    yaxis=dict(range=[0, 100], autorange=False),
    showlegend=False
)

# 显示结果
fig.show()

plot.ly与网页开发

plot.ly与Dash

Dash是由Plotly开发的基于Python的框架,专门用于构建数据可视化应用。

创建一个新的Python脚本,例如 app.py,并写下你的Dash应用的基本结构:

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go

app = dash.Dash(__name__)

# 定义应用程序的布局
app.layout = html.Div([
    html.H1("Hello Dash"),
    html.Div("Dash: A web application framework for Python."),

    # 创建一个Plotly图表并添加到Dash应用中
    dcc.Graph(
        id='example-graph',
        figure=go.Figure(
            data=[
                go.Bar(x=['A', 'B', 'C'], y=[1, 3, 2])
            ],
            layout_title_text="A Simple Plotly Bar Chart"
        )
    )
])

if __name__ == '__main__':
    app.run_server(debug=True)

plot.ly与Flask

Plotly图表可以很容易地集成到Flask应用程序中。

创建一个新的Python脚本,比如 app.py,并写下你的Flask应用的基本结构:

from flask import Flask, render_template
import plotly.graph_objs as go
import plotly.io as pio

app = Flask(__name__)

@app.route('/')
def index():
    # 创建Plotly图表
    fig = go.Figure(
        data=[go.Bar(x=['A', 'B', 'C'], y=[1, 3, 2])],
        layout_title_text="A Simple Plotly Bar Chart"
    )
    
    # 将图表转换为HTML字符串
    plot_html = pio.to_html(fig, full_html=False)
    
    # 渲染模板并传递图表的HTML字符串
    return render_template('index.html', plot_html=plot_html)

if __name__ == '__main__':
    app.run(debug=True)

接下来,创建一个HTML模板文件 index.html。这个文件应该放在Flask应用的 templates 目录中:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Plotly with Flask</title>
</head>
<body>
    <h1>My Plotly Chart</h1>
    <!-- 嵌入Plotly图表 -->
    {{ plot_html|safe }}
</body>
</html>

在这个模板中,{{ plot_html|safe }} 会被替换为你的Plotly图表的HTML字符串。|safe 过滤器告诉Jinja2模板引擎信任这个HTML字符串,不要转义它。

plot.ly与Django

将Plotly图表嵌入到Django应用程序中与在Flask中的过程相似,但是它涉及Django的模板系统和视图。

在你的Django应用的 views.py 文件中创建一个视图,该视图生成Plotly图表的HTML代码并将其传递给模板。

from django.shortcuts import render
import plotly.graph_objs as go
import plotly.offline as opy

def my_plotly_view(request):
    fig = go.Figure(
        data=[go.Bar(x=['A', 'B', 'C'], y=[1, 3, 2])],
        layout_title_text="A Simple Plotly Bar Chart"
    )
    
    # 将Plotly图表转换成HTML代码
    div = opy.plot(fig, auto_open=False, output_type='div')
    
    # 传递给模板
    return render(request, 'myapp/plotly.html', context={'plot_div': div})

在这个视图中,我们创建了一个Plotly图表,然后使用Plotly的 offline.plot 函数生成图表的HTML代码,并将其嵌入到div变量中。此函数将auto_open设置为False以防止自动打开图表,并使用output_type=’div’来获取包含图表的HTML div元素。

在你的Django应用的 templates/myapp 目录中创建一个HTML模板文件 plotly.html:

<!DOCTYPE html>
<html>
<head>
    <title>Plotly Chart</title>
</head>
<body>
    <h1>Plotly Chart Example</h1>
    <!-- Plotly图表将被嵌入在这里 -->
    {{ plot_div|safe }}
</body>
</html>

使用Django模板语言,{{ plot_div|safe }} 将渲染包含Plotly图表的HTML代码。safe 过滤器是必要的,以便Django模板系统知道这段HTML代码是安全的,并且不应该被转义。

在你的Django应用的 urls.py 文件中,为你的视图设置URL模式:

from django.urls import path
from . import views

urlpatterns = [
    path('plotly/', views.my_plotly_view, name='plotly_view'),
]

确保该应用的 urls.py 被包含在项目的主 urls.py 中。

Plotly实战

绘制树形图

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

df = pd.read_excel("data/data.xlsx")
print(df.head())
fig = px.treemap(df, path=[px.Constant("所有"), '区域', '省份', '城市'], values='UV', color='转化率',
                 color_continuous_scale='RdBu',
                 color_continuous_midpoint=np.average(df['转化率'], weights=df['UV']))
fig.update_traces(textinfo='label+value')
fig.show()

绘制冰柱图

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

df = pd.read_excel("data/data.xlsx")
fig = px.icicle(df, path=[px.Constant("全部"), '一级分类', '二级分类'], values='UV',
                color='转化率', hover_data=['创单量'],
                color_continuous_scale='Greens',
                color_continuous_midpoint=np.average(df['转化率'], weights=df['UV']))
fig.update_traces(textinfo='label+percent root+percent parent')
fig.update_layout(width=640, height=600, margin=dict(t=50, l=25, r=25, b=25),
                  font=dict(family='Microsoft YaHei', size=14))
fig.show()

绘制分段线性函数

import numpy as np
import plotly.graph_objs as go
import pandas as pd

data = pd.read_excel("data/data.xlsx")
fig = go.Figure()
for category in data['category'].unique():
    data_new = data[(data['category'] == category)]
    x_values = []
    y_values = []
    for index, row in data_new.iterrows():
        x = np.linspace(row["min_x"], row["max_x"], 50)
        y = row["a"] * x + row["b"]
        x_values.extend(x)
        y_values.extend(y)
    fig.add_trace(go.Scatter(x=x_values, y=y_values, mode='lines', name=category))
fig.update_layout(width=800, height=600, title='定价拟合图', xaxis=dict(title='X'), yaxis=dict(title='Y'))
fig.show()

参考链接:

  • Plotly官方文档:https://plotly.com/python/
  • Plotly Express官方文档:https://plotly.com/python/plotly-express/
  • Plotly Dash文档:https://dash.plotly.com/
  • Plotly的GitHub主页:https://github.com/plotly/plotly.py

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注