使用 Plotly 简化 Python 中的数据可视化

Plotly 是一个数据绘图库,具有简洁的界面,旨在让您构建自己的 API。
114 位读者喜欢这篇文章。
Open source voice control

Pixabay。由 Opensource.com 修改。CC BY-SA 4.0。

Plotly 是一个绘图生态系统,允许您在 Python 以及 JavaScript 和 R 中制作图表。在本系列文章中,我将重点介绍使用 Python 库进行绘图

Plotly 有三个不同的 Python API,让您可以选择如何驱动它

我将通过在每个 API 中制作相同的图表来探索这些 API:英国历史选举结果的分组条形图。 

在我们继续之前,请注意您可能需要调整您的 Python 环境才能运行此代码,包括以下内容。 

  • 运行最新版本的 Python(LinuxMac 和 Windows 的说明)
  • 验证您正在运行的 Python 版本与这些库兼容

数据在线可用,可以使用 pandas 导入

import pandas as pd
df = pd.read_csv('https://anvil.works/blog/img/plotting-in-python/uk-election-results.csv') 

现在我们准备开始了。

使用 Graph Objects 制作图表

Plotly 的面向对象 API 名为 graph_objects。它有点类似于 Matplotlib 的面向对象 API

要创建多条形图,您可以构建一个包含四个条形图的图形对象

# Import Plotly and our data
import plotly.graph_objects as go

# Get a convenient list of x-values
years = df['year']
x = list(range(len(years)))

# Specify the plots
bar_plots = [
    go.Bar(x=x, y=df['conservative'], name='Conservative', marker=go.bar.Marker(color='#0343df')),
    go.Bar(x=x, y=df['labour'], name='Labour', marker=go.bar.Marker(color='#e50000')),
    go.Bar(x=x, y=df['liberal'], name='Liberal', marker=go.bar.Marker(color='#ffff14')),
    go.Bar(x=x, y=df['others'], name='Others', marker=go.bar.Marker(color='#929591')),
]
    
# Specify the layout
layout = go.Layout(
    title=go.layout.Title(text="Election results", x=0.5),
    yaxis_title="Seats",
    xaxis_tickmode="array",
    xaxis_tickvals=list(range(27)),
    xaxis_ticktext=tuple(df['year'].values),
)
        
# Make the multi-bar plot
fig = go.Figure(data=bar_plots, layout=layout)

# Tell Plotly to render it
fig.show()

与 Matplotlib 不同,无需手动计算条形的 x 轴位置;Plotly 会为您处理。

这是最终图表

A multi-bar plot made using Graph Objects

使用 Graph Objects 制作的多条形图。 (© 2019 Anvil)

使用 Python 数据结构制作图表

您还可以使用基本的 Python 数据结构来指定您的图表,其结构与面向对象的 API 相同。这直接对应于 Plotly JavaScript 实现的 JSON API。

    # Specify the plots
    fig = {
        'data': [
            {'type': 'bar', 'x': x, 'y': df['conservative'], 'name': 'Conservative', 'marker': {'color': '#0343df'}},
            {'type': 'bar', 'x': x, 'y': df['labour'], 'name': 'Labour', 'marker': {'color': '#e50000'}},
            {'type': 'bar', 'x': x, 'y': df['liberal'], 'name': 'Liberal', 'marker': {'color': '#ffff14'}},
            {'type': 'bar', 'x': x, 'y': df['others'], 'name': 'Others', 'marker': {'color': '#929591'}},
        ],
        'layout': {
            'title': {'text': 'Election results', 'x': 0.5},
            'yaxis': {'title': 'Seats'},
            'xaxis': {
                'tickmode': 'array',
                'tickvals': list(range(27)),
                'ticktext': tuple(df['year'].values),
            }
        }
    }

    # Tell Plotly to render it
    pio.show(fig)

最终图表看起来与之前的图表完全相同

A multi-bar plot made using JSON-like data structures

使用类似 JSON 的数据结构制作的多条形图。 (© 2019 Anvil)

使用 Plotly Express 制作图表

Plotly Express 是一个包装了 Graph Objects 的高级 API。

