Shaun Taylor-morgan 发布的文章

Altair 作为一个 Python 数据制图库,提供了优雅的接口及自有的绘图语言。

Python 中的 绘图库 提供了呈现数据的多种方式,可以满足你不同的偏好,如灵活性、布局、易用性,或者特殊的风格。

和其它方式相比,我发现,Altair 提供的是一种不同的解决方案,且总体而言使用起来更为简单。得益于声明式的绘图语言 Vega,Altair 拥有一套优雅的接口,可以直接定义要绘的图应该是什么样子,而不是通过写一大堆循环和条件判断去一步步构建。

绘图流程

我通过绘制同一个多柱状图比较了多个 Python 绘图库的差异。正式开始之前,你需要将你的 Python 环境调整到能运行下面代码的状态。具体就是:

  • 安装最新版的 Python( LinuxMacWindows 系统下的安装方法)
  • 确认该版本 Python 可以运行本教程所使用的库

演示用数据可从网络下载,并且可以用 pandas 直接导入:

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

准备开始吧。为了做个比较,先看下面这个用 Matplotlib 做的图:

 title=

使用 Matplotlib 需要 16 行代码,图柱的位置需要自己计算。

使用 Altair 绘制相似的图,代码如下:

    import altair as alt

    chart = alt.Chart(df).mark_bar().encode(
        x='party',
        y='seats',
        column='year',
        color='party',
    )

    chart.save('altair-elections.html')

真是简洁多了!与 Seaborn 类似,Altair 所用数据的组织形式是每个变量一列(即 数据列 )。这种方式下可以将每个变量映射到图的一个属性上 —— Altair 称之为“通道”。在上例中,我们期望每个 “党派” 在 x 轴上显示为一组图柱, 其 “席位” 显示在 y 轴,且将图柱按照 “年份” 分开为 “列”。我们还想根据 “党派” 给图柱使用不同的 “颜色”。用语言表述需求的话就是上面这个样子,而这也正是代码所要表述的!

现在把图画出来:

 title=

调整样式

这和我们期待的效果有点接近了。与 Matplotlib 方案相比,主要区别在于 Altair 方案中,每个 year 组显示的时候,内部之间都有个小空白 —— 这不是问题,这只是 Altair 多柱状图显示的一个特性。

所以说呢,还需要对显示样式再做一些改进。

非整形数据

两个不是整数的年份名称(Feb 1974Oct 1974)显示为 NaN 了。这可以通过将年份数值 year 转换为字符串来解决:

    df['year'] = df['year'].astype(str)

指定数据排序方法

还需要让 Altair 知道如何对数据进行排序。Altair 允许通过传给它一个 Column 对象,来设定 Column 通道的更多细节。现在让 Altair 按照数据在数据集中出现的顺序排列:

    chart = alt.Chart(df).mark_bar().encode(
        # ...
        column=alt.Column('year', sort=list(df['year']), title=None),
        # ...
    )

移除坐标轴标签

我们通过设置 title=None 移除了图顶的 "year" 标签。下面再一处每列数据的 "party" 标签:

    chart = alt.Chart(df).mark_bar().encode(
        x=alt.X('party', title=None),
        # ...
    )

指定颜色图

最后,我们还想自己指定图柱的颜色。Altair 允许建立 domain 中数值与 range 中颜色的映射来实现所需功能,太贴心了:

    cmap = {
        'Conservative': '#0343df',
        'Labour': '#e50000',
        'Liberal': '#ffff14',
        'Others': '#929591',
    }

    chart = alt.Chart(df).mark_bar().encode(
        # ...
        color=alt.Color('party', scale=alt.Scale(domain=list(cmap.keys()), range=list(cmap.values())))
    )

样式调整后的最终代码

应用上述样式调整之后,代码看起来不那么悦目了,但我们仍然是用声明的方式实现的,这正是 Altair 如此有弹性的原因所在。实现过程中,仍然是使用的异于显示数据的独立变量来分离图中不同属性的,而不是像在 Matplotlib 中那样直接对显示数据做复杂的操作。唯一的不同是,我们的变量名字封装在类似 alt.X() 的对象中,从而实现对显示效果的控制:

    import altair as alt
    from votes import long as df

    cmap = {
        'Conservative': '#0343df',
        'Labour': '#e50000',
        'Liberal': '#ffff14',
        'Others': '#929591',
    }

    df['year'] = df['year'].astype(str)

    # We're still assigning, e.g. 'party' to x, but now we've wrapped it
    # in alt.X in order to specify its styling
    chart = alt.Chart(df).mark_bar().encode(
        x=alt.X('party', title=None),
        y='seats',
        column=alt.Column('year', sort=list(df['year']), title=None),
        color=alt.Color('party', scale=alt.Scale(domain=list(cmap.keys()), range=list(cmap.values())))
    )

    chart.save('altair-elections.html')

