前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用Julia进行统计绘图

使用Julia进行统计绘图

作者头像
磐创AI
发布2024-01-17 13:58:13
1950
发布2024-01-17 13:58:13
举报
文章被收录于专栏:磐创AI技术团队的专栏
VegaLite(以及Gadfly)的概念基础是图形语法(Grammar of Graphics,GoG),我在《图形语法或如何在Julia中进行ggplot风格绘图》([SPJ01])中介绍过。在那里,我还介绍了将在绘图示例中使用的数据(在这里和[SPJ02]中)。

本文(以及系列中将要发布的其他文章)的目标是使用完全相同的数据重现[SPJ02]中的可视化效果,但每次当然会使用另一个绘图包,以便对所有包进行1:1的比较。

《Towards Data Science》的出版指南不允许重复这些可视化的描述。因此,请参阅[SPJ02]以获取更多信息,或在Julia Forem上阅读本文的更自包含版本。

VegaLite

VegaLite.jl与Gadfly.jl一样,也是图形语法(GoG)的一个非常完整的实现,我们将在下面的示例中看到。它是由大卫·安索夫教授(加州大学伯克利分校)领导的一个由20多名贡献者组成的团队编写的。VegaLite是数据科学包(称为Queryverse)的一部分,其中包括查询语言(Query.jl)、文件IO和UI工具(ElectronDisplay.jl)等。

从技术上讲,VegaLite采取了完全不同的方法:虽然Gadfly完全是用Julia编写的,但VegaLite更像是Vega-Lite图形包的语言接口(注意其名称中的破折号,与Julia包VegaLite相对应)。Vega-Lite以JSON格式的可视化规范作为输入,Vega-Lite编译器将其转换为相应的可视化效果。

Vega-Lite完全独立于Julia生态系统,除了VegaLite外,还存在其他语言(如JavaScript、Python、R或Scala)的接口(完整列表请参见“Vega-Lite生态系统”)。

由于Vega-Lite使用JSON作为其输入格式,这些规范具有相当声明性质。VegaLite试图通过@vlplot宏来模仿这种格式,正如我们将在下面的示例中看到的,该宏是所有可视化的基础。这使其不太像Julia,例如Gadfly,但另一方面,熟悉Vega-Lite的人很容易学会如何使用VegaLite。如果VegaLite文档中有遗漏的内容,通常很容易在Vega-Lite文档中找到相应的部分。

Vega-Lite(以及VegaLite)的一个区别性特征是其互动性。其规范不仅描述了可视化效果,还描述了事件、兴趣点以及如何对这些事件作出反应的规则。但这个特性超出了本文的范围。对于对此感兴趣的读者,我建议查看Vega-Lite主页或论文“Vega-Lite: A Grammar of Interactive Graphics”。

示例绘图

与前一篇文章中一样,我将使用以下相同的图表类型(或者按照GoG的说法称之为几何图形)进行比较:

  • 柱状图
  • 散点图
  • 直方图
  • 箱线图
  • 小提琴图

VegaLite提供的类型的完整列表可以在此图库中找到。

与[SPJ02]一样,我们假设示例数据在DataFrames结构countries、subregions_cum和regions_cum中可用。

并且与[SPJ02]一样,大多数图表首先以基本版本呈现,使用图形包的默认设置,然后使用自定义属性进行优化。

柱状图

按地区划分的人口

第一个图表是柱状图,显示了按地区划分的人口规模(2019年)。在VegaLite中,所有图表都是使用@vlplot命令创建的。在下面的代码中,使用了Julia的流水线语法(|>),将regions_cum-DataFrame指定为@vlplot的输入。

代码语言:javascript
复制
regions_cum |>
    @vlplot(
         width = 600, height = 300,
         :bar,
         x = :Region, y = :Pop2019, color = :Region
     )

这将产生以下柱状图:

现在我们手动设置坐标轴标签、标题和背景颜色,并将x轴上的柱状标签更改为水平方向,以提高可读性。在VegaLite中,标题属性用于标签以及图表标题,轴属性用于更改柱状标签的方向,配置用于一般属性,如背景颜色(与Gadfly中的主题相对应)。

代码语言:javascript
复制
regions_cum |>
    @vlplot(
        width = 600, height = 300,
        title = "Population by Region, 2019",
        :bar,
        x = {:Region, title = "Region", axis = {labelAngle = 0}},
        y = {:Pop2019, title = "Population [millions]"},
        color = :Region,
        config = {background = "ghostwhite"}
    )

… 创建以下柱状图:

按子地区划分的人口

下一个柱状图描述了按子地区划分的人口(同样使用@vlplot):

代码语言:javascript
复制
subregions_cum |>
    @vlplot(
        width = 600, height = 300,
        :bar,
        x = :Subregion, y = :Pop2019, color = :Region
    )

在下一步中,我们切换到了水平柱状图,并再次手动调整了标签、标题和背景颜色。在VegaLite中,通过将x轴和y轴的数据属性翻转,我们可以获得水平布局:

代码语言:javascript
复制
subregions_cum |>
    @vlplot(
        title = "Population by Subregion, 2019",
        width = 600, height = 300,
        :bar,
        x = {:Pop2019, title = "Population [millions]"}, 
        y = {:Subregion, title = "Subregion"}, 
        color = :Region,
        config = {background = "ghostwhite"}
    )

现在我们希望在绘制图表之前按人口大小对子地区进行排序。为此,我们可以使用Julia对subregions_cum-DataFrame进行排序(与在Gadfly示例中所做的一样),但VegaLite提供了使用sort属性在图形引擎中对数据进行排序的可能性。

代码语言:javascript
复制
subregions_cum |>
    @vlplot(
        title = "Population by Subregion, 2019",
        width = 600, height = 300,
        :bar,
        x = {:Pop2019, title = "Population [millions]"}, 
        y = {:Subregion, sort = "-x", title = "Subregion"}, 
        color = :Region,
        config = {background = "ghostwhite"}
    )

在这一点上需要注意:虽然可以在图形引擎内部对数据进行排序,但我不建议在数据集较大时这样做,因为它比直接使用Julia要慢得多。

散点图

下一个图表是一个散点图(使用点几何图形),用于描述国家层面的人口与增长率的关系:

代码语言:javascript
复制
countries |>
    @vlplot(
        width = 600, height = 300,
        :point,
        x = :Pop2019, y = :PopChangePct, color = :Region
    )

现在我们将对x轴应用对数尺度。同样,我们添加了一些标签、背景颜色等:

代码语言:javascript
复制
countries |>
    @vlplot(
        title = "Population vs. Growth Rate, 2019",
        width = 600, height = 300,
        :point,
        x = {:Pop2019, title = "Population [millions]", 
            scale = {type = :log, base = 10}}, 
        y = {:PopChangePct, title = "Growth Rate [%]"}, 
        color = :Region,
        config = {background = "ghostwhite"}
    )

直方图

用于绘制直方图时,VegaLite严格遵循GoG,因为它使用与柱状图相同的几何图形(唯一的区别是x轴上的数据在一个称为binning的过程中映射到人为的类别)。以下代码使用参数bin设置为true的柱状几何图形,通过以下@vlplot命令创建了一个直方图,显示了不同国家之间人均GDP的分布:

代码语言:javascript
复制
countries |>
    @vlplot(
        width = 600, height = 300,
        :bar,
        x = {:GDPperCapita, bin = true}, y = “count()”
    )

默认情况下选择了合理的bin大小(这在Gadfly中不是这种情况)。

在下一步中,我们再次添加标签等。为了使bin的数量与Gadfly示例中的数量完全相同,我们使用以下代码将其明确设置为20:

代码语言:javascript
复制
countries |>
    @vlplot(
        title = "Distribution of GDP per Capita, 2019",
        width = 600, height = 300,
        :bar,
        x = {:GDPperCapita, bin = {maxbins = 20}, 
            title = "GDP per Capita [USD]"}, 
        y = {"count()", title = "Number of countries"},
        config = {background = "ghostwhite"}
    )

箱线图和小提琴图

下一个图表显示了每个地区的人均GDP分布,首先使用箱线图,然后使用小提琴图。

