readOGR(rgdal)无法从XML获取多边形名称

时间:2016-11-24 11:39:37

标签: r maps kml rgdal sp

我正在尝试使用包readOGR中的rgdal函数将英格兰的CCG边界的KML地图(Available here, 200Kb)导入到R中。我的最终目标是通过根据某些相关值对CCG着色来创建热图。我有一个列表,其中包含一个数据框中CCG名称旁边的值。我需要将该数据框中的CCG名称与导入的地图对象中的CCG名称相匹配,并根据该值指定颜色。但是,我看不到地图对象中导入的任何CCG名称,尽管它们存在于KML文件中。这就是我在做的事情:

library(sp)
library(rgdal)
library(maps)
library(maptools)

假设KML文件位于工作目录中。 列出图层:

ogrListLayers("Clinical_Commissioning_Groups_April_2016_Ultra_Generalised_Clipped_Boundaries_in_England.KML")

阅读OGRGeoJSON图层:

ccg_boundaries <- ReadOGR("Clinical_Commissioning_Groups_April_2016_Ultra_Generalised_Clipped_Boundaries_in_England.KML","OGRGeoJSON")

R Studio显示对象中有两个部分(右边的单词?)。

polygons,其中包含每个多边形的数据,例如对于第一个:

> ccg_boundaries@polygons[1]
[[1]]
An object of class "Polygons"
Slot "Polygons":
[[1]]
An object of class "Polygon"
Slot "labpt":
[1] -2.104671 54.040320
Slot "area":
[1] 0.168067
...

data,有两个变量(NameDescription),我希望它们包含CCG名称,但它是空的:

> ccg_boundaries@data
    Name Description
0                   
1                   
2                   
3                   
4                   
5         

然而,CCG名称存在于KML文件中,如果使用Word编辑器打开,可以看到,例如,按字母顺序排列的第一个是“NHS Airedale,Wharfedale和Craven”。

<PolyStyle><fill>0</fill></PolyStyle></Style>
    <ExtendedData><SchemaData schemaUrl="#OGRGeoJSON">
        <SimpleData name="objectid">1</SimpleData>
        <SimpleData name="ccg16cd">E38000001</SimpleData>
        <SimpleData name="ccg16nm">NHS Airedale, Wharfedale and Craven CCG</SimpleData>

是否可以选择readOGR或其他选项来提取它们并包含在对象中?

2 个答案:

答案 0 :(得分:1)

好的,如果有人遇到同样的问题,这就是我找到的解决方案。

网站以两种格式提供地图:KML and SHP。我之所以选择KML,是因为这是我所遵循的一个实际例子。但是这个特定的KML文件或其生成方式似乎存在问题。我使用Shapefile(SHP)尝试了这个过程,它就像一个魅力。

Shapefile可以通过相同的函数读入R,但不需要指定图层:

ccg_boundaries <- ReadOGR("Clinical_Commissioning_Groups_April_2016_Ultra_Generalised_Clipped_Boundaries_in_England.SHP")

CCG名称现在位于ccg16nm变量中:

> head(ccg_boundaries@data)
  objectid   ccg16cd                                 ccg16nm st_areasha st_lengths
0        1 E38000001 NHS Airedale, Wharfedale and Craven CCG 1224636590  193149.74
1        2 E38000002                         NHS Ashford CCG  582174805  122841.19
2        3 E38000003                  NHS Aylesbury Vale CCG  984352696  229544.11
3        4 E38000004            NHS Barking and Dagenham CCG   36315011   31196.87
4        5 E38000005                          NHS Barnet CCG   86654018   41833.69
5        6 E38000006                        NHS Barnsley CCG  327520495  106476.52

答案 1 :(得分:1)

您的问题是Windows没有必要的库来从KML中提取ExtendedData。
我在这里提供了一个可行的解决方案:https://stackoverflow.com/a/51657844/2763996

您的问题的解决方案是可以在示例KML上使用的以下功能:

library(tidyverse)
library(xml2)
library(rgdal)

readKML <- function(file,keep_name_description=FALSE,layer,...) {
  # Set keep_name_description = TRUE to keep "Name" and "Description" columns
  #   in the resulting SpatialPolygonsDataFrame. Only works when there is
  #   ExtendedData in the kml file.

  sp_obj<-readOGR(file,layer,...)
  xml1<-read_xml(file)
  if (!missing(layer)) {
    different_layers <- xml_find_all(xml1, ".//d1:Folder") 
    layer_names <- different_layers %>% 
      xml_find_first(".//d1:name") %>% 
      xml_contents() %>% 
      xml_text()

    selected_layer <- layer_names==layer
    if (!any(selected_layer)) stop("Layer does not exist.")
    xml2 <- different_layers[selected_layer]
  } else {
    xml2 <- xml1
  }

  # extract name and type of variables

  variable_names1 <- 
    xml_find_first(xml2, ".//d1:ExtendedData") %>% 
    xml_children() 

  while(variable_names1 %>% 
        xml_attr("name") %>% 
        is.na() %>% 
        any()&variable_names1 %>%
        xml_children() %>% 
        length>0) variable_names1 <- variable_names1 %>%
    xml_children()

  variable_names <- variable_names1 %>%
    xml_attr("name") %>% 
    unique()

  # return sp_obj if no ExtendedData is present
  if (is.null(variable_names)) return(sp_obj)

  data1 <- xml_find_all(xml2, ".//d1:ExtendedData") %>% 
    xml_children()

  while(data1 %>%
        xml_children() %>% 
        length>0) data1 <- data1 %>%
    xml_children()

  data <- data1 %>% 
    xml_text() %>% 
    matrix(.,ncol=length(variable_names),byrow = TRUE) %>% 
    as.data.frame()

  colnames(data) <- variable_names

  if (keep_name_description) {
    sp_obj@data <- data
  } else {
    try(sp_obj@data <- cbind(sp_obj@data,data),silent=TRUE)
  }
  sp_obj
}