现在与 Matplotlib 方案扯平了,代码数量达到了 16 行!

下图是使用我们的样式调整方案之后的 Altair 效果图:

 title=

结论

尽管在代码数量上,使用 Altair 绘图没有表现出优势,但它的声明式绘图语言使得对图层的操控更为精密,这是我比较欣赏的。Altair 还提供了清晰而独立的方式来调校显示样式,这使得 相关代码与绘图的代码块分离开来。Altair 确实是使用 Python 绘图时又一个很棒的工具库。

本文首次发布于 这里,蒙允编辑后再次发布。


via: https://opensource.com/article/20/6/altair-python

作者:Shaun Taylor-Morgan 选题:lujun9972 译者:silentdawn-zz 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

介绍一种更时尚的 Python 绘图库。

Python 有很多可以将数据可视化的库。其中一个互动性较强的库是 Pygal,我认为这个库适合喜欢漂亮事物的人。它可以生成用户可以与之交互的漂亮的 SVG(可缩放矢量图形)文件。SVG 是交互式图形的标准格式,仅使用几行 Python 就可以带来丰富的用户体验。

使用 Pygal 进行时尚的 Python 绘图

在本文中,我们要重新创建多柱状图,用来表示 1966 年至 2020 年英国大选的结果:

 title=

在继续之前,请注意你可能需要调整 Python 环境以使此代码运行,包括:

  • 运行最新版本的 Python(LinuxMacWindows 的说明)
  • 确认你运行的是与这些库兼容的 Python 版本

数据可在线获得,并可使用 pandas 导入:

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

现在我们可以继续进行了。。数据如下所示:

        year  conservative  labour  liberal  others
0       1966           253     364       12       1
1       1970           330     287        6       7
2   Feb 1974           297     301       14      18
..       ...           ...     ...      ...     ...
12      2015           330     232        8      80
13      2017           317     262       12      59
14      2019           365     202       11      72

在 Pygal 中进行绘制会以一种易于阅读的方式显示。首先,我们以一种简化柱状图定义的方式定义样式对象。然后我们将自定义样式以及其他元数据传递给 Bar 对象:

import pygal
from pygal.style import Style

custom_style = Style(
    colors=('#0343df', '#e50000', '#ffff14', '#929591'),
    font_family='Roboto,Helvetica,Arial,sans-serif',
    background='transparent',
    label_font_size=14,
)

c = pygal.Bar(
    title="UK Election Results",
    style=custom_style,
    y_title='Seats',
    width=1200,
    x_label_rotation=270,
)

然后,我们将数据添加到 Bar 对象中:

c.add('Conservative', df['conservative'])
c.add('Labour', df['labour'])
c.add('Liberal', df['liberal'])
c.add('Others', df['others'])

c.x_labels = df['year']

最后,我们将图另存为 SVG 文件:

c.render_to_file('pygal.svg')

结果是一个交互式 SVG 图,你可以在此 gif 中看到:

 title=

精美简单,并且效果漂亮。

总结

Python 中的某些绘图工具需要非常详细地构建每个对象,而 Pygal 从一开始就为你提供这些。如果你手边有数据并且想做一个干净、漂亮、简单的交互式图表,请尝试一下 Pygal。


via: https://opensource.com/article/20/6/pygal-python

作者:Shaun Taylor-Morgan 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Plotly 是一个数据绘图库,具有整洁的接口,它旨在允许你构建自己的 API。

Plotly 是一个绘图生态系统,可以让你在 Python 以及 JavaScript 和 R 中进行绘图。在本文中,我将重点介绍使用 Python 库进行绘图

Plotly 有三种不同的 Python API,你可以选择不同的方法来使用它:

  • 类似于 Matplotlib 的面向对象的 API
  • 数据驱动的 API,通过构造类似 JSON 的数据结构来定义绘图
  • 类似于 Seaborn 的高级绘图接口,称为 “Plotly Express” API