箱线图

我们跳过使用默认值的版本,直接进入基于箱线图几何图形的“美化”版本:

代码语言:javascript
复制
countries |>
    @vlplot(
        title = "GDP per Capita by Region, 2019",
        width = 600, height = 300,
        :boxplot,
        x = {:Region, title = "Region", axis = {labelAngle = 0}}, 
        y = {:GDPperCapita, title = "GDP per Capita [USD]"}, 
        color = :Region,
        config = {background = "ghostwhite"}
    )
小提琴图

由于VegaLite本身不支持小提琴图作为一种几何图形,因此必须使用密度图(每个地区一个)构建它们,这些密度图在水平上排列。这导致了以下相当复杂的规范:

代码语言:javascript
复制
countries |>
    @vlplot(
        title = "GDP per Capita by Region, 2019",
        height = 400,
        mark = {:area, orient = "horizontal"},

        transform = [
        {density = "GDPperCapita", groupby = ["Region"]}
        ],

        x = {"density:q", stack = "center", impute = nothing, title = nothing,
            axis = {labels = false}}, 
        y = {"value:q", title = "GDP per Capita [USD]", axis = {labelAngle = 0}}, 

        column = {"Region", 
            header = {titleOrient = "bottom", labelOrient = "bottom"}},
        color = :Region,

        config = {background = "ghostwhite"},
        width = 120, spacing = 0
    )

用于创建密度图的基本几何图形是面积几何图形。然后,数据按地区分组,并为每个组计算密度。这是通过变换操作完成的。将密度分配给x轴会得到垂直密度图。在下一步中,所有五个密度图使用column属性水平排列。

最后一行中的width和spacing属性定义了每列(即每个密度图)在水平方向上具有120像素的宽度,并且在这些图之间没有空间。

因此,我们最终得到了以下小提琴图:

放大

与Gadfly示例中一样,我们注意到分布的真正有趣部分位于0到10万美元之间的范围内。因此,我们希望在y轴上限制图表的范围,以实现一种缩放效果。

在Gadfly示例中,我们通过将y轴上的值限制在该范围内来实现所需的效果。在VegaLite中,也可以使用scale = {domain = [0, 100000]}来指定此限制。不幸的是,这并没有给我们想要的结果:图表将在此范围内绘制,但图表本身仍然使用整个范围,直到20万美元,因此部分绘制在图表外部:

在VegaLite中获得大致相似的结果的唯一方法是使用过滤表达式将数据限制在0到10万美元的范围内。但请注意:这在概念上是不同的,不会像在整个数据集上执行的那样给我们完全相同的图表。因此,我们没有这个可视化的真正解决方案。

这可能只是VegaLite文档的问题,我在其中找不到其他解决方案(或者是我没有做足够的研究,例如还可以使用Vega-Lite的广泛文档)。

结论

我认为,上面的示例非常清楚地展示了VegaLite是另一个Julia绘图包,它相当密切地遵循了图形语法的概念(甚至比Gadfly更密切)。因此,对于VegaLite也适用于相同的发现,即绘图规范非常一致,因此易于学习。

但正如我们从小提琴图中可以看到的那样,如果事先没有定义,规范可能变得相当复杂。再加上相对非Julia的语法,需要一些时间来学习和适应,我不建议VegaLite用于偶尔的用户。它需要一些学习和训练。但是,如果你投入了时间和精力,你将获得一个非常强大(且互动性强)的可视化工具。

一个有趣的VegaLite附加组件是交互式数据探索工具Voyager(见:DataVoyager.jl)。这是一个应用程序,可以加载数据并创建各种可视化效果,无需任何编程。

如果你想自己尝试上面的示例,可以从我的GitHub存储库中获取Pluto笔记本,这是一种可以执行的这篇文章的变体。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-01-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 磐创AI 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • VegaLite
  • 示例绘图
  • 柱状图
    • 按地区划分的人口
      • 按子地区划分的人口
      • 散点图
      • 直方图
      • 箱线图和小提琴图
        • 箱线图
          • 小提琴图
          • 放大
          • 结论
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档