【问题标题】:Plot a vegetation transect with dots用点绘制植被样带
【发布时间】:2016-09-15 06:15:11
【问题描述】:

我有一个数据集,其中包含(很多)带地形高度的横断面(x 是水平距离,z 是海拔,均以米为单位)和植被结构。 b_ml、b_kl1、b_kl2 和 b_s1 分别是苔藓层、草本层 1、草本层 2 和灌木层的覆盖率,以 % 和 h_??是相同层的高度(苔藓层总是 3 厘米)。我想以有吸引力的图表呈现这些数据。以下是数据样本(1 个样带):

#sample data
structure(list(X = c(432529.4846, 432530.4562, 432531.3492, 432532.3046, 
432533.3252, 432533.3419, 432534.3361, 432535.2709, 432536.3843, 
432537.4198, 432538.4336, 432539.3736, 432540.448, 432541.3967, 
432542.2748, 432543.0681, 432544.2508, 432545.2269, 432546.0911, 
432547.0195, 432548.0396, 432549.0209, 432549.9539, 432550.9391, 
432551.8999, 432552.8647, 432553.8258, 432554.7889, 432555.7722, 
432556.7435, 432557.7456, 432558.714, 432559.6824, 432560.6456, 
432561.6306, 432562.6059, 432563.5442, 432564.5688, 432565.5408, 
432566.5742), Z = c(10.6399, 10.5674, 10.4631, 10.3553, 10.2856, 
10.2392, 10.1234, 10.0792, 10.037, 9.9068, 9.834, 9.7207, 9.6024, 
9.5322, 9.3343, 9.2266, 9.0705, 8.9673, 8.9716, 8.8292, 8.7495, 
8.6541, 8.5429, 8.4306, 8.2933, 8.1877, 7.9679, 7.7799, 7.6801, 
7.5073, 7.3754, 7.2414, 7.0254, 7.0095, 6.8553, 6.7976, 6.7528, 
6.7151, 6.5225, 6.1952), b_ml = c(0.1, 0.05, NA, 0.1, 0.05, NA, 
NA, NA, 0.05, NA, 0.1, 0.2, 0.1, 0.05, NA, NA, NA, NA, NA, NA, 
NA, 0.01, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
NA, NA, NA, NA, NA), h_kl1 = c(75, 75, 70, 80, 80, 70, NA, 30, 
30, 50, 60, 60, 60, 60, 40, 30, 30, 70, 10, 10, 10, 20, 30, 30, 
30, 15, 15, 7, 5, 5, 5, 5, 3, 5, 5, 5, 5, 5, 3, 3), b_kl1 = c(0.9, 
0.95, 0.85, 0.95, 0.95, 0.9, NA, 0.4, 0.8, 0.9, 0.9, 0.9, 0.4, 
0.05, 0.6, 0.1, 0.05, 0.1, 0.1, 0.05, 0.1, 0.1, 0.98, 1, 1, 0.98, 
0.98, 0.9, 0.95, 0.95, 0.9, 0.8, 0.4, 0.95, 0.98, 0.95, 0.5, 
0.25, 0.05, 0.01), h_kl2 = c(110, 110, 110, 100, NA, 110, NA, 
110, 110, 100, 110, 120, 110, 110, 110, 70, 70, 120, 130, 120, 
110, 50, 80, NA, 90, NA, NA, NA, NA, 20, NA, NA, NA, NA, NA, 
45, 45, 25, NA, NA), b_kl2 = c(0.05, 0.05, 0.03, 0.02, NA, 0.1, 
NA, 0.05, 0.05, 0.05, 0.05, 0.1, 0.05, 0.1, 0.05, 0.95, 0.95, 
0.95, 0.95, 0.95, 0.95, 0.95, 0.01, NA, 0.01, NA, NA, NA, NA, 
0.05, NA, NA, NA, NA, NA, 0.1, 0.6, 0.1, NA, NA), h_s1 = c(NA, 
NA, NA, NA, NA, NA, NA, 300, 250, NA, NA, NA, 270, 270, 250, 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
NA, NA, NA, NA, NA, NA, NA, NA, NA), b_s1 = c(NA, NA, NA, NA, 
NA, NA, NA, 0.7, 0.6, NA, NA, NA, 0.75, 0.75, 0.75, NA, NA, NA, 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
NA, NA, NA, NA, NA, NA)), .Names = c("X", "Z", "b_ml", "h_kl1", 
"b_kl1", "h_kl2", "b_kl2", "h_s1", "b_s1"), class = "data.frame", row.names = 40:79)

