Как правильно построить спроецированные данные с координатной сеткой в ​​ggplot2?

Я использовал ggplot2 для построения климатических данных с координатной сеткой в ​​течение многих лет. Обычно это проецируемые файлы NetCDF. Ячейки имеют квадратные координаты в координатах модели, но в зависимости от того, какую проекцию использует модель, в реальном мире может быть не так.

Мой обычный подход - сначала переназначить данные на подходящую регулярную сетку, а затем построить. Это приводит к небольшому изменению данных, обычно это приемлемо.

Однако я решил, что этого уже недостаточно: я хочу построить спроецированные данные напрямую, без переназначения, как могут, если я не ошибаюсь, делать другие программы (например, ncl), не касаясь выходных значений модели.

Однако я столкнулся с некоторыми проблемами. Ниже я подробно расскажу о возможных решениях, от самых простых до самых сложных, и их проблемах. Сможем ли мы их преодолеть?

РЕДАКТИРОВАТЬ: благодаря ответу @ lbusett я получил эту прекрасную функцию, которая включает решение. Если вам это нравится, проголосуйте за ответ @ lbusett!

Начальная настройка

#Load packages
library(raster)
library(ggplot2)

#This gives you the starting data, 's'
load(url('https://files.fm/down.php?i=kew5pxw7&n=loadme.Rdata'))
#If you cannot download the data, maybe you can try to manually download it from http://s000.tinyupload.com/index.php?file_id=04134338934836605121

#Check the data projection, it's Lambert Conformal Conic
projection(s)
#The data (precipitation) has a 'model' grid (125x125, units are integers from 1 to 125)
#for each point a lat-lon value is also assigned
pr <- s[[1]]
lon <- s[[2]]
lat <- s[[3]]

#Lets get the data into data.frames
#Gridded in model units:
pr_df_basic <- as.data.frame(pr, xy=TRUE)
colnames(pr_df_basic) <- c('lon', 'lat', 'pr')
#Projected points:
pr_df <- data.frame(lat=lat[], lon=lon[], pr=pr[])

Мы создали два фрейма данных, один с координатами модели, другой с реальными точками пересечения широты и долготы (центрами) для каждой ячейки модели.

Необязательно: использование меньшего домена

Если вы хотите более четко видеть формы ячеек, вы можете подгруппировать данные и извлечь только небольшое количество ячеек модели. Просто будьте осторожны, вам может потребоваться настроить размер точек, пределы сюжета и другие удобства. Вы можете подмножество, подобное этому, а затем повторить приведенную выше часть кода (без load()):

s <- crop(s, extent(c(100,120,30,50)))

Если вы хотите полностью разобраться в проблеме, возможно, вы захотите попробовать как большой, так и малый домен. код идентичен, меняются только размеры точек и лимиты карты. Приведенные ниже значения относятся к большому целому домену. Хорошо, а теперь приступим к сюжету!

Начните с плитки

Наиболее очевидное решение - использовать плитку. Давай попробуем.

my_theme <- theme_bw() + theme(panel.ontop=TRUE, panel.background=element_blank())
my_cols <- scale_color_distiller(palette='Spectral')
my_fill <- scale_fill_distiller(palette='Spectral')

#Really unprojected square plot:
ggplot(pr_df_basic, aes(y=lat, x=lon, fill=pr)) + geom_tile() + my_theme + my_fill

И вот результат:  введите описание изображения здесь

Хорошо, теперь кое-что более продвинутое: мы используем настоящие LAT-LON, используя квадратные плитки.

ggplot(pr_df, aes(y=lat, x=lon, fill=pr)) + geom_tile(width=1.2, height=1.2) +
    borders('world', xlim=range(pr_df$lon), ylim=range(pr_df$lat), colour='black') + my_theme + my_fill +
    coord_quickmap(xlim=range(pr_df$lon), ylim=range(pr_df$lat)) #the result is weird boxes...

введите описание изображения здесь

Хорошо, но это не настоящие квадраты модели, это хитрость. Кроме того, блоки модели расходятся в верхней части области и все ориентированы одинаково. Не хорошо. Давайте спроецируем сами квадраты, хотя мы уже знаем, что это неправильно ... может быть, это выглядит хорошо.

