【问题标题】:how to display a projected map on an R::lattice::layerplot?如何在 R::lattice::layerplot 上显示投影地图?
【发布时间】:2013-01-29 16:54:54
【问题描述】:

总结:我可以在lattice::layerplot 上显示经纬度图,我可以在spam::image 上显示兰伯特保角圆锥 (LCC) 地图。如何在lattice::layerplot 上显示 LCC 地图?以下是如何不执行此操作的示例——感谢您提供修复帮助(甚至只是调试)。

详情:

我一直在使用格子图形(通过latticeExtrarasterVis)成功地显示未投影的经纬度全球大气数据,效果很好(尽管我肯定对ggplot/ggmap 很感兴趣) .特别是,我可以用地图覆盖这些地块,这对于我正在做的工作来说是必不可少的。但是,我目前无法将 lattice::layerplot 用于某些 区域 数据投影 LCC:数据绘图,但我无法获得要叠加的地图。我可以通过更粗略的方式做到这一点,但更愿意知道如何在lattice/rasterVis 或类似的方式(例如ggplot/ggmap)中做到这一点。下面是两个几乎独立的示例……但是如果您已经知道如何执行此操作,请告诉我,我将跳过调试。 (我在一个项目上落后了。)

netCDF 数据 ozone_lcc.nc 附带 CRAN package=M3 ... 除了 M3 提供它

system.file("extdata/ozone_lcc.ncf", package="M3")

并且该文件扩展名 (.ncf) 当前会导致 CRAN package=raster 出现问题(请参阅 this post)。您可以重命名该文件(并将其放入当前工作目录),或者您可以下载just that file (270 kB),或者您可以从M3 tarball 获取它(但记得重命名它!)。

然后,您可以运行以下任何示例(前提是 (IIRC) 您没有运行 Windows,package=M3 不会在其上构建(但 ICBW)),根据需要更改常量以适应您的系统。示例 1 生成我知道(根据以前的经验)将与 levelplot 中的 raster 一起使用的类型的映射;但是,在这种情况下,地图和数据/栅格的坐标值不匹配。示例 2 使用旧式基本图形,实际上绘制了数据和地图;不幸的是,我不知道如何制作它在levelplot 上生成的那种地图。因为我想让这段代码与使用rasterlevelplot 的其他代码一起工作,所以这是个问题。

示例 1: 产生类似

的输出
##### start example 1 #####

library("M3")        # http://cran.r-project.org/web/packages/M3/
library("rasterVis") # http://cran.r-project.org/web/packages/rasterVis/

## Use an example file with projection=Lambert conformal conic.
# lcc.file <- system.file("extdata/ozone_lcc.ncf", package="M3")
lcc.file <- "./ozone_lcc.nc" # unfortunate problem with raster::raster
lcc.proj4 <- M3::get.proj.info.M3(lcc.file)
lcc.proj4   # debugging
# [1] "+proj=lcc +lat_1=33 +lat_2=45 +lat_0=40 +lon_0=-97 +a=6370000 +b=6370000"
# Note +lat_0=40 +lat_1=33 +lat_2=45 for maps::map@projection (below)
lcc.crs <- sp::CRS(lcc.proj4)
lcc.pdf <- "./ozone_lcc.example1.pdf" # for output

## Read in variable with daily ozone.
# o3.raster <- raster::raster(x=lcc.file, varname="O3", crs=lcc.crs)
# ozone_lcc.nc has 4 timesteps, choose 1 at random
o3.raster <- raster::raster(x=lcc.file, varname="O3", crs=lcc.crs, level=1)
o3.raster@crs <- lcc.crs # why does the above assignment not take?
# start debugging
o3.raster
summary(coordinates(o3.raster)) # thanks, Felix Andrews!
M3::get.grid.info.M3(lcc.file)
#   end debugging

