Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to plot wind direction with lat lon and arrow in ggplot2

Tags:

plot

r

ggplot2

I have a data frame with Lat Lon mean_wind and wind_dir in each grid cells. I am trying to make a spatial plot with mean wind in background and wind direction as arrow on each grid cells.

I have tried following on sample data-frame wind.dt

win.plt<- ggplot(wind.dt,aes(x=Lon,y=Lat))+
           #Mean wind plot : OK
        geom_tile(aes(fill=mean_wind),alpha=1)+
        geom_tile(aes(color=mean_wind), fill=NA) +
        scale_fill_gradientn(colours=(brewer.pal(9,rev("RdYlGn"))))+ 
        scale_color_gradientn(colours=(brewer.pal(9,rev("RdYlGn"))),guide=F)
          #Wind Direction : doesnot work
        geom_segment(arrow = arrow(),aes(yend = Lon + wind_dir, xend = Lat + wind_dir))

win.plt

wind.dt<-structure(list(Lon = c(170.25, 171, 171.75, 172.5, 173.25, 174, 
174.75, 175.5, 176.25, 177, 177.75, 178.5, 179.25, 180, 180.75, 
181.5, 182.25, 183, 183.75, 184.5, 185.25, 186, 186.75, 187.5, 
188.25, 189, 189.75, 190.5, 191.25, 192, 192.75, 193.5, 194.25, 
170.25, 171, 171.75, 172.5, 173.25, 174, 174.75, 175.5, 176.25, 
177, 177.75, 178.5, 179.25, 180, 180.75, 181.5, 182.25, 183, 
183.75, 184.5, 185.25, 186, 186.75, 187.5, 188.25, 189, 189.75, 
190.5, 191.25, 192, 192.75, 193.5, 194.25, 170.25, 171, 171.75, 
172.5, 173.25, 174, 174.75, 175.5, 176.25, 177, 177.75, 178.5, 
179.25, 180, 180.75, 181.5, 182.25, 183, 183.75, 184.5, 185.25, 
186, 186.75, 187.5, 188.25, 189, 189.75, 190.5, 191.25, 192, 
192.75, 193.5, 194.25, 170.25, 171, 171.75, 172.5, 173.25, 174, 
174.75, 175.5, 176.25, 177, 177.75, 178.5, 179.25, 180, 180.75, 
181.5, 182.25, 183, 183.75, 184.5, 185.25, 186, 186.75, 187.5, 
188.25, 189, 189.75, 190.5, 191.25, 192, 192.75, 193.5, 194.25, 
170.25, 171, 171.75, 172.5, 173.25, 174, 174.75, 175.5, 176.25, 
177, 177.75, 178.5, 179.25, 180, 180.75, 181.5, 182.25, 183, 
183.75, 184.5, 185.25, 186, 186.75, 187.5, 188.25, 189, 189.75, 
190.5, 191.25, 192, 192.75, 193.5, 194.25, 170.25, 171, 171.75, 
172.5, 173.25, 174, 174.75, 175.5, 176.25, 177, 177.75, 178.5, 
179.25, 180, 180.75, 181.5, 182.25, 183, 183.75, 184.5, 185.25, 
186, 186.75, 187.5, 188.25, 189, 189.75, 190.5, 191.25, 192, 
192.75, 193.5, 194.25), Lat = c(14.25, 14.25, 14.25, 14.25, 14.25, 
14.25, 14.25, 14.25, 14.25, 14.25, 14.25, 14.25, 14.25, 14.25, 
14.25, 14.25, 14.25, 14.25, 14.25, 14.25, 14.25, 14.25, 14.25, 
14.25, 14.25, 14.25, 14.25, 14.25, 14.25, 14.25, 14.25, 14.25, 
14.25, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 
13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 
13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 
13.5, 13.5, 12.75, 12.75, 12.75, 12.75, 12.75, 12.75, 12.75, 
12.75, 12.75, 12.75, 12.75, 12.75, 12.75, 12.75, 12.75, 12.75, 
12.75, 12.75, 12.75, 12.75, 12.75, 12.75, 12.75, 12.75, 12.75, 
12.75, 12.75, 12.75, 12.75, 12.75, 12.75, 12.75, 12.75, 12, 12, 
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11.25, 
11.25, 11.25, 11.25, 11.25, 11.25, 11.25, 11.25, 11.25, 11.25, 
11.25, 11.25, 11.25, 11.25, 11.25, 11.25, 11.25, 11.25, 11.25, 
11.25, 11.25, 11.25, 11.25, 11.25, 11.25, 11.25, 11.25, 11.25, 
11.25, 11.25, 11.25, 11.25, 11.25, 10.5, 10.5, 10.5, 10.5, 10.5, 
10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 
10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 
10.5, 10.5, 10.5, 10.5, 10.5, 10.5), mean_wind = c(8.34, 8.33, 
8.31, 8.29, 8.27, 8.24, 8.22, 8.2, 8.19, 8.16, 8.14, 8.13, 8.1, 
8.08, 8.06, 8.02, 7.99, 7.96, 7.93, 7.89, 7.85, 7.81, 7.78, 7.73, 
7.7, 7.67, 7.63, 7.62, 7.6, 7.58, 7.56, 7.53, 7.54, 8.65, 8.64, 
8.61, 8.59, 8.56, 8.53, 8.51, 8.48, 8.46, 8.43, 8.41, 8.39, 8.38, 
8.37, 8.33, 8.31, 8.28, 8.24, 8.2, 8.15, 8.12, 8.07, 8.03, 8.01, 
7.97, 7.94, 7.92, 7.89, 7.87, 7.85, 7.85, 7.83, 7.8, 8.85, 8.84, 
8.81, 8.8, 8.77, 8.74, 8.72, 8.69, 8.67, 8.65, 8.63, 8.61, 8.59, 
8.58, 8.55, 8.54, 8.5, 8.46, 8.44, 8.4, 8.37, 8.33, 8.29, 8.26, 
8.21, 8.18, 8.16, 8.13, 8.12, 8.09, 8.06, 8.06, 8.03, 9.01, 8.99, 
8.96, 8.94, 8.91, 8.89, 8.86, 8.83, 8.82, 8.79, 8.78, 8.77, 8.75, 
8.75, 8.73, 8.7, 8.68, 8.66, 8.63, 8.59, 8.55, 8.52, 8.47, 8.43, 
8.4, 8.38, 8.35, 8.32, 8.31, 8.29, 8.26, 8.25, 8.23, 9.07, 9.06, 
9.04, 9.01, 8.99, 8.97, 8.94, 8.92, 8.91, 8.9, 8.89, 8.88, 8.88, 
8.87, 8.86, 8.84, 8.83, 8.8, 8.75, 8.74, 8.7, 8.67, 8.63, 8.59, 
8.57, 8.53, 8.52, 8.51, 8.47, 8.47, 8.45, 8.42, 8.41, 9.1, 9.08, 
9.06, 9.04, 9.02, 9, 8.98, 8.97, 8.96, 8.96, 8.95, 8.95, 8.97, 
8.96, 8.96, 8.94, 8.91, 8.89, 8.86, 8.84, 8.8, 8.76, 8.73, 8.69, 
8.67, 8.64, 8.63, 8.63, 8.61, 8.59, 8.57, 8.54, 8.53), wind_dir = c(81.27, 
81.34, 81.38, 81.44, 81.47, 81.34, 81.31, 81.51, 81.56, 81.46, 
81.54, 81.53, 81.42, 81.53, 81.66, 81.76, 81.86, 81.96, 82.02, 
82.28, 82.65, 82.77, 83.07, 83.46, 83.78, 84.15, 84.52, 84.92, 
85.39, 85.87, 86.15, 86.38, 86.53, 81.34, 81.34, 81.38, 81.31, 
81.2, 81.25, 81.39, 81.36, 81.31, 81.4, 81.47, 81.48, 81.59, 
81.64, 81.58, 81.62, 81.75, 81.98, 82.13, 82.26, 82.52, 82.77, 
82.97, 83.15, 83.49, 83.74, 84.23, 84.78, 85.04, 85.49, 85.73, 
86.05, 86.35, 81.5, 81.41, 81.32, 81.28, 81.32, 81.31, 81.24, 
81.17, 81.28, 81.33, 81.24, 81.3, 81.44, 81.46, 81.55, 81.76, 
81.8, 81.88, 82.11, 82.31, 82.4, 82.61, 82.88, 82.95, 83.29, 
83.59, 83.93, 84.46, 84.8, 85.26, 85.47, 85.78, 86.11, 81.3, 
81.29, 81.29, 81.28, 81.32, 81.22, 81.24, 81.32, 81.31, 81.23, 
81.34, 81.47, 81.37, 81.42, 81.5, 81.6, 81.78, 81.98, 82.06, 
82.26, 82.49, 82.52, 82.7, 82.79, 83.05, 83.46, 83.79, 84.18, 
84.5, 84.91, 85.23, 85.49, 85.7, 81.31, 81.33, 81.28, 81.19, 
81.26, 81.29, 81.36, 81.24, 81.16, 81.18, 81.23, 81.23, 81.23, 
81.47, 81.5, 81.55, 81.73, 81.99, 82.14, 82.18, 82.41, 82.46, 
82.63, 82.83, 82.97, 83.27, 83.62, 84.01, 84.34, 84.64, 85.01, 
85.38, 85.55, 81.14, 81.14, 81.1, 81.15, 81.2, 81.1, 81.14, 81.06, 
81.21, 81.26, 81.13, 81.16, 81.17, 81.22, 81.28, 81.63, 81.71, 
81.77, 82.13, 82.22, 82.37, 82.48, 82.56, 82.7, 82.92, 83.19, 
83.43, 83.74, 84.15, 84.59, 84.89, 85.22, 85.39)), row.names = c(NA, 
-198L), .Names = c("Lon", "Lat", "mean_wind", "wind_dir"), class = c("tbl_df", 
"tbl", "data.frame"))
like image 757
Lily Nature Avatar asked Dec 19 '17 06:12