我将通过使用每个 API 来绘制相同的图来探索它们:英国大选结果的分组柱状图。

在我们进一步探讨之前,请注意,你可能需要调整你的 Python 环境来让这段代码运行,包括以下内容:

  • 运行最新版本的Python(LinuxMacWindows 的说明)
  • 确认你运行的 Python 版本能与这些库一起工作

数据可在线获得,可以用 Pandas 导入。

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

现在我们可以继续进行了。

使用图对象来绘制图

Plotly 面向对象的 API 被称为 graph_objects,它有点类似于 Matplotlib 的面向对象 API

要创建一个柱状图,你可以构造一个包含四个柱状图的对象:

# 导入 Plotly 和数据
import plotly.graph_objects as go
from votes import wide as df

# 得到 x 列表
years = df['year']
x = list(range(len(years)))

# 定义绘图
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')),
]

# 指定样式
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),
)
   
# 绘制柱状图
fig = go.Figure(data=bar_plots, layout=layout)

# 告诉 Plotly 去渲染
fig.show()

与 Matplotlib 不同的是,你无需手动计算柱状图的 x 轴位置,Plotly 会帮你适配。

最终结果图:

 title=

A multi-bar plot made using Graph Objects (© 2019 Anvil)

使用 Python 数据结构来绘图

你还可以使用 Python 基本数据结构来定义绘图,它与面对对象 API 具有相同的结构。这直接对应于 Plotly 的 JavaScript 实现的 JSON API。

# 定义绘图数据
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),
        }
    }
}

# 告诉 Plotly 去渲染它
pio.show(fig)

最终结果与上次完全相同:

 title=

A multi-bar plot made using JSON-like data structures (© 2019 Anvil)

使用 Plotly Express 进行绘图

Plotly Express 是对图对象进行封装的高级 API。

你可以使用一行代码来绘制柱状图:

# 导入 Plotly 和数据
import plotly.express as px
from votes import long as df

# 定义颜色字典获得自定义栏颜色
cmap = {
    'Conservative': '#0343df',
    'Labour': '#e50000',
    'Liberal': '#ffff14',
    'Others': '#929591',
}

# 生成图
fig = px.bar(df, x="year", y="seats", color="party", barmode="group", color_discrete_map=cmap)

这里使用了 长表 Long Form 数据,也称为“整洁数据”。这些列代表年份、政党和席位,而不是按政党划分。这与在 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]

你可以访问底层的图对象 API 进行详细调整。如添加标题和 y 轴标签:

# 使用图对象 API 来调整绘图
import plotly.graph_objects as go
fig.layout = go.Layout(
    title=go.layout.Title(text="Election results", x=0.5),
    yaxis_title="Seats",
)

最后,让 Plotly 渲染:

fig.show()

这将在未使用的端口上运行一个临时 Web 服务器,并打开默认的 Web 浏览器来查看图像(Web 服务器将会马上被关闭)。

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

 title=

A multi-bar plot made using Plotly Express (© 2019 Anvil)

你可能会尝试通过将 x 值转换为字符串来使 Plotly Express 将其视为字符串,这样它就会以均匀的间隔和词法顺序来绘制。不幸的是,它们的间隔还是很大,像在 graph_objects中那样设置 xaxis_tickvals 也不行。

Seaborn 中的类似示例不同,在这种情况下,抽象似乎没有提供足够的应急方案来提供你想要的东西,但是也许你可以编写自己的 API?

构建自己的 Plotly API

对 Plotly 的操作方式不满意?那就构建自己的 Plotly API!

Plotly 的核心是一个 JavaScript 库,它使用 D3stack.gl 进行绘图。JavaScript 库的接口使用指定的 JSON 结构来绘图。因此,你只需要输出 JavaScript 库喜欢使用的 JSON 结构就好了。

Anvil 这样做是为了创建一个完全在浏览器中工作的 Python Plotly API。

 title=

Plotly uses a JavaScript library to create plots, driven by libraries in other languages via JSON (© 2019 Anvil)

在 Anvil 版本中,你可以同时使用图对象 API 和上面介绍的 Python 数据结构方法。运行完全相同的命令,将数据和布局分配给 Anvil 应用程序中的 Plot 组件

这是用 Anvil 的客户端 Python API 绘制的多列柱状图:

# 导入 Anvil 库
from ._anvil_designer import EntrypointTemplate
from anvil import *
import anvil.server

# 导入客户端 Plotly
import plotly.graph_objs as go

# 这是一个 Anvil 表单
class Entrypoint(EntrypointTemplate):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)

    # 从服务器获取数据
    data = anvil.server.call('get_election_data')
   
    # 获取一个方便的 x 值列表
    years = data['year']
    x = list(range(len(years)))

    # 定义绘图
    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')),
    ]
    # 规定布局
    layout = {
      'title': 'Election results',
      'yaxis': {'title': 'Seats'},
      'xaxis': {
        'tickmode': 'array',
        'tickvals': list(range(27)),
        'ticktext': data['year'],
      },
    }

    # 生成多列柱状图
    self.plot_1.data = bar_plots
    self.plot_1.layout = layout

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

这是在 Anvil 应用中运行的交互式 Plotly 图:

 title=

The election plot on the web using Anvil's client-side-Python Plotly library (© 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>',
    ),

当你把这个应用到每个柱状图时,你会看到以下结果:

 title=

A multi-bar plot with custom tool-tips (© 2019 Anvil)

这很有用,当你想要在某些事件发生时执行任何你想要的代码就更好了(例如,当用户将鼠标悬停在栏上,你想要显示一个相关选举的信息框)。在 Anvil 的 Plotly 库中,你可以将事件处理程序绑定到诸如悬停之类的事件,这使得复杂的交互成为可能。

