Как читать расширение файла .MAP в R? - PullRequest
1 голос
/ 05 мая 2020

Есть ли простой способ прочитать файл с расширением .MAP в R? Я попробовал несколько вариантов ниже, но безуспешно. Вот файл .MAP для воспроизводимого примера .

context : по какой-то странной причине пространственное регионализация, используемое в политике планирования здравоохранения в Бразилии, доступно только в этом формате. Я хотел бы преобразовать его в geopackage, чтобы мы могли добавить его в пакет geobr .

# none of these options work
mp <- sf::st_read("./se_mapas_2013/se_regsaud.MAP")
mp <- rgdal::readGDAL("./se_mapas_2013/se_regsaud.MAP")
mp <- rgdal::readOGR("./se_mapas_2013/se_regsaud.MAP")
mp <- raster::raster("./se_mapas_2013/se_regsaud.MAP")
mp <- stars::read_stars("./se_mapas_2013/se_regsaud.MAP")

ps. есть аналогичный вопрос по SO, ориентированный на Python, к сожалению, без ответа

ОБНОВЛЕНИЕ

Мы нашли публикацию , в которой используется настраиваемая функция который читает файл .MAP. См. Пример ниже. Однако он возвращает объект "polylist". Есть ли простой способ преобразовать его в simple feature?

исходную пользовательскую функцию

read.map = function(filename){
  zz=file(filename,"rb")
  #
  # header of .map
  #
  versao = readBin(zz,"integer",1,size=2)  # 100 = versao 1.00
  #Bounding Box
  Leste = readBin(zz,"numeric",1,size=4)
  Norte = readBin(zz,"numeric",1,size=4)
  Oeste = readBin(zz,"numeric",1,size=4)
  Sul   = readBin(zz,"numeric",1,size=4)

  geocodigo = ""
  nome = ""
  xleg = 0
  yleg = 0
  sede = FALSE
  poli = list()
  i = 0

  #
  # repeat of each object in file
  #
  repeat{  
    tipoobj = readBin(zz,"integer",1,size=1) # 0=Poligono, 1=PoligonoComSede, 2=Linha, 3=Ponto

    if (length(tipoobj) == 0) break
    i = i + 1

    Len = readBin(zz,"integer",1,size=1)  # length byte da string Pascal
    geocodigo[i] = readChar(zz,10)
    Len = readBin(zz,"integer",1,size=1)  # length byte da string Pascal
    nome[i] = substr(readChar(zz,25),1,Len)
    xleg[i] = readBin(zz,"numeric",1,size=4)
    yleg[i] = readBin(zz,"numeric",1,size=4)
    numpontos = readBin(zz,"integer",1,size=2)

    sede = sede || (tipoobj = 1)

    x=0
    y=0   
    for (j in 1:numpontos){
      x[j] = readBin(zz,"numeric",1,size=4)
      y[j] = readBin(zz,"numeric",1,size=4)
    }


    # separate polygons
    xInic = x[1]
    yInic = y[1]  
    for (j in 2:numpontos){
      if (x[j] == xInic & y[j] == yInic) {x[j]=NA; y[j] = NA}
    }

    poli[[i]] = c(x,y)
    dim(poli[[i]]) = c(numpontos,2)
  }

  class(poli) = "polylist"
  attr(poli,"region.id") = geocodigo
  attr(poli,"region.name") = nome
  attr(poli,"centroid") = list(x=xleg,y=yleg)
  attr(poli,"sede") = sede
  attr(poli,"maplim") = list(x=c(Oeste,Leste),y=c(Sul,Norte))

  close(zz)
  return(poli)
}

с использованием исходной пользовательской функции

mp <- read.map("./se_mapas_2013/se_regsaud.MAP")

class(mp)
>[1] "polylist"

# plot
plot(attributes(mp)$maplim, type='n', asp=1, xlab=NA, ylab=NA)
title('Map')
lapply(mp, polygon, asp=T, col=3)

enter image description here

Ответы [ 2 ]

3 голосов
/ 06 мая 2020

Проблемы были: использование readChar с завершающими нулевыми байтами - изменено на readBin(); 8-битные символы, которые rawToChar() не принимает (в моей системе UTF-8); несколько осколков в некоторых файлах, которые нужно было удалить; и некоторые другие. Я добавил отредактированную функцию read.map() выше в maptools , но с другим именем и не экспортировал. Итак, теперь (с maptools rev 370 из https://r-forge.r-project.org/R/?group_id=943 по завершении сборки):

library(maptools)
o <- maptools:::readMAP2polylist("se_regsaud.MAP")
oo <- maptools:::.makePolylistValid(o)
ooo <- maptools:::.polylist2SpP(oo, tol=.Machine$double.eps^(1/4))
rn <- row.names(ooo)
df <- data.frame(ID=rn, row.names=rn, stringsAsFactors=FALSE)
res <- SpatialPolygonsDataFrame(ooo, data=df)
library(sf)
res_sf <- st_as_sf(res)
res_sf
plot(st_geometry(res_sf))

enter image description here

В этом подходе повторно используется код maptools , созданный почти двадцать лет назад, с небольшими правками для обработки последующих изменений при чтении двоичных файлов и исправления осколков.

2 голосов
/ 06 мая 2020

EDIT: похоже, что это работает не для всех файлов, поэтому правильное преобразование в sf потребует более глубокого изучения.

Вот быстрый удар по воскрешению. Было бы неправильно проводить кумулятивное суммирование для получения многострочных строк, я тестировал с se_municip.MAP, и в нем были только NA в качестве замыкающей строки каждого кольца. Если у него потенциально есть несвязанные множественные кольца (мультиполигон), то этот подход не будет работать полностью.

x <- read.map("se_municip.MAP")
df <- setNames(as.data.frame(do.call(rbind, x)), c("x", "y"))
df$region.name <- rep(attr(x, "region.name"), unlist(lapply(x, nrow)))
## in case there are multi-rings
df$linestring_id <- cumsum(c(0, diff(is.na(df$x)))) 
df$polygon_id <- as.integer(factor(df$region.name))
df <- df[!is.na(df$x), ]
sfx <- sfheaders::sf_polygon(df, x = "x", y = "y", linestring_id = "linestring_id", polygon_id = "polygon_id", keep = TRUE)
#sf::st_crs(sfx) <- sf::st_crs(<whatever it is probably 4326>)

plot(sf::st_geometry(sfx), reset = FALSE)
maps::map(add = TRUE)

Интересно, что вы наткнулись на официальную версию забытого наследия!

(Кстати, могу ли я опубликовать sh наборы данных в пакете?)

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...