4.数据可视化(二)

4.6 几何对象

先来看看下面这两个图有什么相似之处呢?

image.png

两个图都包含相同的 x 变量和 y 变量,并且都描述了相同的数据。但图形并不相同。每个图都使用不同的几何对象来表示数据。在 ggplot2 语法中,我们说它们使用不同的geoms

要生成上面的图,可以使用以下代码:

# left
ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy))

# right
ggplot(data = mpg) + 
  geom_smooth(mapping = aes(x = displ, y = hwy))

ggplot2 中的每个 geom 函数都有一个mapping参数。然而,并不是每一种图形属性都适用于每一种几何对象。您可以设置点的形状,但不能设置线的“形状”。另一方面,您可以设置线的线型。geom_smooth()将为映射到线型的变量的每个唯一值绘制具有不同线型的线。

ggplot(data = mpg) + 
  geom_smooth(mapping = aes(x = displ, y = hwy, linetype = drv))
image

这里geom_smooth()根据汽车的drv值将汽车分为三类,这描述了汽车的动力传动系统。在这里,4代表四轮驱动、f前轮驱动和r后轮驱动。

如果这听起来很奇怪,我们可以通过将线条叠加在原始数据之上,然后根据drv对所有内容进行着色来使其更加清晰。

image

请注意,此图在同一图中包含两个几何体!我们很快就会学习如何在同一个图中放置多个几何体。

ggplot2 提供了 40 多个 geoms,扩展包提供了更多内容(请参阅https://exts.ggplot2.tidyverse.org/gallery/以获取示例)。想要查看 ggplot2 所有的内容,您可以在http://rstudio.com/resources/cheatsheets找到它。要了解有关任何单个 geom 的更多信息,请使用 help: ?geom_smooth

许多几何图形,例如geom_smooth(),使用单个几何对象来显示多行数据。对于这些几何图形,您可以将group图形属性设置为分类变量以绘制多个对象。ggplot2 将为分组变量的每个唯一值绘制一个单独的对象。在实践中,每当您将图形属性映射到离散变量时(如linetype示例中所示),ggplot2 将自动对这些几何图形的数据进行分组。依靠此功能很方便,因为group属性本身不会向几何图形添加图例或区别特征。

ggplot(data = mpg) +
  geom_smooth(mapping = aes(x = displ, y = hwy))

ggplot(data = mpg) +
  geom_smooth(mapping = aes(x = displ, y = hwy, group = drv))

ggplot(data = mpg) +
  geom_smooth(
    mapping = aes(x = displ, y = hwy, color = drv),
    show.legend = FALSE
  )
image.png

要在同一个图中显示多个 geom,直接将多个 geom 函数添加到ggplot()

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy)) +
  geom_smooth(mapping = aes(x = displ, y = hwy))
image

然而,这会在我们的代码中引入一些重复。想象一下,如果您想将 y 轴更改为显示cty而不是hwy. 您需要在两个地方更改变量,而且您可能会忘记更新其中一个。您可以通过将一组映射传递给ggplot()来避免这种类型的重复。ggplot2 将这些映射视为适用于图中每个几何图形的全局映射。换句话说,此代码将生成与先前代码相同的图:

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
  geom_point() + 
  geom_smooth()

如果将映射放置在 geom 函数中,ggplot2 会将它们视为图层的本地映射。它将仅使用这些映射来扩展或覆盖该的全局映射。这使得可以在不同的层中展示不同的几何对象。

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
  geom_point(mapping = aes(color = class)) + 
  geom_smooth()
image

您可以使用相同的想法为data每个图层指定不同的内容。在这里,我们的平滑线仅显示mpg数据集的一个子集,即小型汽车。ggplot()中的局部数据参数仅覆盖该层geom_smooth()的全局数据参数。

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
  geom_point(mapping = aes(color = class)) + 
  geom_smooth(data = filter(mpg, class == "subcompact"), se = FALSE)
image

4.7 统计变换

接下来,让我们看一下条形图。条形图看起来很简单,但它们很有趣,因为它们揭示了一些关于图的微妙之处。使用geom_bar()绘制的基本条形图。下图显示了diamonds数据集中的钻石总数,按cut分组。该diamonds数据集来自GGPLOT2,并包含约54000颗钻石,其中包括每颗钻石的pricecaratcolorclarity,和cut信息。该图表显示,与低质量切割相比,高质量切割的钻石更多。

ggplot(data = diamonds) + 
  geom_bar(mapping = aes(x = cut))
image

在 x 轴上,图表显示cut,一个来自diamonds的变量。在 y 轴上,它显示计数,但计数不是diamonds! 计数从何而来?许多图表(如散点图)绘制数据集的原始值。其他图形,如条形图,计算要绘制的新值:

  • 条形图、直方图和频率多边形对您的数据进行分箱,然后绘制分箱计数,即落在每个分箱中的点数。

  • 平滑器将模型拟合到您的数据,然后根据模型绘制预测。

  • boxplots 计算分布的可靠摘要,然后显示一个特殊格式的框。

用于计算图形新值的算法称为stat,是统计转换的缩写。下图描述了此过程如何与geom_bar().

image

您可以通过检查stat参数的默认值来了解 geom 使用的统计数据。例如,?geom_bar显示的默认值为stat“count”,这意味着geom_bar()使用stat_count(). stat_count()geom_bar()记录在同一页面上,如果向下滚动,您可以找到名为“计算变量”的部分。这描述了它如何计算两个新变量:countprop

您通常可以交替使用 geoms 和 stats。例如,您可以使用stat_count()代替geom_bar()

ggplot(data = diamonds) + 
  stat_count(mapping = aes(x = cut))
image

这是有效的,因为每个 geom 都有一个默认的统计变量;并且每个 stat 都有一个默认的 geom。这意味着您通常可以使用 geom 而不必担心底层的统计转换。但是有时候,你可能需要明确使用统计数据:

  1. 您可能想要覆盖默认统计。在下面的代码中,我将geom_bar()的统计从count(默认)更改为identity。这让我把条形图的高度映射到y的原始值变量。不幸的是,当人们不经意地谈论柱状图时,他们可能指的是这种类型的柱状图,其中柱状图的高度已经显示在数据中,或者之前的柱状图中柱状图的高度是通过计算行生成的。

    demo <- tribble(
      ~cut,         ~freq,
      "Fair",       1610,
      "Good",       4906,
      "Very Good",  12082,
      "Premium",    13791,
      "Ideal",      21551
    )
    
    ggplot(data = demo) +
      geom_bar(mapping = aes(x = cut, y = freq), stat = "identity")
    
    image
  1. 您可能想要覆盖从转换变量到图形属性的默认映射。例如,你可能想要显示一个比例条形图,而不是计数:

    ggplot(data = diamonds) + 
      geom_bar(mapping = aes(x = cut, y = stat(prop), group = 1))
    
    image

    要查找由 stat 计算的变量,请查找标题为“computed variables”的帮助部分。

  2. 您可能希望更多地关注代码中的统计转换。例如,您可以使用stat_summary(),它总结了每个唯一 x 值的 y 值,以引起对您正在计算的总结的注意:

    ggplot(data = diamonds) + 
      stat_summary(
        mapping = aes(x = cut, y = depth),
        fun.min = min,
        fun.max = max,
        fun = median
      )
    
    image

ggplot2 提供了 20 多个统计变量使用。每个 stat 都是一个函数,因此您可以通过通常的方式获得帮助,例如 ?stat_bin. 要查看完整的统计信息列表,请尝试使用 ggplot2 备忘单。

4.8 位置调整

还有一种与条形图相关的。使用colour属性为条形图着色,或者更有用的是fill

ggplot(data = diamonds) + 
  geom_bar(mapping = aes(x = cut, colour = cut))
ggplot(data = diamonds) + 
  geom_bar(mapping = aes(x = cut, fill = cut))
image.png

请注意如果将fill图形属性映射到另一个变量会发生什么,例如clarity:条形自动堆叠。每个彩色矩形代表的组合cutclarity

ggplot(data = diamonds) + 
  geom_bar(mapping = aes(x = cut, fill = clarity))
image

通过参数指定的位置调整自动执行堆叠position。如果您不想要堆积条形图,您可以使用其他三个选项之一:"identity""dodge""fill"

  • position = "identity"将把每个对象准确地放置在图形上下文中的位置。这对条形不是很有用,因为它与它们重叠。要查看重叠,我们需要通过设置alpha为较小的值来使条形略微透明,或者通过设置 使条形完全透明fill = NA

    ggplot(data = diamonds, mapping = aes(x = cut, fill = clarity)) + 
      geom_bar(alpha = 1/5, position = "identity")
    ggplot(data = diamonds, mapping = aes(x = cut, colour = clarity)) + 
      geom_bar(fill = NA, position = "identity")
    
image.png
`identity`位置调整对于二维几何图形更有用,例如点,它是默认设置。
  • position = "fill"像堆叠一样工作,但使每组堆叠的条具有相同的高度。这样可以更轻松地比较各组之间的比例。

    ggplot(data = diamonds) + 
      geom_bar(mapping = aes(x = cut, fill = clarity), position = "fill")
    
    image
  • position = "dodge"将重叠的对象直接放在一起。这样可以更轻松地比较各个值。

    ggplot(data = diamonds) + 
      geom_bar(mapping = aes(x = cut, fill = clarity), position = "dodge")
    
    image

还有一种对条形图没有用的调整类型,但它对散点图非常有用。回想一下我们的第一个散点图。您是否注意到该图仅显示 126 个点,即使数据集中有 234 个观测值?

image

hwydispl的值是圆形的,所以点出现在网格上,许多点相互重叠。这个问题被称为overplotting。这种图形使得很难看到大量数据在哪里。数据点是否均匀分布在整个图中,或者是否存在一个包含109个值的特殊的hwydispl组合?

您可以通过将位置调整设置为“抖动”来避免这种网格化。position = "jitter"向每个点添加少量随机噪声。这会将点分散开,因为没有两个点可能会收到相同数量的随机噪声。

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy), position = "jitter")
image

添加随机性似乎是一种改善绘图的奇特方法,但虽然它会在小尺度上降低图形的准确性,但它会使你的图形在大尺度上更具揭示性。因为这是这样一个有用的操作,GGPLOT2自带的简写geom_point(position = "jitter")geom_jitter()

要了解更多关于位置调节,查找与每个调整相关的帮助页面:?position_dodge?position_fill?position_identity?position_jitter,和?position_stack

4.9 坐标系

坐标系可能是 ggplot2 中最复杂的部分。默认坐标系是笛卡尔坐标系,其中 x 和 y 位置独立作用以确定每个点的位置。还有许多其他坐标系有时会有所帮助。

  • coord_flip()切换 x 和 y 轴。如果您想要水平箱线图,这很有用(例如)。它对于长标签也很有用:很难让它们在 x 轴上不重叠。

    ggplot(data = mpg, mapping = aes(x = class, y = hwy)) + 
      geom_boxplot()
    ggplot(data = mpg, mapping = aes(x = class, y = hwy)) + 
      geom_boxplot() +
      coord_flip()
    
image.png
  • coord_quickmap()正确设置地图的纵横比。如果您使用 ggplot2 绘制空间数据,这非常重要。

    nz <- map_data("nz")
    
    ggplot(nz, aes(long, lat, group = group)) +
      geom_polygon(fill = "white", colour = "black")
    
    ggplot(nz, aes(long, lat, group = group)) +
      geom_polygon(fill = "white", colour = "black") +
      coord_quickmap()
    
image.png
  • coord_polar()使用极坐标。极坐标揭示了条形图和 Coxcomb 图之间的有趣联系。

    bar <- ggplot(data = diamonds) + 
      geom_bar(
        mapping = aes(x = cut, fill = cut), 
        show.legend = FALSE,
        width = 1
      ) + 
      theme(aspect.ratio = 1) +
      labs(x = NULL, y = NULL)
    
    bar + coord_flip()
    bar + coord_polar()
    
image.png

4.10 图形的分层语法

在前面的部分中,您学到的不仅仅是如何制作散点图、条形图和箱线图。你学习了一个基础,你可以用它来用 ggplot2制作任何类型的图。为了看到这一点,让我们向我们的代码模板添加位置调整、统计数据、坐标系和分面:

ggplot(data = <DATA>) + 
  <GEOM_FUNCTION>(
     mapping = aes(<MAPPINGS>),
     stat = <STAT>, 
     position = <POSITION>
  ) +
  <COORDINATE_FUNCTION> +
  <FACET_FUNCTION>

我们的新模板采用七个参数,即模板中出现的括号内的词。实际上,您很少需要提供所有七个参数来制作图形,因为 ggplot2 将为除数据、映射和 geom 函数之外的所有内容提供有用的默认值。

模板中的七个参数组成了图形的语法,一个用于构建图的正式模板。图形的语法基于这样的见解,即您可以将任何图唯一地描述为数据集、几何图形、一组映射、统计数据、位置调整、坐标系和分面方案的组合。

要了解其工作原理,请考虑如何从头开始构建基本图:您可以从数据集开始,然后将其转换为您想要显示的信息(使用统计数据)。

image

接下来,您可以选择一个几何对象来表示转换数据中的每个观察值。然后,您可以使用几何图形的美学属性来表示数据中的变量。您可以将每个变量的值映射到美学级别。

image

然后选择一个坐标系统来放置几何图形。您可以使用对象的位置(这本身就是一个图形属性)来显示x和y变量的值。此时,您将拥有一个完整的图,但您可以进一步调整坐标系统中的图形的位置(位置调整)或将图分割为子图(分面)。您还可以通过添加一个或多个额外层来扩展绘图,其中每个额外层使用一个数据集、一个geom、一组映射、一个统计数据和一个位置调整。


image

您可以使用此方法构建您想象的任何图形。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容