#This takes a while, maybe you can trust me with the result
ggplot(pr_df, aes(y=lat, x=lon, fill=pr)) + geom_tile(width=1.5, height=1.5) +
    borders('world', xlim=range(pr_df$lon), ylim=range(pr_df$lat), colour='black') + my_theme + my_fill +
    coord_map('lambert', lat0=30, lat1=65, xlim=c(-20, 39), ylim=c(19, 75))

введите описание изображения здесь

Во-первых, на это уходит много времени. Недопустимо. И еще раз: это неправильные модельные ячейки.

Попробуйте использовать очки, а не плитки

Может быть, мы можем использовать круглые или квадратные точки вместо плиток, а также проецировать их!

#Basic 'unprojected' point plot
ggplot(pr_df, aes(y=lat, x=lon, color=pr)) + geom_point(size=2) +
    borders('world', xlim=range(pr_df$lon), ylim=range(pr_df$lat), colour='black') + my_cols + my_theme +
    coord_quickmap(xlim=range(pr_df$lon), ylim=range(pr_df$lat))

введите описание изображения здесь

Мы можем использовать квадратные точки ... и проецировать! Мы подходим ближе, хотя знаем, что это все равно неверно.

#In the following plot pointsize, xlim and ylim were manually set. Setting the wrong values leads to bad results.
#Also the lambert projection values were tired and guessed from the model CRS
ggplot(pr_df, aes(y=lat, x=lon, color=pr)) +
    geom_point(size=2, shape=15) +
    borders('world', xlim=range(pr_df$lon), ylim=range(pr_df$lat), colour='black') + my_theme + my_cols +
    coord_map('lambert', lat0=30, lat1=65, xlim=c(-20, 39), ylim=c(19, 75))

введите описание изображения здесь

Достойные результаты, но не полностью автоматические, и построения точек недостаточно. Я хочу, чтобы клетки реальной модели с их формой были видоизменены проекцией!

Может быть, полигоны?

Итак, как вы можете видеть, я ищу способ правильно построить блоки модели, спроектированные в правильной форме и положении. Конечно, блоки модели, которые представляют собой квадраты в модели, после проецирования становятся формами, которые больше не являются правильными. Так, может быть, я смогу использовать полигоны и проецировать их? Я пытался использовать rasterToPolygons и fortify и следить за этим сообщением, но мне это не удалось. Я пробовал это:

pr2poly <- rasterToPolygons(pr)
#http://mazamascience.com/WorkingWithData/?p=1494
pr2poly@data$id <- rownames(pr2poly@data)
tmp <- fortify(pr2poly, region = "id")
tmp2 <- merge(tmp, pr2poly@data, by = "id")
ggplot(tmp2, aes(x=long, y=lat, group = group, fill=Total.precipitation.flux)) + geom_polygon() + my_fill

введите описание изображения здесь

Ладно, попробуем заменить латинские на латинские ...

tmp2$long <- lon[]
tmp2$lat <- lat[]
#Mh, does not work! See below:
ggplot(tmp2, aes(x=long, y=lat, group = group, fill=Total.precipitation.flux)) + geom_polygon() + my_fill

введите описание изображения здесь

(извините, что поменял цветовую гамму в сюжетах)

Мммм, даже не стоит пробовать с проекцией. Может, мне стоит попытаться вычислить широты и долготы углов ячеек модели, создать для них многоугольники и перепроецировать их?

Вывод

  1. Я хочу нанести данные проектируемой модели на ее собственную сетку, но у меня не получилось. Использование тайлов неверно, использование точек - хакерское занятие, а использование полигонов, похоже, не работает по неизвестным причинам.
  2. При проецировании через coord_map() линии сетки и метки осей неправильные. Это делает спроектированные ggplots непригодными для публикаций.

person AF7    schedule 25.04.2017    source источник
comment
Вы пробовали ggmap?   -  person ulfelder    schedule 25.04.2017
comment
@ulfelder Я помню, как использовал его раньше, но не недавно. Я забыл, что он существует. Я разберусь с этим. Есть ли что-нибудь особенно интересное, на что стоит обратить внимание?   -  person AF7    schedule 25.04.2017
comment
Мне не удалось загрузить ваши данные; вы уверены, что URL правильный?   -  person SymbolixAU    schedule 26.04.2017
comment
@SymbolixAU Я сменил поставщика donwload, попробуйте еще раз. Это должно работать более надежно.   -  person AF7    schedule 26.04.2017
comment
Ваши данные вызываются с диска: /home/adriano/EURO-CORDEX_59_tas_pr_prc_monmean_1998-2000.nc Таким образом, вы сохраняете на свой компьютер объект без реальных данных, а только с URL-адресом. Вместо RData можно ли сохранить в растровом слое?   -  person gonzalez.ivan90    schedule 27.04.2017
comment
@ gonzalez.ivan90 Моя беда, readAll() перед сохранением не делал. Теперь он должен работать, вы можете его протестировать?   -  person AF7    schedule 27.04.2017
comment
Привет. Я думаю, что с твоим набором данных есть что-то странное. Проекция s результатов как "+proj=lcc +lat_1=30. +lat_2=65. +lat_0=48. +lon_0=9.75 +x_0=-25000. +y_0=-25000. +ellps=sphere +a=6371229. +b=6371229. +units=m +no_defs", что является метрической проекцией. Однако ваши координаты - долгота-широта, а разрешение растра - 1. Где вы взяли набор данных? Делали ли вы над ним какие-то пространственные разработки?   -  person lbusett    schedule 27.04.2017
comment
Разве вы не можете просто сделать субдискретизацию растра с более высоким разрешением перед повторным проецированием?   -  person Jacob Socolar    schedule 28.04.2017
comment
@ AF7 Вам нужно строить с использованием проекции LCC? Разве нельзя просто изменить проекцию растровых данных?   -  person Marcelo    schedule 28.04.2017
comment
@LoBu Хорошая находка. Это данные непосредственно в том виде, в каком они поступают из модели, а строка проекции задается самой моделью. Понятия не имею, почему там написано +units=m, и я не эксперт по прогнозам, возможно, для этого есть причина. Странный. Тем не менее, похоже, что это сработает, если я перепроектирую материал.   -  person AF7    schedule 28.04.2017
comment
@JacobSocolar Вся суть вопроса в том, что я вообще не хочу трогать входные данные перед построением графика. Если бы это не было ограничением, я мог бы просто переназначить правильную взвешенную технику и довольствоваться ею, в большинстве случаев это не так сильно влияет на данные.   -  person AF7    schedule 28.04.2017
comment
@Marcelo Суть вопроса, как было сказано ранее, заключается в том, что я не хочу вносить какие-либо изменения в значения данных. Следовательно, я не могу переназначить, что я обычно делаю при создании таких графиков.   -  person AF7    schedule 28.04.2017
comment
Мне кажется, что хотя координаты широты и долготы в s [[1]] и s [[2]] верны, форматирование в виде стека растров полностью отключено. Фактически, если вы попытаетесь визуализировать один из слоев с помощью mapview, вы получите совершенно неправильную систему координат.   -  person lbusett    schedule 28.04.2017
comment
@LoBu Я не понимаю. Конечно, вы получите неправильную систему координат, поскольку координаты x-y - это просто координаты модели и изменяются от 1 до 125. Это точка наличия отдельных переменных для отображения широты и долготы.   -  person AF7    schedule 28.04.2017
comment
@ AF7, я хочу сказать, что вы не должны сохранять набор данных как объект RasterStack. Это может привести к путанице, поскольку, например, стандартные процедуры обработки raster, такие как projectRaster, не будут работать должным образом. На мой взгляд, было бы лучше сохранить его как SpatialPixelsDataFrame.   -  person lbusett    schedule 28.04.2017
comment
@LoBu исходный набор данных - это netCDF, и я обычно читаю это с raster. Если проекция необходима внутри R, я следую этим отличным инструкциям: gis.stackexchange.com/questions/120900/   -  person AF7    schedule 28.04.2017
comment
Но график никогда не покажет в точности исходные данные. По крайней мере, это ограничено разрешением графического устройства. Это чисто академический вопрос, или есть проблема с эффективностью, или ...   -  person Jacob Socolar    schedule 28.04.2017
comment
@JacobSocolar Хорошо, если вы печатаете многоугольники в PDF, тогда разрешение графического устройства не имеет значения. Основная причина, по которой я хочу это сделать, заключается в том, что я хочу достичь того же уровня точности, что и другие программы. Мне нравится строить графики с помощью R и ggplot, и я знаю, что довольно ужасный NCL может делать более точные графики, это меня очень раздражает :) С другой стороны, другие программы для построения графиков NetCDF (такие как GrADS и, как мне кажется, Ferret) просто автоматически переназначаются на свой внутренний максимум. -res сетка LAT-LON, не сообщая об этом пользователю. Эти сюжеты считаются приемлемыми, но я хочу добиться большего.   -  person AF7    schedule 29.04.2017


Ответы (2)


Покопавшись еще немного, кажется, что ваша модель основана на регулярной сетке 50 км в "конической" проекции Ламберта. Однако координаты, которые у вас есть в netcdf, являются координатами широты и долготы WGS84 центра «ячеек».

Учитывая это, более простой подход состоит в том, чтобы восстановить ячейки в исходной проекции, а затем построить полигоны после преобразования в объект sf, в конечном итоге после повторного проецирования. Примерно так должно работать (обратите внимание, что вам нужно установить devel версию ggplot2 из github, чтобы она работала):

load(url('https://files.fm/down.php?i=kew5pxw7&n=loadme.Rdata'))
library(raster)
library(sf)
library(tidyverse)
library(maps)
devtools::install_github("hadley/ggplot2")

#   ____________________________________________________________________________
#   Transform original data to a SpatialPointsDataFrame in 4326 proj        ####

coords = data.frame(lat = values(s[[2]]), lon = values(s[[3]]))
spPoints <- SpatialPointsDataFrame(coords, 
                                   data = data.frame(data = values(s[[1]])), 
                                   proj4string = CRS("+init=epsg:4326"))

#   ____________________________________________________________________________
#   Convert back the lat-lon coordinates of the points to the original      ###
#   projection of the model (lcc), then convert the points to polygons in lcc
#   projection and convert to an `sf` object to facilitate plotting

orig_grid = spTransform(spPoints, projection(s))
polys = as(SpatialPixelsDataFrame(orig_grid, orig_grid@data, tolerance = 0.149842),"SpatialPolygonsDataFrame")
polys_sf = as(polys, "sf")
points_sf = as(orig_grid, "sf")

#   ____________________________________________________________________________
#   Plot using ggplot - note that now you can reproject on the fly to any    ###
#   projection using `coord_sf`

# Plot in original  projection (note that in this case the cells are squared): 
my_theme <- theme_bw() + theme(panel.ontop=TRUE, panel.background=element_blank())

ggplot(polys_sf) +
  geom_sf(aes(fill = data)) + 
  scale_fill_distiller(palette='Spectral') +
  ggtitle("Precipitations") +
  coord_sf() + 
  my_theme 

введите описание изображения здесь

# Now Plot in WGS84 latlon projection and add borders: 

ggplot(polys_sf) +
  geom_sf(aes(fill = data)) + 
  scale_fill_distiller(palette='Spectral') +
  ggtitle("Precipitations")  +
  borders('world', colour='black')+
  coord_sf(crs = st_crs(4326), xlim = c(-60, 80), ylim = c(15, 75))+
  my_theme 

введите описание изображения здесь

Однако, чтобы добавить границы, вы также должны рисовать в исходной проекции, вам нужно будет указать границы лойгона как sf объект. Заимствование отсюда:

Преобразование объекта карты в объект SpatialPolygon

Примерно так будет работать:

library(maptools)
borders  <- map("world", fill = T, plot = F)
IDs      <- seq(1,1627,1)
borders  <- map2SpatialPolygons(borders, IDs=borders$names, 
                               proj4string=CRS("+proj=longlat +datum=WGS84")) %>% 
            as("sf")

ggplot(polys_sf) +
  geom_sf(aes(fill = data), color = "transparent") + 
  geom_sf(data = borders, fill = "transparent", color = "black") +
  scale_fill_distiller(palette='Spectral') +
  ggtitle("Precipitations") +
  coord_sf(crs = st_crs(projection(s)), 
           xlim = st_bbox(polys_sf)[c(1,3)],
           ylim = st_bbox(polys_sf)[c(2,4)]) +
  my_theme

введите описание изображения здесь

Кстати, теперь, когда мы «восстановили» правильную пространственную привязку, также можно построить правильный raster набор данных. Например:

r <- s[[1]]
extent(r) <- extent(orig_grid) + 50000

даст вам правильный raster в r:

r
class       : RasterLayer 
band        : 1  (of  36  bands)
dimensions  : 125, 125, 15625  (nrow, ncol, ncell)
resolution  : 50000, 50000  (x, y)
extent      : -3150000, 3100000, -3150000, 3100000  (xmin, xmax, ymin, ymax)
coord. ref. : +proj=lcc +lat_1=30. +lat_2=65. +lat_0=48. +lon_0=9.75 +x_0=-25000. +y_0=-25000. +ellps=sphere +a=6371229. +b=6371229. +units=m +no_defs 
data source : in memory
names       : Total.precipitation.flux 
values      : 0, 0.0002373317  (min, max)
z-value     : 1998-01-16 10:30:00 
zvar        : pr 

Обратите внимание, что теперь разрешение составляет 50 км, а размер выражен в метрических координатах. Таким образом, вы можете построить / работать с r, используя функции для raster данных, например:

library(rasterVis)
gplot(r) + geom_tile(aes(fill = value)) + 
  scale_fill_distiller(palette="Spectral", na.value = "transparent") +
  my_theme  

library(mapview)
mapview(r, legend = TRUE)  
person lbusett    schedule 28.04.2017
comment
object 'transf' not found. Кроме того, как вы получили «толерантность»? А зачем делать переназначение на epsg:4326? Вносит ли это (хотя и небольшую) ошибку? - person AF7; 28.04.2017
comment
опс, извините. Я отредактировал пост. Что касается допуска, то для создания SpatialPixelsDataFrame требуется регулярная сетка, а перепроектирование ячеек, вероятно, приведет к некоторой ошибке округления. Если вы вызываете SpatialPixelsDataFrame(orig_grid, orig_grid@data) без аргумента tolerance, дается предполагаемый допуск. По поводу проекции: Нет, конвертировать в 4326 не нужно. Это было просто, чтобы показать вам, что вы можете легко перепроецировать любую CRS. - person lbusett; 28.04.2017
comment
ой, извини. Я, наверное, неверно истолковал ваш вопрос о переназначении на epsg:4326. При создании SpatialPixelsDataFrame я не переназначаю. Я просто назначаю координатам их правильную систему отсчета, то есть 4326. Тот факт, что это правильная система координат, подтверждается тем фактом, что при преобразовании в проекцию lcc вы получаете регулярную сетку (вы можете увидеть это, выполнив head(coordinates(orig_grid)) - person lbusett; 28.04.2017
comment
Да, спасибо за пояснение. Для меня было важно, чтобы если в ячейке N было значение X, на графике это не изменилось даже незначительно. Ваш ответ выглядит потрясающе. Позвольте мне немного изучить это, прежде чем принять и наградить его. - person AF7; 29.04.2017
comment
У меня проблемы с построением графика только с geom_sf() на сетке модели, а также с нанесением границ с borders() из того, что я собираю, все слои (включая границы) должны быть автоматически перенесены во входные данные CRS (точно так же, как при использовании coord_map()), но похоже, что это не работает. У меня должен получиться квадратный участок, как у вас, с бордюрами сверху. Я получаю только такой сюжет, как ваш, с маленькой черной точкой посередине. Что не так? - person AF7; 29.04.2017
comment
это потому, что borders("world",..... не является sf объектом, так что, очевидно, перепроецирование не применяется. См. Обновленный ответ для обходного пути. - person lbusett; 29.04.2017
comment
Спасибо. Я подал жалобу на ggplot на github по этому поводу, так как это кажется ошибкой. github.com/tidyverse/ggplot2/issues/2118 - person AF7; 29.04.2017
comment
Кстати, чтобы получить границы, вы можете просто borders <- sf::st_as_sf(map('world', plot = FALSE, fill = TRUE)) - person AF7; 29.04.2017
comment
Еще у меня вопрос: почему extent(orig_grid) + 50000? Почему не 25k, половина размера сетки? Зачем вообще что-то добавлять? - person AF7; 29.04.2017
comment
Вам необходимо расширить экстент на половину пикселя по отношению к точкам, потому что экстент объекта raster вычисляется по углам ячеек. Я использую 50000, потому что при суммировании с объектом extent экстент увеличивается на половину значения во всех направлениях (я обнаружил это методом проб и ошибок). - person lbusett; 30.04.2017
comment
Отлично. Я предлагаю такой способ вычисления 50000: extog <- extent(orig_grid) ; target.res <- (extog[2] - extog[1]) / (nrow(r) -1) - person AF7; 30.04.2017
comment
Хорошая идея. Я включу это в свой ответ. Также: в функции, которую вы добавили в свой вопрос, подумайте о том, что вы можете удалить строку points_sf = as(orig_grid, "sf"). Это был остаток проверки правильности совмещения полигонов ячеек с точками. - person lbusett; 02.05.2017

«Увеличение», чтобы увидеть точки, являющиеся центрами ячеек. Вы можете видеть, что они находятся в прямоугольной сетке.

Очки Уэльса

Я вычислил вершины многоугольников следующим образом.

  • Преобразование широты и долготы 125x125 в матрицу

  • Инициализировать матрицу размером 126x126 для вершин (углов) ячеек.

  • Вычислить вершины ячеек как среднее положение каждой группы точек 2x2.

  • Добавьте вершины ячеек для ребер и углов (предположим, что ширина и высота ячейки равны ширине и высоте соседних ячеек).

  • Сгенерируйте data.frame с каждой ячейкой, имеющей четыре вершины, так что мы получим 4x125x125 строк.

Код становится

 pr <- s[[1]]
lon <- s[[2]]
lat <- s[[3]]

#Lets get the data into data.frames
#Gridded in model units:
#Projected points:
lat_m <- as.matrix(lat)
lon_m <- as.matrix(lon)
pr_m <- as.matrix(pr)

#Initialize emptry matrix for vertices
lat_mv <- matrix(,nrow = 126,ncol = 126)
lon_mv <- matrix(,nrow = 126,ncol = 126)


#Calculate centre of each set of (2x2) points to use as vertices
lat_mv[2:125,2:125] <- (lat_m[1:124,1:124] + lat_m[2:125,1:124] + lat_m[2:125,2:125] + lat_m[1:124,2:125])/4
lon_mv[2:125,2:125] <- (lon_m[1:124,1:124] + lon_m[2:125,1:124] + lon_m[2:125,2:125] + lon_m[1:124,2:125])/4

#Top edge
lat_mv[1,2:125] <- lat_mv[2,2:125] - (lat_mv[3,2:125] - lat_mv[2,2:125])
lon_mv[1,2:125] <- lon_mv[2,2:125] - (lon_mv[3,2:125] - lon_mv[2,2:125])

#Bottom Edge
lat_mv[126,2:125] <- lat_mv[125,2:125] + (lat_mv[125,2:125] - lat_mv[124,2:125])
lon_mv[126,2:125] <- lon_mv[125,2:125] + (lon_mv[125,2:125] - lon_mv[124,2:125])

#Left Edge
lat_mv[2:125,1] <- lat_mv[2:125,2] + (lat_mv[2:125,2] - lat_mv[2:125,3])
lon_mv[2:125,1] <- lon_mv[2:125,2] + (lon_mv[2:125,2] - lon_mv[2:125,3])

#Right Edge
lat_mv[2:125,126] <- lat_mv[2:125,125] + (lat_mv[2:125,125] - lat_mv[2:125,124])
lon_mv[2:125,126] <- lon_mv[2:125,125] + (lon_mv[2:125,125] - lon_mv[2:125,124])

#Corners
lat_mv[c(1,126),1] <- lat_mv[c(1,126),2] + (lat_mv[c(1,126),2] - lat_mv[c(1,126),3])
lon_mv[c(1,126),1] <- lon_mv[c(1,126),2] + (lon_mv[c(1,126),2] - lon_mv[c(1,126),3])

lat_mv[c(1,126),126] <- lat_mv[c(1,126),125] + (lat_mv[c(1,126),125] - lat_mv[c(1,126),124])
lon_mv[c(1,126),126] <- lon_mv[c(1,126),125] + (lon_mv[c(1,126),125] - lon_mv[c(1,126),124])


pr_df_orig <- data.frame(lat=lat[], lon=lon[], pr=pr[])

pr_df <- data.frame(lat=as.vector(lat_mv[1:125,1:125]), lon=as.vector(lon_mv[1:125,1:125]), pr=as.vector(pr_m))
pr_df$id <- row.names(pr_df)

pr_df <- rbind(pr_df,
               data.frame(lat=as.vector(lat_mv[1:125,2:126]), lon=as.vector(lon_mv[1:125,2:126]), pr = pr_df$pr, id = pr_df$id),
               data.frame(lat=as.vector(lat_mv[2:126,2:126]), lon=as.vector(lon_mv[2:126,2:126]), pr = pr_df$pr, id = pr_df$id),
               data.frame(lat=as.vector(lat_mv[2:126,1:125]), lon=as.vector(lon_mv[2:126,1:125]), pr = pr_df$pr, id= pr_df$id))

То же увеличенное изображение с многоугольными ячейками

Wales Cells

Исправление ярлыков

ewbrks <- seq(-180,180,20)
nsbrks <- seq(-90,90,10)
ewlbls <- unlist(lapply(ewbrks, function(x) ifelse(x < 0, paste(abs(x), "°W"), ifelse(x > 0, paste(abs(x), "°E"),x))))
nslbls <- unlist(lapply(nsbrks, function(x) ifelse(x < 0, paste(abs(x), "°S"), ifelse(x > 0, paste(abs(x), "°N"),x))))

Замена geom_tile и geom_point на geom_polygon

ggplot(pr_df, aes(y=lat, x=lon, fill=pr, group = id)) + geom_polygon() +
    borders('world', xlim=range(pr_df$lon), ylim=range(pr_df$lat), colour='black') + my_theme + my_fill +
    coord_quickmap(xlim=range(pr_df$lon), ylim=range(pr_df$lat)) +
scale_x_continuous(breaks = ewbrks, labels = ewlbls, expand = c(0, 0)) +
scale_y_continuous(breaks = nsbrks, labels = nslbls, expand = c(0, 0)) + 
labs(x = "Longitude", y = "Latitude")

введите описание изображения здесь

ggplot(pr_df, aes(y=lat, x=lon, fill=pr, group = id)) + geom_polygon() +
    borders('world', xlim=range(pr_df$lon), ylim=range(pr_df$lat), colour='black') + my_theme + my_fill +
    coord_map('lambert', lat0=30, lat1=65, xlim=c(-20, 39), ylim=c(19, 75)) +
scale_x_continuous(breaks = ewbrks, labels = ewlbls, expand = c(0, 0)) +
scale_y_continuous(breaks = nsbrks, labels = nslbls, expand = c(0, 0)) + 
labs(x = "Longitude", y = "Latitude")

введите описание изображения здесь

Изменить - работа с отметками оси

Мне не удалось найти быстрое решение для линий сетки и меток для широты. Вероятно, где-то есть пакет R, который решит вашу проблему с гораздо меньшим количеством кода!

Ручная установка необходимого nsbreaks и создание data.frame

ewbrks <- seq(-180,180,20)
nsbrks <- c(20,30,40,50,60,70)
nsbrks_posn <- c(-16,-17,-16,-15,-14.5,-13)
ewlbls <- unlist(lapply(ewbrks, function(x) ifelse(x < 0, paste0(abs(x), "° W"), ifelse(x > 0, paste0(abs(x), "° E"),x))))
nslbls <- unlist(lapply(nsbrks, function(x) ifelse(x < 0, paste0(abs(x), "° S"), ifelse(x > 0, paste0(abs(x), "° N"),x))))
latsdf <- data.frame(lon = rep(c(-100,100),length(nsbrks)), lat = rep(nsbrks, each =2), label = rep(nslbls, each =2), posn = rep(nsbrks_posn, each =2))

Удалите метки отметок оси Y и соответствующие линии сетки, а затем добавьте их «вручную», используя geom_line и geom_text

ggplot(pr_df, aes(y=lat, x=lon, fill=pr, group = id)) + geom_polygon() +
    borders('world', xlim=range(pr_df$lon), ylim=range(pr_df$lat), colour='black') + my_theme + my_fill +
    coord_map('lambert', lat0=30, lat1=65, xlim=c(-20, 40), ylim=c(19, 75)) +
    scale_x_continuous(breaks = ewbrks, labels = ewlbls, expand = c(0, 0)) +
    scale_y_continuous(expand = c(0, 0), breaks = NULL) + 
    geom_line(data = latsdf, aes(x=lon, y=lat, group = lat), colour = "white", size = 0.5, inherit.aes = FALSE) +
    geom_text(data = latsdf, aes(x = posn, y = (lat-1), label = label), angle = -13, size = 4, inherit.aes = FALSE) +
    labs(x = "Longitude", y = "Latitude") +
    theme( axis.text.y=element_blank(),axis.ticks.y=element_blank())

введите описание изображения здесь

person Jeremy Voisey    schedule 28.04.2017
comment
Мне нравится этот подход, но я думаю, что с результатом что-то не так, поскольку пространственные узоры на вашей выходной карте сильно отличаются от исходной. - person lbusett; 28.04.2017
comment
Я заметил, что. Я проверю, но считаю, что это может быть связано с загрузкой разных данных с load(url.. или, возможно, с исходными графиками, имеющими перекрывающиеся плитки или точки, которые потеряли часть информации. - person Jeremy Voisey; 28.04.2017
comment
Я понимаю что ты имеешь ввиду. Я не могу сейчас это исправить, извините, так как я на работе. Но я уверен, что это будет довольно просто. Вероятно, это просто случай перестановки матрицы. - person Jeremy Voisey; 28.04.2017
comment
Я предлагаю быстрое решение, это может сработать, но в данный момент я не могу протестировать. pr_m <- as.matrix(pr). Затем в data.frame use pr = as.vector(pr_m) я думаю, что обработка pr точно так же, как lat и lon, гарантирует, что они не поменяются местами. - person Jeremy Voisey; 28.04.2017
comment
Подойдет сегодня днем ​​или вечером (по кипрскому времени). - person Jeremy Voisey; 28.04.2017
comment
Позвольте нам продолжить это обсуждение в чате. - person Jeremy Voisey; 28.04.2017
comment
Я исправил ошибку. - person Jeremy Voisey; 28.04.2017
comment
@JeremyVoisey круто. Теперь единственное, чего не хватает, - это исправить ggplot проблему с метками осей и линиями сетки. Я думаю, что лучше всего преобразовать полигоны в тип sf и использовать geom_sf() вместо geom_polygon(). geom_sf() использует st_graticule() и должен работать намного лучше. Я займусь этим, но, к сожалению, не скоро. - person AF7; 28.04.2017
comment
Я изменил метки благодаря ответу, найденному в другом месте stackoverflow.com/questions/33302424/ - person Jeremy Voisey; 28.04.2017
comment
@JeremyVoisey Это ответ на вопрос, который я задал, я знаю, как лучше исправить ярлык таким образом :). Я не это имел в виду, я должен был быть более точным, извините. Посмотрите последний сюжет. Метки размещены не на своем месте по сравнению с линиями сетки. Например, 40N не соответствует строке 40N. То же для -20E. Другое дело, что линия 60Н почему-то тоже не доходит до границ сюжета. - person AF7; 29.04.2017
comment
Я понимаю что ты имеешь ввиду. Метки фактически выровнены по горизонтали с точками пересечения с линией долготы -20E. Это имеет смысл с одной стороны, поскольку это указанный предел на этой оси. Но очевидно, что это не работает для проекции Ламберта. - person Jeremy Voisey; 29.04.2017
comment
Что ж, тогда может быть достаточно вручную удалить метку первого и последнего разрыва, если вы строите график в Ламберте. Кстати: есть ошибка при переназначении меток: метки к востоку от Грин, которые должны быть 10 E, 20 E и так далее. - person lbusett; 29.04.2017
comment
@LoBu Смешивать E & W, это неловко. Я получил код из stackoverflow, я предполагал, что он надежный, мой плохой. - person Jeremy Voisey; 29.04.2017
comment
Я добавил исправление для линий сетки (ОК) и меток (нужно немного поработать). Я думаю, что @LoBu каким-то образом придумал лучший ответ! - person Jeremy Voisey; 29.04.2017
comment
@ Джереми, все еще очень хорошая работа, я кое-что узнал. Если бы я мог наградить обоих, я бы наградил. Спасибо. - person AF7; 30.04.2017
comment
Спасибо, @LoBu - явный победитель и получил мой голос. Я тоже многому научился. - person Jeremy Voisey; 30.04.2017