Почему geom_tile отображает подмножество моих данных, а не больше?

Я пытаюсь построить карту, но не могу понять, почему не работает следующее:

Вот минимальный пример

testdf <- structure(list(x = c(48.97, 44.22, 44.99, 48.87, 43.82, 43.16, 38.96, 38.49, 44.98, 43.9), y = c(-119.7, -113.7, -109.3, -120.6,  -109.6, -121.2, -114.2, -118.9, -109.7, -114.1), z = c(0.001216,  0.001631, 0.001801, 0.002081, 0.002158, 0.002265, 0.002298, 0.002334, 0.002349, 0.00249)), .Names = c("x", "y", "z"), row.names = c(NA, 10L), class = "data.frame")

Это работает для 1-8 рядов:

ggplot(data = testdf[1,], aes(x,y,fill = z)) + geom_tile()
ggplot(data = testdf[1:8,], aes(x,y,fill = z)) + geom_tile()

Но не для 9 рядов:

ggplot(data = testdf[1:9,], aes(x,y,fill = z)) + geom_tile()

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

Полный набор данных доступен в виде gist.

testdf выше был небольшим подмножеством полного набора данных, растра высокого разрешения США (> 7500 строк).

require(RCurl) # requires libcurl; sudo apt-get install libcurl4-openssl-dev
tmp <- getURL("https://gist.github.com/raw/4635980/f657dcdfab7b951c7b8b921b3a109c7df1697eb8/test.csv")
testdf <- read.csv(textConnection(x))

Что я пробовал:

  1. использование geom_point работает, но не дает желаемого эффекта:

    ggplot(data = testdf, aes(x,y,color=z)) + geom_point()
    
  2. если я конвертирую либо x или y в вектор 1:10, график работает так, как ожидалось:

    newdf <- transform(testdf, y =1:10)
    
    ggplot(data = newdf[1:9,], aes(x,y,fill = z)) + geom_tile()
    
    newdf <- transform(testdf, x =1:10)
    ggplot(data = newdf[1:9,], aes(x,y,fill = z)) + geom_tile()
    

sessionInfo()R version 2.15.2 (2012-10-26) Platform: x86_64-pc-linux-gnu (64-bit)


> attached base packages: [1] stats     graphics  grDevices utils    
> datasets  methods   base     

> other attached packages: [1] reshape2_1.2.2 maps_2.3-0    
> betymaps_1.0   ggmap_2.2      ggplot2_0.9.3 

> loaded via a namespace (and not attached):  [1] colorspace_1.2-0   
> dichromat_1.2-4     digest_0.6.1        grid_2.15.2        
> gtable_0.1.2        labeling_0.1         [7] MASS_7.3-23        
> munsell_0.4         plyr_1.8            png_0.1-4          
> proto_0.3-10        RColorBrewer_1.0-5  [13] RgoogleMaps_1.2.0.2
> rjson_0.2.12        scales_0.2.3        stringr_0.6.2      
> tools_2.15.2

person Abe    schedule 24.01.2013    source источник
comment
У вас есть дополнительная информация о растре, из которого были получены данные? то есть проекционная информация   -  person Simon O'Hanlon    schedule 12.03.2013
comment
@SimonO101 они были сгенерированы на сетке 30x30 км.   -  person Abe    schedule 12.03.2013
comment
В порядке. Вам нужно будет сделать некоторую передискретизацию ваших данных. Точки расположены неравномерно, поэтому вы не можете использовать geom_raster или geom_tile. Подробности и решение, использующее geom_raster, см. в моем ответе.   -  person Simon O'Hanlon    schedule 12.03.2013
comment
ниже работает на вашей системе?   -  person Simon O'Hanlon    schedule 12.03.2013
comment
Абэ, я применил правку, которую вы правильно предложили, но рецензенты отклонили ее, прежде чем я успел ее принять! Вы совершенно правы, скрипт требует RCurl.   -  person Simon O'Hanlon    schedule 12.03.2013
comment
@SimonO101 СаймонО101 да, отлично работает. Спасибо за Ваш ответ! Но я все еще застрял (и прокомментирую ниже ваш ответ).   -  person Abe    schedule 12.03.2013


Ответы (4)


