0

I am trying to make a wind vector plot, and the closest I have come is using ggplot2 and the tutorials here: https://theoceancode.netlify.app/post/wind_vectors/ and here: http://jason-doug-climate.blogspot.com/2014/08/weather-station-at-worldfish-hq-goes.html

First I'm going to specify some example data that has the same structure as I'm working with...some code is redundant for the example here but I'm leaving it in for continuity with what I'm working with.

library(tidyverse)

dat <- tibble(Date = seq(as.POSIXct('2018-08-01 00:00:00'), 
                         as.POSIXct('2018-08-12 00:00:00'), "hour"),
              WSMPS = rnorm(265,3,1),
              WDir = rnorm(265,180,75),
              month = 8,
              year = rep(2018))

vec_dat <- dat %>% 
  rename(ws=WSMPS, wd= WDir) %>%  
  filter(year==2018, month==8) %>% # redundant for example data
  mutate(hour = as.numeric(substr(Date,12,13)),
         bin = cut.POSIXt(Date, 
                          breaks = NROW(unique(Date))/4),
         u = (1 * ws) * sin((wd * pi / 180.0)), # convert to cartesian coordinate vectors
         v = (1 * ws) * cos((wd * pi / 180.0))) %>% 
  group_by(bin) %>% # bin the data into 4hr increments
  summarise(u=mean(u),
            v=mean(v)) %>% 
  mutate(bin = as.POSIXct(bin),
         date = as.Date(substr(bin, 1,10)),
         time = chron::as.times(substr(bin, 12,19)))

The closest I have come is using the code below

wind_scale <- 1 # this is a scaling factor not used at the moment so set to 1
y_axis <- seq(-5, 5, 5) 

ggplot(data = vec_dat, aes(x = bin, y = y_axis)) +
  # Here we create the wind vectors as a series of segments with arrow tips
  geom_segment(aes(x = date, xend = date + u*wind_scale, y = 0, yend = v*wind_scale), 
               arrow = arrow(length = unit(0.15, 'cm')), size = 0.5, alpha = 0.7) 

This creates a plot that looks good except that I would like to split the vectors into their respective bins (4 hour increments denoted by vec_dat$bin) instead of having all the vectors for a given day originate from the same point on the x axis. I've tried switching vec_dat$date for vec$dat$bin but then the math within geom_segment() no longer works and the plot originates from the bins but the vectors are all perfectly vertical as below:

ggplot(data = vec_dat, aes(x = bin, y = y_axis)) +
  # Here we create the wind vectors as a series of segments with arrow tips
  geom_segment(aes(x = bin, xend = bin + u*wind_scale, y = 0, yend = v*wind_scale), 
               arrow = arrow(length = unit(0.15, 'cm')), size = 0.5, alpha = 0.7)

UPDATE This appears to be a math problem. When I calculate the xend argument using bin instead of date the result is that the xend value is not scaled correctly as below:

test <- vec_dat[1:12,]
test$bin+test$u
test$date+test$u

So what is required is to use data as class Date within the xend formula...however this throws an error:

ggplot(data = vec_dat, aes(x = bin, y = y_axis)) +
  # Here we create the wind vectors as a series of segments with arrow tips
  geom_segment(aes(x = bin, xend = date + u*wind_scale, y = 0, yend = v*wind_scale), 
               arrow = arrow(length = unit(0.15, 'cm')), size = 0.5, alpha = 0.7)

Error: Invalid input: time_trans works with objects of class POSIXct only

So if anyone can help with this error or with a workaround I'd appreciate it.

dandrews
  • 967
  • 5
  • 18
  • Have you seen [this related question](https://stackoverflow.com/questions/64919147/how-can-i-make-a-feather-plot-in-r/64919685#64919685)? – Allan Cameron Dec 22 '20 at 00:21
  • I had not @AllanCameron. That example is what I'd like the plot to come out looking like, however my issue is the use of a simple numeric for the 'hour' variable compared to the datetime data that I am using. In my example the first plot is very near what I am hoping to achieve but you can see that every vector starts from the same point. I believe the issue is with the numeric equivalents for `date` and `bin` being drastically different, but I can't figure out a workaround – dandrews Dec 22 '20 at 14:47

1 Answers1

1

I think you are looking for something like this:

wind_scale <- 86400 # (seconds in a day)
y_axis <- seq(-5, 5, 5) 

ggplot(data = vec_dat, aes(x = bin, y = y_axis)) +
  geom_segment(aes(xend = bin + u * wind_scale, y = 0, yend = v), 
               arrow = arrow(length = unit(0.15, 'cm')), 
               size = 0.5, alpha = 0.7) +
  coord_fixed(ratio = wind_scale) # Preserves correct angle for wind vector

enter image description here

For what it's worth, I don't think having this many arrows on a single plot makes for a great visualization because there is a lot of clashing and overlap of arrows that makes it hard to read. Vertical faceting by day might make this easier to interpret.

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87
  • I agree...this will be broken out into individual days for our purposes...just trying to get the code working. I just happened to add an update to my question above. This looks like this will work. Could you help me understand why you don't specify the x argument in the call to `aes()` within the `geom_segment()` call? Not sure if my question makes sense but perhaps running my code from the update will clarify...you can see the error. – dandrews Dec 22 '20 at 16:11
  • 1
    @dandrews geoms all inherit any aes items that are specified in the initial call to ggplot – Allan Cameron Dec 22 '20 at 16:42