简体   繁体   English

R —将递归划分的区域转换为ggplot2氯盐的XY坐标

[英]R — Translating recursively divided areas into XY coordinates for ggplot2 chloropleth

I've worked out a solution for this but it's ugly, ad hoc and ungeneralizable; 我已经为此解决了一个问题,但是它是丑陋的,临时的并且无法概括。 I assume there has to be a better way. 我认为必须有更好的方法。 Our study area is divided into a grid of 100mx100m blocks, columns named 3-8 and rows named CJ. 我们的研究区域分为100mx100m的网格,名为3-8的列和名为CJ的行。 Each block is divided into four quadrats and each quadrat into four subquadrats, so a subquad name would be something like '4F23'; 每个块分为四个四边形,每个四边形分为四个子四角形,因此子四角形的名称类似于“ 4F23”。 the division pattern looks like this: 划分模式如下所示:

11 12 21 22 11 12 21 22

13 14 23 24 13 14 23 24

31 32 41 42 31 32 41 42

33 34 43 44 33 34 43 44

Different datasets use whichever of the three resolutions is appropriate so I want something that can deal with '4F', '4F1' and '4F34'. 不同的数据集使用这三种分辨率中的任意一种都是合适的,因此我希望可以处理“ 4F”,“ 4F1”和“ 4F34”。 To show values in a heatmap/chloropleth of the area I need a way to represent that nested scheme more orthogonally to ggplot -- or better, to tell ggplot something so it knows how to interpret the section labels itself. 为了在该区域的热图/叶绿素中显示值,我需要一种方法来表示该嵌套方案与ggplot更正交-或者更好地告诉ggplot某些信息,以便它知道如何解释部分标签本身。 What I want is a simple way to plot the map of any of our studies. 我想要的是一种简单的方法来绘制我们所有研究的地图。 The best I could come up with was using a translation function to generate XYs and bind those to the dataframe. 我能想到的最好的方法是使用转换函数生成XY,并将其绑定到数据框。

toyDF <- tibble(SECT = c('3E1', '5G3', '8H4'), HT = c(22,6,15))
# Translator function
SACoords <- function(sqr) {
    sqVec <- substring(sqr, seq(1, nchar(sqr), 1), seq(1, nchar(sqr), 1))
    rws <- 'JIHGFEDC'
    cl <- (as.integer(sqVec[1]) - 3) * 100
    rw <- (as.integer(gregexpr(sqVec[2], rws)) - 1) * 100
    qd <- ifelse(!is.na(sqVec[3]), 
        list(c(0,50), c(50,50), c(0,0), c(50,0))[as.integer(sqVec[3])],
        c(0,0))
    sq <- ifelse(!is.na(sqVec[4]), 
        list(c(0,25), c(25,25), c(0,0), c(25,0))[as.integer(sqVec[4])],
        c(0,0))
    coords <- data.frame(c(cl, rw), qd, sq)
    rowSums(coords, na.rm=TRUE)
}
#> SACoords('8C24')  # Test
#[1] 575 750  # Yes

# Mash in the coordinates (as lists)
toyXY <- toyDF %>% 
    mutate(coords = sapply(SECT, SACoords, simplify=FALSE))
# Got the coords in, but as lists -- difficult to work with;
# but can't mutate() into two columns with one operation, so
# redo it this ungainly way:
toyXY[,4:5] <- matrix(unlist(sapply(toyDF$SECT, SACoords)), 
    ncol=2, byrow=TRUE)
names(toyXY)[4:5] <- c('Xcoor', 'Ycoor')

# And finally to plot (in reality many observations per SECT)
toyXY %>% group_by(SECT) %>%
    mutate(MHT = mean(HT)) %>%
    ggplot(aes(xmin=Xcoor, xmax=Xcoor + 50, ymin=Ycoor, ymax=Ycoor+50)) +
        geom_rect(aes(fill = MHT))