# > o3.raster
# class       : RasterLayer 
# band        : 1 
# dimensions  : 112, 148, 16576  (nrow, ncol, ncell)
# resolution  : 1, 1  (x, y)
# extent      : 0.5, 148.5, 0.5, 112.5  (xmin, xmax, ymin, ymax)
# coord. ref. : +proj=lcc +lat_1=33 +lat_2=45 +lat_0=40 +lon_0=-97 +a=6370000 +b=6370000 
# data source : .../ozone_lcc.nc 
# names       : O3 
# z-value     : 1 
# zvar        : O3 
# level       : 1 
# > summary(coordinates(o3.raster))
#        x                y         
#  Min.   :  1.00   Min.   :  1.00  
#  1st Qu.: 37.75   1st Qu.: 28.75  
#  Median : 74.50   Median : 56.50  
#  Mean   : 74.50   Mean   : 56.50  
#  3rd Qu.:111.25   3rd Qu.: 84.25  
#  Max.   :148.00   Max.   :112.00  
# > M3::get.grid.info.M3(lcc.file)
# $x.orig
# [1] -2736000
# $y.orig
# [1] -2088000
# $x.cell.width
# [1] 36000
# $y.cell.width
# [1] 36000
# $hz.units
# [1] "m"
# $ncols
# [1] 148
# $nrows
# [1] 112
# $nlays
# [1] 1

# The grid (`coordinates(o3.raster)`) is integers, because this
# data is stored using the IOAPI convention. IOAPI makes the grid
# Cartesian by using an (approximately) equiareal projection (LCC)
# and abstracting grid positioning to metadata stored in netCDF
# global attributes. Some of this spatial metadata can be accessed
# by `M3::get.grid.info.M3` (above), and some can be accessed via
# the coordinate reference system (`CRS`, see `lcc.proj4` above)

## Get US state boundaries in projection units.
state.map <- maps::map(
  database="state", projection="lambert", par=c(33,45), plot=FALSE)
#                  parameters to lambert: ^^^^^^^^^^^^
#                  see mapproj::mapproject
state.map.shp <-
  maptools::map2SpatialLines(state.map, proj4string=lcc.crs)
# start debugging
# thanks, Felix Andrews!
class(state.map.shp)
summary(do.call("rbind",
  unlist(coordinates(state.map.shp), recursive=FALSE)))
#   end debugging

# > class(state.map.shp)
# [1] "SpatialLines"
# attr(,"package")
# [1] "sp"
# >     summary(do.call("rbind", 
# +       unlist(coordinates(state.map.shp), recursive=FALSE)))
#        V1                  V2         
#  Min.   :-0.234093   Min.   :-0.9169  
#  1st Qu.:-0.000333   1st Qu.:-0.8289  
#  Median : 0.080378   Median :-0.7660  
#  Mean   : 0.058492   Mean   :-0.7711  
#  3rd Qu.: 0.162993   3rd Qu.:-0.7116  
#  Max.   : 0.221294   Max.   :-0.6343  
# I can't see how to relate these coordinates to `coordinates(o3.raster)`

pdf(file=lcc.pdf)
rasterVis::levelplot(o3.raster, margin=FALSE
) + latticeExtra::layer(
  sp::sp.lines(state.map.shp, lwd=0.8, col='darkgray'))

dev.off()
# change this for viewing PDF on your system
system(sprintf("xpdf %s", lcc.pdf))
# data looks correct, map invisible

## Try again, with lambert(40,33)
state.map <- maps::map(
  database="state", projection="lambert", par=c(40,33), plot=FALSE)
#                  parameters to lambert: ^^^^^^^^^^^^
#                  see mapproj::mapproject
state.map.shp <-
  maptools::map2SpatialLines(state.map, proj4string=lcc.crs)
# start debugging
summary(do.call("rbind", 
  unlist(coordinates(state.map.shp), recursive=FALSE)))
#   end debugging

# >     summary(do.call("rbind", 
# +       unlist(coordinates(state.map.shp), recursive=FALSE)))
#        V1                  V2         
#  Min.   :-0.2226344   Min.   :-0.9124  
#  1st Qu.:-0.0003149   1st Qu.:-0.8295  
#  Median : 0.0763322   Median :-0.7706  
#  Mean   : 0.0553948   Mean   :-0.7752  
#  3rd Qu.: 0.1546465   3rd Qu.:-0.7190  
#  Max.   : 0.2112617   Max.   :-0.6458  
# no real change from previous `coordinates(state.map.shp)`

pdf(file=lcc.pdf)
rasterVis::levelplot(o3.raster, margin=FALSE
) + latticeExtra::layer(
  sp::sp.lines(state.map.shp, lwd=0.8, col='darkgray'))

dev.off()
system(sprintf("xpdf %s", lcc.pdf))
# as expected, same as before: data looks correct, map invisible

#####   end example 1 #####

示例 2: 产生类似

的输出
##### start example 2 #####

# Following adapted from what is installed in my
# .../R/x86_64-pc-linux-gnu-library/2.14/m3AqfigExampleScript.r
# (probably by my sysadmin), which also greatly resembles
# https://wiki.epa.gov/amad/index.php/R_packages_developed_in_AMAD
# which is behind a firewall :-(

## EXAMPLE WITH LAMBERT CONIC CONFORMAL FILE.

library("M3")
library("aqfig") # http://cran.r-project.org/web/packages/aqfig/

## Use an example file with LCC projection: either local download ...
lcc.file <- "./ozone_lcc.nc"
## ... or as installed by package=M3:
# lcc.file <- system.file("extdata/ozone_lcc.ncf", package="M3")
## Choose the one that works for you.
lcc.pdf <- "./ozone_lcc.example2.pdf" # for output

##  READ AND PLOT OZONE FROM FILE WITH LCC PROJECTION.

## Read in variable with daily ozone. Note that we can give dates
## rather than date-times, and that will include all time steps
## anytime during those days.  Or, we can give lower and upper bounds
## and all time steps between these will be taken.
o3 <- M3::get.M3.var(
  file=lcc.file, var="O3", hz.units="m",
  ldatetime=as.Date("2001-07-01"), udatetime=as.Date("2001-07-04"))
# start debugging
class(o3)
summary(o3)
summary(o3$x.cell.ctr)
#   end debugging

# > class(o3)
# [1] "list"
# > summary(o3)
#            Length Class   Mode     
# data       66304  -none-  numeric  
# data.units     1  -none-  character
# x.cell.ctr   148  -none-  numeric  
# y.cell.ctr   112  -none-  numeric  
# hz.units       1  -none-  character
# rows         112  -none-  numeric  
# cols         148  -none-  numeric  
# layers         1  -none-  numeric  
# datetime       4  POSIXct numeric  
# > summary(o3$x.cell.ctr)
#     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
# -2718000 -1395000   -72000   -72000  1251000  2574000 

# Note how these grid coordinates relate to the IOAPI metadata above:
# min(o3$x.cell.ctr)      == -2718000
# == -2736000 + (36000/2) == x.orig + (x.cell.width/2)

## Get colors and map boundaries for plot.
library("fields")
col.rng <- tim.colors(20)
detach("package:fields")

## Get state boundaries in projection units.
map.lines <- M3::get.map.lines.M3.proj(
  file=lcc.file, database="state", units="m")
# start debugging
class(map.lines)
summary(map.lines)
summary(map.lines$coords)
#   end debugging

# >     class(map.lines)
# [1] "list"
# >     summary(map.lines)
#        Length Class  Mode     
# coords 23374  -none- numeric  
# units      1  -none- character
# >     summary(map.lines$coords)
#        x                  y           
#  Min.   :-2272238   Min.   :-1567156  
#  1st Qu.:   94244   1st Qu.: -673953  
#  Median :  913204   Median :  -26948  
#  Mean   :  689997   Mean   :  -84644  
#  3rd Qu.: 1744969   3rd Qu.:  524531  
#  Max.   : 2322260   Max.   : 1265778  
#  NA's   :168        NA's   :168       

## Set color boundaries to encompass the complete data range.
z.rng <- range(as.vector(o3$data))

## Make a color tile plot of the ozone for the first day (2001-07-01).
pdf(file=lcc.pdf)
image(o3$x.cell.ctr, o3$y.cell.ctr, o3$data[,,1,1],
      col=col.rng, zlim=z.rng,
      xlab="x-coord (m)", ylab="y-coord (m)")

## Put date-time string and chemical name (O3) into a format I can use
## to label the actual figure.
date.str <- format(o3$datetime[1], "%Y-%m-%d")
title(main=bquote(paste(O[3], " on ", .(date.str), sep="")))

## Put the state boundaries on the plot.
lines(map.lines$coords)

## Add legend to right of plot. NOTE: YOU CANNOT ADD TO THE PLOT
## AFTER USING vertical.image.legend(). Before making a new plot,
## open a new device or turn this device off.
vertical.image.legend(zlim=z.rng, col=col.rng)

dev.off() # close the plot if you haven't already, ...
# ... and change the following to display PDFs on your system.
system(sprintf("xpdf %s", lcc.pdf))
# data displays with state map

#####   end example 2 #####

但我看不出如何从M3::get.map.lines.M3.proj 返回的简单矩阵(等,但不多)到sp::sp.lines 想要的SpatialLines,更不用说latticeExtra::layer 想要的任何东西。 (我是一个新手,发现格子文档相当难以理解。)此外,我更愿意避免手动进行上面的 IOAPI 转换(尽管我当然更愿意这样做而不是跳过旧式图形的箍)。

【问题讨论】:

    标签: r plot maps lattice netcdf


    【解决方案1】:

    一种方法虽然丑陋,但使用线性 IOAPI 变换“修复”从maps::map 获得的state.map 中的坐标。例如,

    示例 3: 产生类似

    的输出
    ##### start example 3 #####
    
    library("M3")        # http://cran.r-project.org/web/packages/M3/
    library("rasterVis") # http://cran.r-project.org/web/packages/rasterVis/
    
    ## Use an example file with projection=Lambert conformal conic.
    # lcc.file <- system.file("extdata/ozone_lcc.ncf", package="M3")
    # See notes in question regarding unfortunate problem with raster::raster,
    # and remember to download or rename the file (symlinking alone will not work).
    lcc.file <- "./ozone_lcc.nc"
    
    lcc.proj4 <- M3::get.proj.info.M3(lcc.file)
    lcc.proj4   # debugging
    # [1] "+proj=lcc +lat_1=33 +lat_2=45 +lat_0=40 +lon_0=-97 +a=6370000 +b=6370000"
    # Note +lat_0=40 +lat_1=33 +lat_2=45 for maps::map@projection (below)
    lcc.crs <- sp::CRS(lcc.proj4)
    lcc.pdf <- "./ozone_lcc.example3.pdf" # for output
    
    ## Read in variable with daily ozone.
    # o3.raster <- raster::raster(x=lcc.file, varname="O3", crs=lcc.crs)
    # ozone_lcc.nc has 4 timesteps, choose 1 at random
    o3.raster <- raster::raster(x=lcc.file, varname="O3", crs=lcc.crs, level=1)
    o3.raster@crs <- lcc.crs # why does the above assignment not take?
    # start debugging
    o3.raster
    summary(coordinates(o3.raster)) # thanks, Felix Andrews!
    M3::get.grid.info.M3(lcc.file)
    #   end debugging
    
    # > o3.raster
    # class       : RasterLayer 
    # band        : 1 
    # dimensions  : 112, 148, 16576  (nrow, ncol, ncell)
    # resolution  : 1, 1  (x, y)
    # extent      : 0.5, 148.5, 0.5, 112.5  (xmin, xmax, ymin, ymax)
    # coord. ref. : +proj=lcc +lat_1=33 +lat_2=45 +lat_0=40 +lon_0=-97 +a=6370000 +b=6370000 
    # data source : .../ozone_lcc.nc 
    # names       : O3 
    # z-value     : 1 
    # zvar        : O3 
    # level       : 1 
    
    # > summary(coordinates(o3.raster))
    #        x                y         
    #  Min.   :  1.00   Min.   :  1.00  
    #  1st Qu.: 37.75   1st Qu.: 28.75  
    #  Median : 74.50   Median : 56.50  
    #  Mean   : 74.50   Mean   : 56.50  
    #  3rd Qu.:111.25   3rd Qu.: 84.25  
    #  Max.   :148.00   Max.   :112.00  
    
    # > M3::get.grid.info.M3(lcc.file)
    # $x.orig
    # [1] -2736000
    # $y.orig
    # [1] -2088000
    # $x.cell.width
    # [1] 36000
    # $y.cell.width
    # [1] 36000
    # $hz.units
    # [1] "m"
    # $ncols
    # [1] 148
    # $nrows
    # [1] 112
    # $nlays
    # [1] 1
    
    # The grid (`coordinates(o3.raster)`) is integers, because this
    # data is stored using the IOAPI convention. IOAPI makes the grid
    # Cartesian by using an (approximately) equiareal projection (LCC)
    # and abstracting grid positioning to metadata stored in netCDF
    # global attributes. Some of this spatial metadata can be accessed
    # by `M3::get.grid.info.M3` (above), and some can be accessed via
    # the coordinate reference system (`CRS`, see `lcc.proj4` above)
    
    ## Get US state boundaries in projection units.
    state.map <- maps::map(
      database="state", projection="lambert", par=c(33,45), plot=FALSE)
    #                  parameters to lambert: ^^^^^^^^^^^^
    #                  see mapproj::mapproject
    
    # replace its coordinates with
    metadata.coords.IOAPI.list <- M3::get.grid.info.M3(lcc.file)
    metadata.coords.IOAPI.x.orig <- metadata.coords.IOAPI.list$x.orig
    metadata.coords.IOAPI.y.orig <- metadata.coords.IOAPI.list$y.orig
    metadata.coords.IOAPI.x.cell.width <- metadata.coords.IOAPI.list$x.cell.width
    metadata.coords.IOAPI.y.cell.width <- metadata.coords.IOAPI.list$y.cell.width
    map.lines <- M3::get.map.lines.M3.proj(
      file=lcc.file, database="state", units="m")
    map.lines.coords.IOAPI.x <-
      (map.lines$coords[,1] - metadata.coords.IOAPI.x.orig)/metadata.coords.IOAPI.x.cell.width
    map.lines.coords.IOAPI.y <-
      (map.lines$coords[,2] - metadata.coords.IOAPI.y.orig)/metadata.coords.IOAPI.y.cell.width
    map.lines.coords.IOAPI <- 
      cbind(map.lines.coords.IOAPI.x, map.lines.coords.IOAPI.y)
    # start debugging
    class(map.lines.coords.IOAPI)
    summary(map.lines.coords.IOAPI)
    #   end debugging
    
    # >     class(map.lines.coords.IOAPI)
    # [1] "matrix"
    # >     summary(map.lines.coords.IOAPI)
    #  map.lines.coords.IOAPI.x map.lines.coords.IOAPI.y
    #  Min.   : 12.88           Min.   :14.47           
    #  1st Qu.: 78.62           1st Qu.:39.28           
    #  Median :101.37           Median :57.25           
    #  Mean   : 95.17           Mean   :55.65           
    #  3rd Qu.:124.47           3rd Qu.:72.57           
    #  Max.   :140.51           Max.   :93.16           
    #  NA's   :168              NA's   :168        
    
    coordinates(state.map.shp) <- map.lines.coords.IOAPI # FAIL:
    > Error in `coordinates<-`(`*tmp*`, value = c(99.0242231482288, 99.1277727928691,  : 
    >   setting coordinates cannot be done on Spatial objects, where they have already been set
    
    state.map.IOAPI <- state.map # copy
    state.map.IOAPI$x <- map.lines.coords.IOAPI.x
    state.map.IOAPI$y <- map.lines.coords.IOAPI.y
    state.map.IOAPI$range <- c(
      min(map.lines.coords.IOAPI.x),
      max(map.lines.coords.IOAPI.x),
      min(map.lines.coords.IOAPI.y),
      max(map.lines.coords.IOAPI.y))
    state.map.IOAPI.shp <-
      maptools::map2SpatialLines(state.map.IOAPI, proj4string=lcc.crs)
    # start debugging
    # thanks, Felix Andrews!
    class(state.map.IOAPI.shp)
    summary(do.call("rbind",
      unlist(coordinates(state.map.IOAPI.shp), recursive=FALSE)))
    #   end debugging
    
    # > class(state.map.IOAPI.shp)
    # [1] "SpatialLines"
    # attr(,"package")
    # [1] "sp"
    
    # > summary(do.call("rbind",
    # +   unlist(coordinates(state.map.IOAPI.shp), recursive=FALSE)))
    #        V1               V2       
    #  Min.   : 12.88   Min.   :14.47  
    #  1st Qu.: 78.62   1st Qu.:39.28  
    #  Median :101.37   Median :57.25  
    #  Mean   : 95.17   Mean   :55.65  
    #  3rd Qu.:124.47   3rd Qu.:72.57  
    #  Max.   :140.51   Max.   :93.16  
    
    pdf(file=lcc.pdf)
    rasterVis::levelplot(o3.raster, margin=FALSE
    ) + latticeExtra::layer(
      sp::sp.lines(state.map.IOAPI.shp, lwd=0.8, col='darkgray'))
    dev.off()
    # change this for viewing PDF on your system
    system(sprintf("xpdf %s", lcc.pdf))
    
    #####   end example 3 #####
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-03
      • 2017-07-24
      • 2013-09-14
      • 2019-07-01
      • 2019-05-22
      • 2016-08-21
      • 2012-06-08
      • 2013-08-24
      相关资源
      最近更新 更多