我尝试使用 geom_line 和 geom_pointrange 绘制它们,使用密度作为 alpha,但这看起来不太好:

#set the terrein heigth
ld <- 2
p <- ggplot(df, aes(x=X,y=Z)) + geom_line()

#add the vegetation layers
p + geom_line(aes(x=X,y=Z+0.02, alpha = b_ml), size = ld, color = "darkgreen") + 
    geom_line(aes(x=X,y=Z+h_kl1/100, alpha = b_kl1), size = ld, color = "green") +  #divide by 100 because z is in meters and h in cm
    geom_line(aes(x=X,y=Z+h_kl2/100, alpha = b_kl2), size = ld, color = "green") +
    geom_line(aes(x=X,y=Z+h_s1/100, alpha = b_s1), size = ld, color = "brown") +
  theme_bw()

#add the vegetation layers with pointrange
p + geom_pointrange(aes(x = X, ymin = Z, ymax=Z+0.03, alpha = b_ml), color = "darkgreen") + 
  geom_pointrange(aes(x = X, ymin = Z+0.03, ymax=Z+h_kl1/100, alpha = b_kl1), color = "green") + 
  geom_pointrange(aes(x = X, ymin = Z+h_kl1/100, ymax=Z+h_kl2/100, alpha = b_kl2), color = "green") +
  geom_pointrange(aes(x = X, ymin = Z+h_kl2/100, ymax=Z+h_s1/100, alpha = b_s1), color = "brown") +
  theme_bw()

我想我想制作一个更好看的图,点的密度代表图层的密度。就像这张来自 Nature 的图片:

本质上,两层之间的区域是用点填充的,点的数量取决于密度/覆盖率。
但我有点不知道如何到达那里。我也考虑过“geom_point”和“geom_dotplot”,但这包括手动计算点。

关于如何实现这一目标的任何建议?例如。使用哪个几何图形(抖动?),或者如何重构我的数据?

【问题讨论】:

  • 我将假设您的问题不是“我希望它看起来不错”,而是“我如何到达那个自然情节”。在这种情况下,我的猜测是geom_point(但它还需要更多的数据点才能看起来像大自然)。这会让你更接近你想要的吗?
  • @RHA 我有点困惑。如果我想在我的情节中有一个点,我需要知道它的坐标。这意味着,我需要有数据。所以我需要与图中的点一样多的数据点。如果此数据不存在(因为每个高度只有一个数据点),则必须创建它,然后使用 jitter 例如(随机化它们的位置)和 geom_point。您必须使用密度来确定您需要的“人工数据”的数量。这会在您的原始点周围创建点云(您当然可以在空间中移动它......)。
  • 但是看看那个自然图,我不认为这些点仅仅意味着密度——它们也形成了图案,不是吗?
  • 这可能很难向非植被生态学家解释。在田间,不可能测量每一株植物或树枝的高度。因此,人们估计每层的密度和平均最大高度。用随机点表示这一点并不令人困惑,但实际上非常接近现实。自然图确实可能是用某种扫描技术制作的,我的数据不同。我只是把它作为我所追求的一个例子。
  • 如果你可以承认这让非植物生态学家感到困惑,想象一下神经科学家有多困惑 :)) 我想我终于得到了你需要的东西,但我和 @Axeman 在同一条船上关于为此目的的数据模拟。如果自然图是特定技术的结果,我会认为这是一个额外的反对理由 - 因为那时您将错误的想法放入观察者的脑海中(即,这些点对应于实际数据点,但它们并不对应) .我知道这不是我的领域。在进行编码之前请仔细考虑(以免浪费)。

标签: r ggplot2


【解决方案1】:

我认为您没有实际数据来创建一个图作为您的示例,仅仅是因为它们似乎有大量的数据点(个人观察?某种扫描技术?),而您只有密度估计。从中创建点似乎充其量是令人困惑的,并且可能具有误导性。如果您有计算这些密度的原始数据,那么也许情况就不同了。以下是您可以制作的一些绘图示例:

首先我以整齐的格式重新排列数据,这样事情就更有意义了:

library(dplyr)
library(tidyr)

densities <- df %>% 
  select(-h_kl1, -h_kl2, -h_s1) %>% 
  gather('type', 'density', b_ml, b_kl1, b_kl2, b_s1) %>% 
  mutate(type = substring(type, 3))
heights <- df %>% 
  select(-b_ml, -b_kl1, -b_kl2, -b_s1) %>% 
  gather('type', 'height', h_kl1, h_kl2, h_s1) %>% 
  mutate(type = substring(type, 3))
df2 <- left_join(densities, heights) %>% 
  mutate(height = ifelse(type == 'ml', 0.03, height / 100),
         type = factor(type, levels = c('s1', 'kl2', 'kl1', 'ml')))

尝试 1:

ggplot(df2, aes(X, Z)) +
  geom_line() +
  geom_linerange(aes(ymin = Z, ymax = Z + height, alpha = density, col = type), size = 4) +
  scale_alpha_continuous(range = c(0, 0.7))

一个问题是ml 几乎是不可见的,因为它的比例与其他比例不同。我们可以尝试躲避:

ggplot(df2, aes(X, Z)) +
  geom_line() +
  geom_linerange(aes(ymin = Z, ymax = Z + height, alpha = density, col = type), 
                 size = 2, position = position_dodge(1))

这没有多大帮助。也许刻面:

ggplot(df2, aes(X, Z)) +
  geom_line() +
  geom_linerange(aes(ymin = Z, ymax = Z + height, alpha = density, col = type), size = 4) +
  facet_wrap(~type)

最后一个选项:

ggplot(df2, aes(X, Z)) +
  geom_line() +
  geom_point(aes(y = Z + height, size = density, col = type), alpha = 0.6)

我认为这个非常清楚地显示了植被的趋势。我喜欢的是对不同的类别给予同等重视。

包括段:

ggplot(df2, aes(X, Z)) +
  geom_line() +
  geom_segment(aes(xend = X, yend = Z + height), alpha = 0.1) +
  geom_point(aes(y = Z + height, size = density, col = type), alpha = 0.8)

【讨论】:

  • 感谢您的努力,但这不是我所追求的。这些方面对我没有吸引力,因为这些层一起形成了一个结构,而图的总数将是原来的 4 倍。堆叠它们会是一个更好的选择,但仍然不理想。我认为 geom_point 与 jitter 是要走的路,根据密度复制点。午饭后我会试试的。
  • 堆叠会歪曲他们的身高。我恭敬地不同意变出数据是一件好事。
  • 是的,必须先减去前面的层。
  • @RHA 添加了一个附加选项。
  • 我没有考虑过这一点,一点也不差(这个想法+1)。我将继续寻找其他选择,但这是迄今为止最好的。
【解决方案2】:

我自己使用 geom_jitter 已经非常接近解决方案了。为了展示我想做的事情(并反驳完全没有根据的指责“虚构数据”和“将错误的想法放入观察者的头脑中”[原文如此]),我将在这里发布我的尝试:

#make a tidy data.frame (taken from @Axeman)
library(dplyr)
library(tidyr)

densities <- df %>% 
  select(-h_kl1, -h_kl2, -h_s1) %>% 
  gather('type', 'density', b_ml, b_kl1, b_kl2, b_s1) %>% 
  mutate(type = substring(type, 3))
heights <- df %>% 
  select(-b_ml, -b_kl1, -b_kl2, -b_s1) %>% 
  gather('type', 'height', h_kl1, h_kl2, h_s1) %>% 
  mutate(type = substring(type, 3))
df2 <- left_join(densities, heights) %>% 
  mutate(height = ifelse(type == 'ml', 0.03, height / 100),
         type = factor(type, levels = c('s1', 'kl2', 'kl1', 'ml')))

# repeat rows according to density
# multiply density by 100: 1% will be 10 dots, 100%, 1000 dots and NA -> 1 (jitter can't handle NA)
df2$repli <- df2$density*1000
df2$repli[is.na(df2$repli)] <- 1

df3 <- df2[rep(rownames(df2), df2$repli), ]

require(ggplot2)

p <- ggplot(df3, aes(x=X,y=Z)) + geom_line(size = 1.5, colour = "gray") + theme_bw()

p + #geom_line(aes(y = Z + height, col = type)) +
  geom_jitter(aes(y = Z + height/2, col = type), position = position_jitter(width = 1, height = df3$height), 
                size = 0.0001, alpha = 0.1 ) +
  scale_color_manual(values = c("brown", "#CCFF00", "#33CC00","#666600"))

它仍然不完美,因为有一些我不明白的警告信息,“抖动”和一些较小的问题之间存在重叠。但它接近我最初的想法:植被层的视觉表示,得到高度和密度。

从美学上看,我认为 Axemans 的“最后选择”更具吸引力。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 2020-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-19
    相关资源
    最近更新 更多