您可以使用(几乎)一行代码在 Plotly Express 中制作多条形图

    # Import Plotly and our data
    import plotly.express as px

    # Define the colourmap to get custom bar colours
    cmap = {
        'Conservative': '#0343df',
        'Labour': '#e50000',
        'Liberal': '#ffff14',
        'Others': '#929591',
    }
    
    # Make the plot!
    fig = px.bar(df, x="year", y="seats", color="party", barmode="group", color_discrete_map=cmap)

这利用了长格式数据中的数据,也称为“整洁数据”。列是年份、政党和席位,而不是按政党拆分。这非常类似于在 Seaborn 中制作多条形图。

>> print(long)
     year         party  seats
0    1922  Conservative    344
1    1923  Conservative    258
2    1924  Conservative    412
3    1929  Conservative    260
4    1931  Conservative    470
..    ...           ...    ...
103  2005        Others     30
104  2010        Others     29
105  2015        Others     80
106  2017        Others     59
107  2019        Others     72

[108 rows x 3 columns]

您可以访问底层的 Graph Objects API 进行详细调整。添加标题和 y 轴标签

    # Use the Graph Objects API to tweak our plot
    import plotly.graph_objects as go
    fig.layout = go.Layout(
        title=go.layout.Title(text="Election results", x=0.5),
        yaxis_title="Seats",
    )

最后,要求 Plotly 向您展示它

    # Tell Plotly to render it
    fig.show()

这会在未使用的端口上运行一个临时 Web 服务器,并打开默认的 Web 浏览器以查看图表(Web 服务器会立即被拆除)。

遗憾的是,结果并不完美。x 轴被视为整数,因此组之间距离很远且很小。这使得很难看到趋势。

A multi-bar plot made using Plotly Express

使用 Plotly Express 制作的多条形图 (© 2019 Anvil

您可以尝试通过将 x 值转换为字符串来鼓励 Plotly Express 将 x 值视为字符串。您可能希望这会导致它们以均匀的间距和词法顺序绘制。不幸的是,您仍然会得到它们以数值方式间隔排列。设置 xaxis_tickvals 也像在 graph_objects 中一样不起作用。

Seaborn 中类似的示例不同,在这种情况下,抽象似乎没有提供足够的逃生舱口来完全按照您想要的方式提供东西。但也许您可以编写自己的 API?

构建您自己的 Plotly API

对 Plotly 的某些功能不满意?构建您自己的 Plotly API!

从本质上讲,Plotly 是一个 JavaScript 库,它使用 D3stack.gl 制作图表。JavaScript 库有一个接口,可以消费指定图表的 JSON 结构。因此,您只需要输出 JavaScript 库喜欢消费的 JSON 结构。

Anvil 做了这件事,创建了一个完全在浏览器中工作的 Python Plotly API。

Plotly uses a JavaScript library to create plots, driven by libraries in other languages via JSON

Plotly 使用 JavaScript 库创建图表,通过 JSON 由其他语言的库驱动 (© 2019 Anvil)

在 Anvil 版本中,您可以使用 Graph Objects API 和上面解释的 Python 数据结构方法。您运行完全相同的命令,将数据和布局分配给 Anvil 应用程序中的 Plot 组件

这是用 Anvil 的客户端 Python API 编写的多条形图

# Import Anvil libraries
from ._anvil_designer import EntrypointTemplate
from anvil import *
import anvil.server

# Import client-side Plotly
import plotly.graph_objs as go


# This is an Anvil Form
class Entrypoint(EntrypointTemplate):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)

    # Fetch the data from the server
    data = anvil.server.call('get_election_data')
    
    #  Get a convenient list of x-values
    years = data['year']
    x = list(range(len(years)))

    # Specify the plots
    bar_plots = [
      go.Bar(x=x, y=data['conservative'], name='Conservative', marker=go.Marker(color='#0343df')),
      go.Bar(x=x, y=data['labour'], name='Labour', marker=go.Marker(color='#e50000')),
      go.Bar(x=x, y=data['liberal'], name='Liberal', marker=go.Marker(color='#ffff14')),
      go.Bar(x=x, y=data['others'], name='Others', marker=go.Marker(color='#929591')),
    ]
    # Specify the layout
    layout = {
      'title': 'Election results',
      'yaxis': {'title': 'Seats'},
      'xaxis': {
        'tickmode': 'array',
        'tickvals': list(range(27)),
        'ticktext': data['year'],
      },
    }

    # Make the multi-bar plot
    self.plot_1.data = bar_plots
    self.plot_1.layout = layout