Lily Nature


1 Answers

geom_spoke was made for this particular sort of plot. Cleaned up a little,

library(ggplot2)

ggplot(wind.dt, 
       aes(x = Lon , 
           y = Lat, 
           fill = mean_wind, 
           angle = wind_dir, 
           radius = scales::rescale(mean_wind, c(.2, .8)))) +
    geom_raster() +
    geom_spoke(arrow = arrow(length = unit(.05, 'inches'))) + 
    scale_fill_distiller(palette = "RdYlGn") + 
    coord_equal(expand = 0) + 
    theme(legend.position = 'bottom', 
          legend.direction = 'horizontal')

Adjust scaling and sizes as desired.


Edit: Controlling the number of arrows

To adjust the number of arrows, a quick-and-dirty route is to subset one of the aesthetics passed to geom_spoke with a recycling vector that will cause some rows to be dropped, e.g.

library(ggplot2)

ggplot(wind.dt, 
       aes(x = Lon , 
           y = Lat, 
           fill = mean_wind, 
           angle = wind_dir[c(TRUE, NA, NA, NA, NA)],    # causes some values not to plot
           radius = scales::rescale(mean_wind, c(.2, .8)))) +
    geom_raster() +
    geom_spoke(arrow = arrow(length = unit(.05, 'inches'))) + 
    scale_fill_distiller(palette = "RdYlGn") + 
    coord_equal(expand = 0) + 
    theme(legend.position = 'bottom', 
          legend.direction = 'horizontal')