Причина, по которой вы не можете использовать geom_tile() (или более подходящий geom_raster(), заключается в том, что эти два geoms полагаются на то, что ваши плитки расположены равномерно, а это не так. Вам нужно будет привести свои данные к точкам и передискретизировать их в равномерно распределенный растр. который вы затем можете построить с помощью geom_raster() Вам придется признать, что вам нужно будет немного передискретизировать исходные данные, чтобы построить это так, как вы хотите.

Вы также должны прочитать raster:::projection и rgdal:::spTransform для получения дополнительной информации о картографических проекциях.

require( RCurl )
require( raster )
require( sp )
require( ggplot2 )
tmp <- getURL("https://gist.github.com/geophtwombly/4635980/raw/f657dcdfab7b951c7b8b921b3a109c7df1697eb8/test.csv")
testdf <- read.csv(textConnection(tmp))
spdf <- SpatialPointsDataFrame( data.frame( x = testdf$y , y = testdf$x ) , data = data.frame( z = testdf$z ) )

# Plotting the points reveals the unevenly spaced nature of the points
spplot(spdf)

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

# You can see the uneven nature of the data even better here via the moire pattern
plot(spdf)

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

# Make an evenly spaced raster, the same extent as original data
e <- extent( spdf )

# Determine ratio between x and y dimensions
ratio <- ( e@xmax - e@xmin ) / ( e@ymax - e@ymin )

# Create template raster to sample to
r <- raster( nrows = 56 , ncols = floor( 56 * ratio ) , ext = extent(spdf) )
rf <- rasterize( spdf , r , field = "z" , fun = mean )

# Attributes of our new raster (# cells quite close to original data)
rf
class       : RasterLayer 
dimensions  : 56, 135, 7560  (nrow, ncol, ncell)
resolution  : 0.424932, 0.4248191  (x, y)
extent      : -124.5008, -67.13498, 25.21298, 49.00285  (xmin, xmax, ymin, ymax)

# We can then plot this using `geom_tile()` or `geom_raster()`
rdf <- data.frame( rasterToPoints( rf ) )    
ggplot( NULL ) + geom_raster( data = rdf , aes( x , y , fill = layer ) )

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

# And as the OP asked for geom_tile, this would be...
ggplot( NULL ) + geom_tile( data = rdf , aes( x , y , fill = layer ) , colour = "white" )

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

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

person Simon O'Hanlon    schedule 12.03.2013
comment
Заранее извиняюсь за сумбурность - мне нужно кое-что прочитать - но я не понимаю последнюю часть. Почему данные бессмысленны? Неопределенность, связанная с повторной выборкой, невелика, а в наборе данных есть широта и долгота, поэтому, например, я вижу, что средний запад имеет более высокие значения, чем западное побережье. Какую информацию добавляет проект, кроме той, которая необходима для построения графика? Неверная ли проекция, используемая в объекте rf RasterLayer? Дополнительную информацию об этих данных можно найти на gis.SE. Я застрял, пытаясь назначить gridded() <- TRUE. - person Abe; 12.03.2013
comment
Хорошо, это не совсем бессмысленно, но фактически мы наложили обычную сетку поверх того, что вы видите на первых изображениях, и присвоили значения обычной сетке в зависимости от того, где они находятся на основном изображении. Это неправильно. Преобразование данных путем перепроецирования приведет к тому, что некоторые из ваших точек данных сместятся больше, чем другие, в зависимости от их широты и долготы. Если вы не заботитесь о точности и хотите получить общий обзор, возможно, вы можете использовать это, но я не думаю, что это было бы не очень оправдано в публикации. Возможно, @PaulHiemstra мог бы уточнить немного больше? - person Simon O'Hanlon; 12.03.2013
comment
@ SimonO101 SimonO101 да, спасибо за помощь. Учитывая допущения, использованные для создания карты (это не 'данные', но вывод модели), а также ограниченное разрешение цветовой шкалы, я думаю, что можно будет оправдать некоторые ошибки, допущенные во время отображения - мое общее эмпирическое правило состоит в том, чтобы игнорировать то, что составляет ‹ 5% или около того от полной неопределенности. - person Abe; 12.03.2013

Это будет не ответ на geom_tile() проблему, а другой способ построения графика данных.

Поскольку у вас есть координаты x и y 30-километровой сетки (я предполагаю, что середина этой сетки), вы можете использовать geom_point() и отображать данные. Вы должны выбрать соответствующее значение shape=. Форма 15 будет строить прямоугольники.

Другая проблема - значения x и y - при построении данных они должны быть представлены как x=y и y=x, чтобы соответствовать широте и долготе.

coord_equal() обеспечит правильное соотношение сторон (я нашел это решение с соотношением в качестве примера в сети).

ggplot(data = testdf, aes(y,x,colour=z)) + geom_point(shape=15)+
  coord_equal(ratio=1/cos(mean(testdf$x)*pi/180))

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

person Didzis Elferts    schedule 11.03.2013

отвечать:

данные отображаются, но они очень маленькие.


Отсюда:

"Tile plot as densely as possible, assuming that every tile is the same size.

Рассмотрим этот сюжет

ggplot(data = testdf[1:2,], aes(x,y,fill = z)) + geom_tile()

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

На графике выше есть две плитки. geom_tile пытается сделать график максимально плотным, учитывая, что все плитки имеют одинаковый размер. Здесь мы можем сделать две плитки такого размера, не перекрывая друг друга. достаточно места для 4 плиток.

Попробуйте следующие графики и посмотрите, что говорят вам полученные графики:

df1 <- data.frame(x=c(1:3),y=(1:3))
#     df1
#  x   y
#1 1   1
#2 2   2
#3 3   3
ggplot(data = df1[1,], aes(x,y)) + geom_tile()   
ggplot(data = df1[1:2,], aes(x,y)) + geom_tile() 
ggplot(data = df1[1:3,], aes(x,y)) + geom_tile()

сравните с этим примером:

 df2 <- data.frame(x=c(1:3),y=c(1,20,300))
 df2
 # x   y
#1 1   1
#2 2  20
#3 3 300

 ggplot(data = df2[1,], aes(x,y)) + geom_tile()
 ggplot(data = df2[1:2,], aes(x,y)) + geom_tile()
 ggplot(data = df2[1:3,], aes(x,y)) + geom_tile()

Обратите внимание, что первые два графика одинаковы для df1 и df2, но третий график для df2 отличается. Это связано с тем, что самые большие плитки, которые мы можем сделать, находятся между (x[1],y[1]) и (x[2],y[2])). Если больше, они будут перекрываться, что оставляет много места между этими двумя плитками и последней третьей плиткой на y=300.