绘图逻辑与上面相同,但它完全在 Web 浏览器中运行——图表由用户机器上的 Plotly JavaScript 库创建!与本系列中的所有其他 Python 绘图库相比,这是一个很大的优势。所有其他 Python 库都需要在服务器上运行。

这是在 Anvil 应用程序中运行的交互式 Plotly 图表

The election plot on the web using Anvil's client-side-Python Plotly library

使用 Anvil 的 客户端 Python Plotly 库在 Web 上绘制的选举图表 (© 2019 Anvil)

您可以将此示例复制为 Anvil 应用程序(注意:Anvil 需要注册才能使用)。

在前端运行 Plotly 还有另一个优势:它为自定义交互行为开辟了更多选项。

自定义 Plotly 中的交互性

Plotly 图表不仅是动态的;您还可以自定义其交互行为。例如,您可以使用每个条形图中的 hovertemplate 自定义工具提示的格式

    go.Bar(
      x=x,
      y=df['others'],
      name='others',
      marker=go.bar.Marker(color='#929591'),
      hovertemplate='Seats: <b>%{y}</b>',
    ),

这是当您将其应用于每个条形图时得到的结果

A multi-bar plot with custom tool-tips

带有自定义工具提示的多条形图 (© 2019 Anvil)

这很有用,但如果您可以在某些事件发生时执行您想要的任何代码,那就更好了——例如,当用户悬停在条形图上并且您想要显示有关相关选举的信息框时。在 Anvil 的 Plotly 库中,您可以将事件处理程序绑定到悬停等事件,这使得那种复杂的交互性成为可能!

A multi-bar plot with a hover event handler

带有 hover 事件处理程序的多条形图 (© 2019 Anvil)

您可以通过将方法绑定到图表的悬停事件来实现此目的

  def plot_1_hover(self, points, **event_args):
    """This method is called when a data point is hovered."""
    i = points[0]['point_number']
    self.label_year.text = self.data['year'][i]
    self.label_con.text = self.data['conservative'][i]
    self.label_lab.text = self.data['labour'][i]
    self.label_lib.text = self.data['liberal'][i]
    self.label_oth.text = self.data['others'][i]
    url = f"https://en.wikipedia.org/wiki/{self.data['year'][i]}_United_Kingdom_general_election"
    self.link_more_info.text = url
    self.link_more_info.url = url

这是一个相当极端的交互级别,从开发人员的角度来看,也是一个极端的定制级别。这一切都归功于 Plotly 的架构——Plotly 具有一个简洁的界面,该界面明确设计为允许您构建自己的 API。如果能在任何地方看到这种出色的设计,那将非常有帮助!

使用 Bokeh 自定义交互性

您已经了解了 Plotly 如何使用 JavaScript 创建动态图表,并且可以使用 Anvil 的客户端 Python 代码在浏览器中实时编辑它们。

Bokeh 是另一个 Python 绘图库,它输出一个 HTML 文档,您可以将其嵌入到 Web 应用程序中,并获得与 Plotly 提供的动态功能类似的功能。(如果您想知道如何发音,那是“BOE-kay”。)

享受自定义图表,并在下面的评论中分享技巧和窍门。


本文基于 Anvil 博客上的“How to make plots using Plotly”,并已获得许可重用。

接下来阅读
User profile image.
Shaun 开始认真编程,通过在世界上最大的激光系统中模拟燃烧的聚变等离子体。他爱上了 Python 作为数据分析工具,并且从未回头。现在他想把一切都变成 Python。

贡献者

评论已关闭。

Creative Commons License本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.