#> Warning: Removed 158 rows containing missing values (geom_spoke).

This depends on your data frame being in order and is not infinitely flexible, but if it gets you a nice plot with minimal effort, can be useless nonetheless.

A more robust approach is to make a subsetted data frame for use by geom_spoke, say, selecting every other value of Lon and Lat, here using recycling subsetting on a vector of distinct values:

library(dplyr)

wind.arrows <- wind.dt %>% 
    filter(Lon %in% sort(unique(Lon))[c(TRUE, FALSE)], 
           Lat %in% sort(unique(Lat))[c(TRUE, FALSE)])

ggplot(wind.dt, 
       aes(x = Lon , 
           y = Lat, 
           fill = mean_wind, 
           angle = wind_dir, 
           radius = scales::rescale(mean_wind, c(.2, .8)))) +
    geom_raster() +
    geom_spoke(data = wind.arrows,    # this is the only difference in the plotting code
               arrow = arrow(length = unit(.05, 'inches'))) + 
    scale_fill_distiller(palette = "RdYlGn") + 
    coord_equal(expand = 0) + 
    theme(legend.position = 'bottom', 
          legend.direction = 'horizontal')

This approach makes getting (and scaling) a grid fairly easy, but getting a diamond pattern will take a bit more logic:

wind.arrows <- wind.dt %>% 
    filter(( Lon %in% sort(unique(Lon))[c(TRUE, FALSE)] & 
             Lat %in% sort(unique(Lat))[c(TRUE, FALSE)] ) | 
           ( Lon %in% sort(unique(Lon))[c(FALSE, TRUE)] & 
             Lat %in% sort(unique(Lat))[c(FALSE, TRUE)] ))

like image 181
alistaire Avatar answered Oct 16 '22 08:10

alistaire