4
votes

I have a wind speed and direction times series and I am trying to make a plot that uses line segments to depict the windspeed and direction. I need to have a basic point scatter plot of windspeed vs time (which I can create) with a line segment from each point (which is where I am getting hung up.) The length of the line has to be proportional to the windspeed and the angle needs to the wind direction. I am using ggplot2 with the geom_segment, but because x is time I cannot figure the right formula to use for xend.

Here is an example of the dataframe:

  • DateTime WINDSPEED_MPH DIR
  • 8/29/2008 0:00 4.28 231
  • 8/29/2008 1:00 3.11 236
  • 8/29/2008 2:00 1.36 237
  • 8/29/2008 3:00 2.92 153
  • 8/29/2008 4:00 1.94 314
  • 8/29/2008 5:00 3.11 293
  • Here is my code so far:

    library(ggplot2) 
    library(lubridate)
    
    Gustav <- read.csv("C:/Users/ezco3/My Research/LPBF/Pontchartrain-Maurepas Surge Consortium/Projects/Lake Tilting Effect Graphic/Datasets/Gustav_NewCanal_Hydro&Metero.csv")
    
    Gustav$TS <- as.POSIXct(Gustav$DateTime, "%m/%d/%Y %H:%M", tz="America/Chicago")
    Gustav$DelY <- Gustav$WINDSPEED_MPH*sin(Gustav$DIR)/max(Gustav$WINDSPEED_MPH, na.rm=TRUE)
    Gustav$DelX <- Gustav$WINDSPEED_MPH*cos(Gustav$DIR)/max(Gustav$WINDSPEED_MPH, na.rm=TRUE)
    
    plt1 <- ggplot(data = Gustav, aes(x = TS, y =WINDSPEED_MPH))
    plt1 + geom_point(color="blue") + 
      geom_segment(data = Gustav, mapping=aes(x= TS, y = WINDSPEED_MPH, xend = TS + 18000*DelX, 
                   yend=WINDSPEED_MPH + 5*DelY),size=.1,color="red")
    

    And, that creates this: enter image description here

    The 18000 in front of DelX and the 5 in front of DelY are both arbitrary numbers that I found through trail and error. Basically, initially using just DelX and DelY (without multipliers) the lines were short and vertical, so I worked through different option until I found this pair which showed some direction to the line.

    However, the angles are not correct. At this stage, I do not understand how units work with time series objects in lubridate so I am lost as to how to figure the correct formula for xend.

    Any advice would be much appreciated.

    Thanks!!!

    2
    Can you provide a sample of your data for us to work with? Just paste the output of dput(Gustav) into your question. You don't need to paste the whole thing. 10 or 20 rows (e.g., dput(Gustav[1:20,])) should be enough. - eipi10
    Your angles appear to be stretched so that the segments are pointed up or down. My guess is that this is happening because the units on the x axis are not the same as the units on the y axis. Is there some factor that relates a units on the x axis and the y axis to a unit on the figure? Maybe you could then use the different factors instead of 18000. - Tedward
    It's not the different units per se, but the fact that the range of x values is different from the range of y values. In this case, the x-values are in seconds and the x-axis spans about 864000 seconds (10 days), while the y-axis is in mph and spans about 50 mph. 864000/50 = 17280, close to the 18000 scale factor that the OP came up with. But if, for example, we set the x-axis to be just 50 seconds in length (not that that would be useful here) the direction lines would be scaled properly. - eipi10
    To properly scale the direction lines, multiply DelX by the ratio of range of the xaxis to range of the yaxis. To get this exact, you should use coord_cartesian to set the x and y axis ranges and then take the ratio of their ranges as the scale factor. - eipi10

    2 Answers

    3
    votes

    Using the suggestions of @eipi10 to calculate the appropriate ratio and multiply by the change in x but not explicitly setting the coordinate limits, here's a solution that correctly displays wind directions of 45 degrees and the length of the segment corresponds to the windspeed.

    date <- seq(ymd('2012-04-07'),ymd('2013-03-22'), by = 'day')
    windspeed <- rnorm(n = length(date), mean = 5, sd = 1)
    dir <- rep((c(0,30,45,60,90)*(pi/180)), times = length(date)/5)
    
    data <- data.frame(date, windspeed, dir)
    
    rat <-as.numeric(interval(min(date), max(date))) / (max(windspeed) - min(windspeed))
    
    data <- data %>%
        mutate(DelY = windspeed * sin(dir)/(2*max(windspeed)),
               DelX  = rat * windspeed * cos(dir)/(2*max(windspeed)))
    
    
    
    plt1 <- ggplot(data = data, aes(x = date, y =windspeed))
    plt1 + geom_point(color="blue")+
      geom_segment(aes(x= date, y = windspeed, xend = date + DelX,
                       yend=windspeed + DelY),size=.1,color="red") +
      coord_fixed(ratio = rat)
    
    3
    votes

    If you are open to an alternative to geom_segment(), then you can use geom_text() with an ANSI (unicode) arrow symbol to get the desired output:

    ggplot(data = data, aes(x=date, y=windspeed)) + 
      geom_point() + 
      geom_text(aes(angle=-dir+90), label="→")