A multi-bar plot with a hover event handler (© 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 的架构 —— 它有一个简洁的接口,明确的设计是为了让你建立自己的API。如果到处都能看到这种伟大的设计,那将会很有帮助!

使用 Bokeh 进行自定义交互

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

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


via: https://opensource.com/article/20/5/plotly-python

作者:Shaun Taylor-Morgan 选题:lujun9972 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Pandas 是一个非常流行的 Python 数据操作库。学习怎样使用它的 API 绘制数据。

在有关基于 Python 的绘图库的系列文章中,我们将对使用 Pandas 这个非常流行的 Python 数据操作库进行绘图进行概念性的研究。Pandas 是 Python 中的标准工具,用于对进行数据可扩展的转换,它也已成为从 CSV 和 Excel 格式导入和导出数据的流行方法。

除此之外,它还包含一个非常好的绘图 API。这非常方便,你已将数据存储在 Pandas DataFrame 中,那么为什么不使用相同的库进行绘制呢?

在本系列中,我们将在每个库中制作相同的多条形柱状图,以便我们可以比较它们的工作方式。我们使用的数据是 1966 年至 2020 年的英国大选结果:

 title=

自行绘制的数据

在继续之前,请注意你可能需要调整 Python 环境来运行此代码,包括:

  • 运行最新版本的 Python(用于 LinuxMacWindows 的说明)
  • 确认你运行的是与这些库兼容的 Python 版本

数据可在线获得,并可使用 Pandas 导入:

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

现在我们已经准备好了。在本系列文章中,我们已经看到了一些令人印象深刻的简单 API,但是 Pandas 一定能夺冠。

要在 x 轴上绘制按年份和每个党派分组的柱状图,我只需要这样做:

import matplotlib.pyplot as plt
ax = df.plot.bar(x='year')
plt.show()

只有四行,这绝对是我们在本系列中创建的最棒的多条形柱状图。

我以宽格式使用数据,这意味着每个党派都有一列:

        year  conservative  labour  liberal  others
0       1966           253     364       12       1
1       1970           330     287        6       7
2   Feb 1974           297     301       14      18
..       ...           ...     ...      ...     ...
12      2015           330     232        8      80
13      2017           317     262       12      59
14      2019           365     202       11      72

这意味着 Pandas 会自动知道我希望如何分组,如果我希望进行不同的分组,Pandas 可以很容易地重组 DataFrame

Seaborn 一样,Pandas 的绘图功能是 Matplotlib 之上的抽象,这就是为什么要调用 Matplotlib 的 plt.show() 函数来实际生成绘图的原因。

看起来是这样的:

 title=

看起来很棒,特别是它又这么简单!让我们对它进行样式设置,使其看起来像 Matplotlib 的例子。

调整样式

我们可以通过访问底层的 Matplotlib 方法轻松地调整样式。

首先,我们可以通过将 Matplotlib 颜色表传递到绘图函数来为柱状图着色:

from matplotlib.colors import ListedColormap
cmap = ListedColormap(['#0343df', '#e50000', '#ffff14', '#929591'])
ax = df.plot.bar(x='year', colormap=cmap)

我们可以使用绘图函数的返回值设置坐标轴标签和标题,它只是一个 Matplotlib 的 Axis 对象

ax.set_xlabel(None)
ax.set_ylabel('Seats')
ax.set_title('UK election results')

这是现在的样子:

 title=

这与上面的 Matplotlib 版本几乎相同,但是只用了 8 行代码而不是 16 行!我内心的代码高手非常高兴。

抽象必须是可转义的

与 Seaborn 一样,向下访问 Matplotlib API 进行细节调整的能力确实很有帮助。这是给出抽象紧急出口使其既强大又简单的一个很好的例子。


via: https://opensource.com/article/20/6/pandas-python

作者:Shaun Taylor-Morgan 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在 Bokeh 中绘图比其他一些绘图库要复杂一些,但付出额外的努力是有回报的。

在这一系列文章中,我通过在每个 Python 绘图库中制作相同的多条形绘图,来研究不同 Python 绘图库的特性。这次我重点介绍的是 Bokeh(读作 “BOE-kay”)。

Bokeh 中的绘图比其它一些绘图库要复杂一些,但付出的额外努力是有回报的。Bokeh 的设计既允许你在 Web 上创建自己的交互式绘图,又能让你详细控制交互性如何工作。我将通过给我在这个系列中一直使用的多条形图添加工具提示来展示这一点。它绘制了 1966 年到 2020 年之间英国选举结果的数据。

 title=

绘图的放大视图(©2019 年 Anvil

制作多条形图

在我们继续之前,请注意你可能需要调整你的 Python 环境来让这段代码运行,包括以下:

  • 运行最新版本的 Python (在 LinuxMacWindows 上的说明)
  • 确认你运行的 Python 版本能与这些库一起工作。

数据可在线获得,可以用 Pandas 导入。

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

现在我们可以继续进行了。

为了做出多条形图,你需要对你的数据进行一下调整。

原始数据是这样的:

>> print(long)
        year         party  seats
0       1966  Conservative    253
1       1970  Conservative    330
2   Feb 1974  Conservative    297
3   Oct 1974  Conservative    277
4       1979  Conservative    339
..       ...           ...    ...
103     2005        Others     30
104     2010        Others     29
105     2015        Others     80
106     2017        Others     59
107     2019        Others     72

[60 rows x 3 columns]

你可以把数据看成是每一个可能的 (year, party) 组合的一系列 seats 值。这正是 Bokeh 处理的方式。你需要做一个 (year, party) 元组的列表:

# 得到每种可能的 (year, party) 组合的元组
x = [(str(r[1]['year']), r[1]['party']) for r in df.iterrows()]
   
# This comes out as [('1922', 'Conservative'), ('1923', 'Conservative'), ... ('2019', 'Others')]

这些将是 x 值。y 值就是席位(seats)。

y = df['seats']

现在你的数据看起来应该像这样:

x                               y
('1966', 'Conservative')        253
('1970', 'Conservative')        330
('Feb 1974', 'Conservative')    297
('Oct 1974', 'Conservative')    277
('1979', 'Conservative')        339
 ...      ...                   ...
('2005', 'Others')              30
('2010', 'Others')              29
('2015', 'Others')              80
('2017', 'Others')              59
('2019', 'Others')              72

Bokeh 需要你将数据封装在它提供的一些对象中,这样它就能给你提供交互功能。将你的 xy 数据结构封装在一个 ColumnDataSource 对象中。

    from bokeh.models import ColumnDataSource

    source = ColumnDataSource(data={'x': x, 'y': y})

然后构造一个 Figure 对象,并传入你用 FactorRange 对象封装的 x 数据。

    from bokeh.plotting import figure
    from bokeh.models import FactorRange
   
    p = figure(x_range=FactorRange(*x), width=2000, title="Election results")

你需要让 Bokeh 创建一个颜色表,这是一个特殊的 DataSpec 字典,它根据你给它的颜色映射生成。在这种情况下,颜色表是一个简单的党派名称和一个十六进制值之间的映射。

    from bokeh.transform import factor_cmap

    cmap = {
        'Conservative': '#0343df',
        'Labour': '#e50000',
        'Liberal': '#ffff14',
        'Others': '#929591',
    }
    fill_color = factor_cmap('x', palette=list(cmap.values()), factors=list(cmap.keys()), start=1, end=2)

现在你可以创建条形图了:

    p.vbar(x='x', top='y', width=0.9, source=source, fill_color=fill_color, line_color=fill_color)

Bokeh 图表上数据的可视化形式被称为“ 字形 glyphs ”,因此你已经创建了一组条形字形。

调整图表的细节,让它看起来像你想要的样子。

    p.y_range.start = 0
    p.x_range.range_padding = 0.1
    p.yaxis.axis_label = 'Seats'
    p.xaxis.major_label_orientation = 1
    p.xgrid.grid_line_color = None

最后,告诉 Bokeh 你现在想看你的绘图:

   from bokeh.io import show

   show(p)

这将绘图写入一个 HTML 文件,并在默认的 Web 浏览器中打开它。如下结果:

 title=

Bokeh 中的多条形绘图(©2019年Anvil

它已经有了一些互动功能,比如盒子缩放。

 title=

Bokeh 内置的盒子缩放(©2019Anvil

但 Bokeh 的厉害之处在于你可以添加自己的交互性。在下一节中,我们通过在条形图中添加工具提示来探索这个问题。

给条形图添加工具提示

要在条形图上添加工具提示,你只需要创建一个 HoverTool 对象并将其添加到你的绘图中。

    h = HoverTool(tooltips=[
        ('Seats', '@y'),
        ('(Year, Party)', '(@x)')
    ])
    p.add_tools(h)

参数定义了哪些数据会显示在工具提示上。变量 @y@x 是指你传入 ColumnDataSource 的变量。你还可以使用一些其他的值。例如,光标在图上的位置由 $x$y 给出(与 @x@y 没有关系)。

下面是结果:

 title=

选举图,现在带有工具提示(© 2019 Anvil

借助 Bokeh 的 HTML 输出,将绘图嵌入到 Web 应用中时,你可以获得完整的交互体验。你可以在这里把这个例子复制为 Anvil 应用(注:Anvil 需要注册才能使用)。

现在,你可以看到付出额外努力在 Bokeh 中将所有数据封装在 ColumnDataSource 等对象的原因了。作为回报,你可以相对轻松地添加交互性。

回归简单:Altair

Bokeh 是四大最流行的绘图库之一,本系列将研究它们各自的特别之处

我也在研究几个因其有趣的方法而脱颖而出的库。接下来,我将看看 Altair,它的声明式 API 意味着它可以做出非常复杂的绘图,而不会让你头疼。


via: https://opensource.com/article/20/5/bokeh-python

作者:Shaun Taylor-Morgan 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

比较七个在 Python 中绘图的库和 API,看看哪个最能满足你的需求。

“如何在 Python 中绘图?”曾经这个问题有一个简单的答案:Matplotlib 是唯一的办法。如今,Python 作为数据科学的语言,有着更多的选择。你应该用什么呢?

本指南将帮助你决定。

它将向你展示如何使用四个最流行的 Python 绘图库:Matplotlib、Seaborn、Plotly 和 Bokeh,再加上两个值得考虑的优秀的后起之秀:Altair,拥有丰富的 API;Pygal,拥有漂亮的 SVG 输出。我还会看看 Pandas 提供的非常方便的绘图 API。

对于每一个库,我都包含了源代码片段,以及一个使用 Anvil 的完整的基于 Web 的例子。Anvil 是我们的平台,除了 Python 之外,什么都不用做就可以构建网络应用。让我们一起来看看。

示例绘图

每个库都采取了稍微不同的方法来绘制数据。为了比较它们,我将用每个库绘制同样的图,并给你展示源代码。对于示例数据,我选择了这张 1966 年以来英国大选结果的分组柱状图。

Bar chart of British election data

我从维基百科上整理了英国选举史的数据集:从 1966 年到 2019 年,保守党、工党和自由党(广义)在每次选举中赢得的英国议会席位数,加上“其他”赢得的席位数。你可以以 CSV 文件格式下载它

Matplotlib

Matplotlib 是最古老的 Python 绘图库,现在仍然是最流行的。它创建于 2003 年,是 SciPy Stack 的一部分,SciPy Stack 是一个类似于 Matlab 的开源科学计算库。

Matplotlib 为你提供了对绘制的精确控制。例如,你可以在你的条形图中定义每个条形图的单独的 X 位置。下面是绘制这个图表的代码(你可以在这里运行):

    import matplotlib.pyplot as plt
    import numpy as np
    from votes import wide as df

    # Initialise a figure. subplots() with no args gives one plot.
    fig, ax = plt.subplots()

    # A little data preparation
    years = df['year']
    x = np.arange(len(years))

    # Plot each bar plot. Note: manually calculating the 'dodges' of the bars
    ax.bar(x - 3*width/2, df['conservative'], width, label='Conservative', color='#0343df')
    ax.bar(x - width/2, df['labour'], width, label='Labour', color='#e50000')
    ax.bar(x + width/2, df['liberal'], width, label='Liberal', color='#ffff14')
    ax.bar(x + 3*width/2, df['others'], width, label='Others', color='#929591')

    # Customise some display properties
    ax.set_ylabel('Seats')
    ax.set_title('UK election results')
    ax.set_xticks(x)    # This ensures we have one tick per year, otherwise we get fewer
    ax.set_xticklabels(years.astype(str).values, rotation='vertical')
    ax.legend()

    # Ask Matplotlib to show the plot
    plt.show()

这是用 Matplotlib 绘制的选举结果:

Matplotlib plot of British election data

Seaborn

Seaborn 是 Matplotlib 之上的一个抽象层;它提供了一个非常整洁的界面,让你可以非常容易地制作出各种类型的有用绘图。

不过,它并没有在能力上有所妥协!Seaborn 提供了访问底层 Matplotlib 对象的逃生舱口,所以你仍然可以进行完全控制。

Seaborn 的代码比原始的 Matplotlib 更简单(可在此处运行):

    import seaborn as sns
    from votes import long as df

    # Some boilerplate to initialise things
    sns.set()
    plt.figure()

    # This is where the actual plot gets made
    ax = sns.barplot(data=df, x="year", y="seats", hue="party", palette=['blue', 'red', 'yellow', 'grey'], saturation=0.6)

    # Customise some display properties
    ax.set_title('UK election results')
    ax.grid(color='#cccccc')
    ax.set_ylabel('Seats')
    ax.set_xlabel(None)
    ax.set_xticklabels(df["year"].unique().astype(str), rotation='vertical')

    # Ask Matplotlib to show it
    plt.show()

并生成这样的图表:

Seaborn plot of British election data

Plotly

Plotly 是一个绘图生态系统,它包括一个 Python 绘图库。它有三个不同的接口:

  1. 一个面向对象的接口。
  2. 一个命令式接口,允许你使用类似 JSON 的数据结构来指定你的绘图。
  3. 类似于 Seaborn 的高级接口,称为 Plotly Express。

Plotly 绘图被设计成嵌入到 Web 应用程序中。Plotly 的核心其实是一个 JavaScript 库!它使用 D3stack.gl 来绘制图表。

你可以通过向该 JavaScript 库传递 JSON 来构建其他语言的 Plotly 库。官方的 Python 和 R 库就是这样做的。在 Anvil,我们将 Python Plotly API 移植到了 Web 浏览器中运行

这是使用 Plotly 的源代码(你可以在这里运行):

    import plotly.graph_objects as go
    from votes import wide as df

    #  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')),
    ]

    # Customise some display properties
    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()

选举结果图表:

 title=

Bokeh

Bokeh(发音为 “BOE-kay”)擅长构建交互式绘图,所以这个标准的例子并没有将其展现其最好的一面。和 Plotly 一样,Bokeh 的绘图也是为了嵌入到 Web 应用中,它以 HTML 文件的形式输出绘图。

下面是使用 Bokeh 的代码(你可以在这里运行):

    from bokeh.io import show, output_file
    from bokeh.models import ColumnDataSource, FactorRange, HoverTool
    from bokeh.plotting import figure
    from bokeh.transform import factor_cmap
    from votes import long as df

    # Specify a file to write the plot to
    output_file("elections.html")

    # Tuples of groups (year, party)
    x = [(str(r[1]['year']), r[1]['party']) for r in df.iterrows()]
    y = df['seats']

    # Bokeh wraps your data in its own objects to support interactivity
    source = ColumnDataSource(data=dict(x=x, y=y))

    # Create a colourmap
    cmap = {
        'Conservative': '#0343df',
        'Labour': '#e50000',
        'Liberal': '#ffff14',
        'Others': '#929591',
    }
    fill_color = factor_cmap('x', palette=list(cmap.values()), factors=list(cmap.keys()), start=1, end=2)

    # Make the plot
    p = figure(x_range=FactorRange(*x), width=1200, title="Election results")
    p.vbar(x='x', top='y', width=0.9, source=source, fill_color=fill_color, line_color=fill_color)

    # Customise some display properties
    p.y_range.start = 0
    p.x_range.range_padding = 0.1
    p.yaxis.axis_label = 'Seats'
    p.xaxis.major_label_orientation = 1
    p.xgrid.grid_line_color = None

图表如下:

 title=

Altair

Altair 是基于一种名为 Vega 的声明式绘图语言(或“可视化语法”)。这意味着它具有经过深思熟虑的 API,可以很好地扩展复杂的绘图,使你不至于在嵌套循环的地狱中迷失方向。

与 Bokeh 一样,Altair 将其图形输出为 HTML 文件。这是代码(你可以在这里运行):

    import altair as alt
    from votes import long as df

    # Set up the colourmap
    cmap = {
        'Conservative': '#0343df',
        'Labour': '#e50000',
        'Liberal': '#ffff14',
        'Others': '#929591',
    }

    # Cast years to strings
    df['year'] = df['year'].astype(str)

    # Here's where we make the plot
    chart = alt.Chart(df).mark_bar().encode(
        x=alt.X('party', title=None),
        y='seats',
        column=alt.Column('year', sort=list(df['year']), title=None),
        color=alt.Color('party', scale=alt.Scale(domain=list(cmap.keys()), range=list(cmap.values())))
    )

    # Save it as an HTML file.
    chart.save('altair-elections.html')

结果图表:

 title=

Pygal

Pygal 专注于视觉外观。它默认生成 SVG 图,所以你可以无限放大它们或打印出来,而不会被像素化。Pygal 绘图还内置了一些很好的交互性功能,如果你想在 Web 应用中嵌入绘图,Pygal 是另一个被低估了的候选者。

代码是这样的(你可以在这里运行它):

    import pygal
    from pygal.style import Style
    from votes import wide as df

    # Define the style
    custom_style = Style(
        colors=('#0343df', '#e50000', '#ffff14', '#929591')
        font_family='Roboto,Helvetica,Arial,sans-serif',
        background='transparent',
        label_font_size=14,
    )

    # Set up the bar plot, ready for data
    c = pygal.Bar(
        title="UK Election Results",
        style=custom_style,
        y_title='Seats',
        width=1200,
        x_label_rotation=270,
    )

    # Add four data sets to the bar plot
    c.add('Conservative', df['conservative'])
    c.add('Labour', df['labour'])
    c.add('Liberal', df['liberal'])
    c.add('Others', df['others'])

    # Define the X-labels
    c.x_labels = df['year']

    # Write this to an SVG file
    c.render_to_file('pygal.svg')

绘制结果:

 title=

Pandas

Pandas 是 Python 的一个极其流行的数据科学库。它允许你做各种可扩展的数据处理,但它也有一个方便的绘图 API。因为它直接在数据帧上操作,所以 Pandas 的例子是本文中最简洁的代码片段,甚至比 Seaborn 的代码还要短!

Pandas API 是 Matplotlib 的一个封装器,所以你也可以使用底层的 Matplotlib API 来对你的绘图进行精细的控制。

这是 Pandas 中的选举结果图表。代码精美简洁!

    from matplotlib.colors import ListedColormap
    from votes import wide as df

    cmap = ListedColormap(['#0343df', '#e50000', '#ffff14', '#929591'])

    ax = df.plot.bar(x='year', colormap=cmap)

    ax.set_xlabel(None)
    ax.set_ylabel('Seats')
    ax.set_title('UK election results')

    plt.show()

绘图结果:

 title=

要运行这个例子,请看这里

以你的方式绘制

Python 提供了许多绘制数据的方法,无需太多的代码。虽然你可以通过这些方法快速开始创建你的绘图,但它们确实需要一些本地配置。如果需要,Anvil 为 Python 开发提供了精美的 Web 体验。祝你绘制愉快!


via: https://opensource.com/article/20/4/plot-data-python

作者:Shaun Taylor-Morgan 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出