В geom_tile также есть параметр width, хотя я не уверен, насколько он здесь уместен. вы уверены, что вам не нравится другой вариант с такими скудными данными?

(Ваши полные данные все еще отображаются: см. ggplot(data = testdf, aes(x,y)) + geom_tile(width=1000)

person user1317221_G    schedule 24.01.2013
comment
Да, но, возможно, вы могли бы добавить небольшое пояснение о том, как geom_tile выбирает размер плиток в зависимости от того, насколько близко друг к другу расположены точки...? - person joran; 25.01.2013
comment
Какие еще варианты вы предлагаете? Только минимальный пример разреженный; полный набор данных: betydb.org//miscanthusyield.csv - person Abe; 25.01.2013
comment
Точно; это растр США из 7500 строк с шагом сетки 30 км; Я просто уменьшил проблему, пытаясь найти ответ сам, и для ясности этого вопроса. Я удалил предыдущий комментарий и ссылку и добавил пример полного набора данных к моему вопросу. Я попробую width и вернусь к вам. Я думаю, что проблема может быть в проекции... - person Abe; 25.01.2013
comment
Я назначил награду за этот вопрос, ища решение для построения графика данных, которые у меня есть. - person Abe; 11.03.2013

Если вы хотите использовать geom_tile, я думаю, вам нужно сначала выполнить агрегацию:

# NOTE: tmp.csv downloaded from https://gist.github.com/geophtwombly/4635980/raw/f657dcdfab7b951c7b8b921b3a109c7df1697eb8/test.csv
testdf <- read.csv("~/Desktop/tmp.csv") 

# combine x,y coordinates by rounding
testdf$x2 <- round(testdf$x, digits=0)
testdf$y2 <- round(testdf$y, digits=0)

# aggregate on combined coordinates
library(plyr)
testdf <- ddply(testdf, c("x2", "y2"), summarize,
                z = mean(z))

# plot aggregated data using geom_tile
ggplot(data = testdf, aes(y2,x2,fill=z)) +
  geom_tile() +
  coord_equal(ratio=1/cos(mean(testdf$x2)*pi/180)) # copied from @Didzis Elferts answer--nice!

Сделав все это, мы, вероятно, придем к выводу, что geom_point() лучше, как предложил @Didzis Elferts.

person Ista    schedule 11.03.2013