With a full dataset this produces exactly what I want but it's terrible. 有了完整的数据集,就可以产生我想要的东西,但是非常糟糕。 What I'd like best (I think) is for my SACoords() to be a transformation that I can plug into the ggplot(aes()) call so it will effectively understand the SECT labels, hopefully allowing me to use geom_raster instead of geom_rect and avoid the xmin/xmax and its awkward constants that have to be adjusted depending on a given study's resolution. 我最想要的是(我认为)将SACoords()转换为可以插入ggplot(aes())调用的转换,这样它可以有效地理解SECT标签,希望可以让我使用geom_raster而不是geom_rect并避免必须根据给定研究的分辨率进行调整的xmin / xmax及其尴尬常数。 Next best might be a templated representation of the study map -- 2d matrix, 24x32? 次佳的可能是研究图的模板表示-2d矩阵,24x32? 6x8 matrix of lists of lists? 列表列表的6x8矩阵? -- but I don't know how to tell ggplot to read it. -但我不知道如何告诉ggplot读取它。 Or should I really just be wrapping all this up in a bigger function that can handle everything? 还是我真的应该将所有这些包装成一个可以处理所有事情的更大的功能?

It would be clearer if you included an illustration of your study area, but here's my best guess at what you are looking for. 如果您包括学习区域的图示,将会更加清楚,但是这是您所寻找的东西的最佳猜测。 If my understanding is correct, you can perform all the translations within dplyr package's pipe operations, which makes for easier interpretation of what's going on at each step in the code. 如果我的理解是正确的,那么您可以在dplyr软件包的管道操作中执行所有转换,这使对代码中每个步骤所发生的事情的解释更加容易。

Do note that I used different SECT values for illustration purpose. 请注意,出于说明目的,我使用了不同的SECT值。 Explanations in comments within: 注释中的解释:

library(dplyr)
library(ggplot2)

# modify toyDF to include sections of different sizes
toyDF <- tibble::tibble(SECT = c("3E", "5G3", "8C24"), 
                HT = c(22, 6, 15))

toyDF %>%
  mutate(sqr = stringr::str_pad(SECT, 4, side = "right", pad = " ")) %>%
  tidyr::separate(sqr, into = c("x", "y", "quadrat", "subquadrat"), sep = 1:3) %>%

  # convert the first two letters of SECT into x/y coordinates for the centre of the area
  mutate(x = factor(x, levels = as.character(3:8)),
         y = factor(y, levels = LETTERS[10:3])) %>%
  mutate_at(vars(x, y),
            function(i) as.integer(i) * 100 - 50) %>%

  # adjust coordinates for quadrat, if applicable
  mutate(x = case_when(quadrat %in% c("1", "3") ~ x - 25,
                       quadrat %in% c("2", "4") ~ x + 25,
                       TRUE ~ x),
         y = case_when(quadrat %in% c("1", "2") ~ y + 25,
                       quadrat %in% c("3", "4") ~ y - 25,
                       TRUE ~ y)) %>%

  # further adjust coordinates for subquadrat, if applicable
  mutate(x = case_when(subquadrat %in% c("1", "3") ~ x - 12.5,
                       subquadrat %in% c("2", "4") ~ x + 12.5,
                       TRUE ~ x),
         y = case_when(subquadrat %in% c("1", "2") ~ y + 12.5,
                       subquadrat %in% c("3", "4") ~ y - 12.5,
                       TRUE ~ y)) %>%

  # specify appropriate width for each cell, depending on whether
  # subquadrat / quadrat has been defined
  mutate(width = case_when(subquadrat != " " ~ 25,
                           quadrat != " " ~ 50,
                           TRUE ~ 100)) %>%

  ggplot(aes(x = x, y = y, fill = HT)) +
  geom_tile(aes(height = width, width = width)) +
  scale_x_continuous(breaks = seq(50, 550, by = 100),
                     labels = as.character(3:8),
                     expand = c(0, 0)) +
  scale_y_continuous(breaks = seq(50, 750, by = 100),
                     labels = LETTERS[10:3],
                     expand = c(0, 0)) +
  coord_equal(xlim = c(0, 600), ylim = c(0, 800)) +
  theme_bw() +
  theme(panel.grid.major = element_blank(),
        axis.ticks = element_blank())

情节

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM