visualising diurnal wind climatologies

In this post I want to highlight the second core function of the metvurst repository (https://github.com/tim-salabim/metvurst):

The windContours function

It is intended to provide a compact overview of the wind field climatology at a location and plots wind direction and speed as a function of the hour of day.

  • direction is plotted as frequencies of occurrences
  • speed is represented by a box plot

The classical approach for visualising wind direction and speed at a location is to plot a wind rose where a stacked barplot of speeds is plotted in a circular coordinates system showing the direction. As an example of a wind rose we take the example from the Wikipedia page for “wind rose”.

alt text

This kind of representation is very useful for getting a general sense of the of the wind field climatology at a location.
You will be able to quickly get information along the lines of. “the x most prevailing wind directions are from here, there and sometimes also over there”. Furthermore, you will also know which of these tends to produce windier conditions. So far, so good.

If you want to learn about possible diurnal flow climatologies, however, there is no way of obtaining this information straight from the wind rose. The common way to achieve visualising such dynamics using wind roses is to plot individual roses for some specific period (e.g. hourly or 3 hourly roses).

Getting information on diurnal climate dynamics is especially important in regions of complex terrain or for coastal locations, where diurnally reversing wind flow patterns are a major climatic feature.

The windContours function is able to deliver such information at a glance.
Consider the case from the last post, where we used hourly meteorological information from a coastal station in Fiji.

First, we (again) read the data from the web at BOM (Australian Bureau Of Meteorology).

## LOAD RColorBrewer FOR COLOR CREATION
library(metvurst)
library(RColorBrewer)

## SET URL FOR DATA DOWNLOAD
url <- "http://www.bom.gov.au/ntc/IDO70004/IDO70004_"

## YEARS TO BE DOWNLOADED
yr <- 1993:2012

## READ DATA FOR ALL YEARS FROM URL INTO LIST
fijilst <- lapply(seq(yr), function(i) {
 read.csv(paste(url, yr[i], ".csv", sep = ""), na.strings = c(-9999, 999))
})

## TURN LIST INTO COMPLETE DATAFRAME AND CONVERT NA STRINGS TO NAs
fiji <- do.call("rbind", fijilst)
fiji[fiji == -9999] <- NA
fiji[fiji == -9999] <- NA
fiji[fiji == 999] <- NA

## CREATE POSIX DATETIME AND CONVERT UTC TO LOCAL FIJI TIME
dts <- as.POSIXct(strptime(fiji$Date...UTC.Time,
 format = "%d-%b-%Y %H:%M")) + 12 * 60 * 60

Next, we need to create a vector of the hours of the recordings in order to plot our hourly climatologies.

## CREATE CONDITIONING VARIABLE (IN THIS CASE HOUR)
hr <- substr(as.character(dts), 12, 13) 

Now, we can use the windContours function straight away to plot the hourly wind direction frequencies and corresponding wind speeds for the observation period 1993 – 2012.
Note, for reproducibility I have posted the function on my personal uni web page, but it is recommended that you get the function from the metvurst repository at git hub.

windContours(hour = hr,
             wd = fiji$Wind.Direction,
             ws = fiji$Wind.Speed,
             keytitle = "hourly wind frequencies [%]")

plot of chunk unnamed-chunk-3

Just as we would with a wind rose, we easily see that there are 3 main prevailing wind directions:

  1. north north-east
  2. south-east
  3. west north-west

However, we straight away realise that there is a distinct diurnal pattern in these directions with 1. and 2. being nocturnal and 3. denoting the daytime winds. This additional information is captured at a glance.

It is possible to refine the graph in a lot of ways.
In the next few figures I want to highlight a few of the flexibilities that windContours provides:

In order to adjust the x-axis of the speed plot, use the speedlim = parameter

windContours(hour = hr,
             wd = fiji$Wind.Direction,
             ws = fiji$Wind.Speed,
             speedlim = 12,
             keytitle = "hourly wind frequencies [%]")

plot of chunk unnamed-chunk-4

In case you want to change the density of the contour lines you can use spacing =

windContours(hour = hr,
             wd = fiji$Wind.Direction,
             ws = fiji$Wind.Speed,
             speedlim = 12,
             keytitle = "hourly wind frequencies [%]",
             spacing = .5)

plot of chunk unnamed-chunk-5

You can also provide colors through the colour = parameter

windContours(hour = hr,
             wd = fiji$Wind.Direction,
             ws = fiji$Wind.Speed,
             speedlim = 12,
             keytitle = "hourly wind frequencies [%]",
             colour = rev(brewer.pal(11, "Spectral")))

plot of chunk unnamed-chunk-6

You can adjust the number of cuts to be made using ncuts =

windContours(hour = hr,
             wd = fiji$Wind.Direction,
             ws = fiji$Wind.Speed,
             speedlim = 12,
             keytitle = "hourly wind frequencies [%]",
             colour = rev(brewer.pal(11, "Spectral")),
             ncuts = .5)

plot of chunk unnamed-chunk-7

Apart from the design, you can also adjust the position of the x-axis so that the plot is centered north (default is south) using the centre = parameter (allowed values are: “S”, “N”, “E”, “W”)

windContours(hour = hr,
             wd = fiji$Wind.Direction,
             ws = fiji$Wind.Speed,
             speedlim = 12,
             keytitle = "hourly wind frequencies [%]",
             colour = rev(brewer.pal(11, "Spectral")),
             centre = "N")

plot of chunk unnamed-chunk-8

There’s also the possibility to provide an additional variable using add.var = in order to examine the relationship between winds and some other parameter of interest (e.g. concentrations of some pollutant or precipitation or anything really). In doing so, the contours will remain as before (representing wind direction frequencies) and the (colour-)filled part of the left panel will be used to represent the additional variable.
Here, we’re using air temperature (don’t forget to change the keytitle) where we can easily see that cold air mainly comes from south (extra-tropical air masses) and highest temperatures are observed when air flow is from northerly directions (tropical air masses)

windContours(hour = hr,
             wd = fiji$Wind.Direction,
             ws = fiji$Wind.Speed,
             speedlim = 12,
             keytitle = "Temperature [°C]",
             colour = rev(brewer.pal(11, "Spectral")),
             add.var = fiji$Air.Temperature)

plot of chunk unnamed-chunk-9

In case you want to change the smoothing of the contours you can use the smooth.contours = parameter.
The same applies to the (colour-)filled area using smooth.fill =

windContours(hour = hr,
             wd = fiji$Wind.Direction,
             ws = fiji$Wind.Speed,
             speedlim = 12,
             keytitle = "Temperature [°C]",
             colour = rev(brewer.pal(11, "Spectral")),
             add.var = fiji$Air.Temperature,
             smooth.contours = .8,
             smooth.fill = 1.5)

plot of chunk unnamed-chunk-10

In the future I might present some analytical post making use of the windContours function to highlight its usefulness in climate analysis.
For now, I refer the interested reader to Appelhans et al. (2012) where I’m presenting the seasonal wind climatology of Christchurch, New Zealand and also analyse general diurnal patterns of air pollution using windContours.

sessionInfo()

 

## R version 2.15.3 (2013-03-01)
## Platform: x86_64-pc-linux-gnu (64-bit)
##
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C
##  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8
##  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8
##  [7] LC_PAPER=C                 LC_NAME=C
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] grid      parallel  stats     graphics  grDevices utils     datasets
## [8] methods   base
##
## other attached packages:
##  [1] gridBase_0.4-6      abind_1.4-0         fields_6.7
##  [4] spam_0.29-2         reshape_0.8.4       plyr_1.8
##  [7] latticeExtra_0.6-19 lattice_0.20-13     RColorBrewer_1.0-5
## [10] RWordPress_0.2-3    rgdal_0.8-5         raster_2.0-41
## [13] sp_1.0-5            knitr_1.1
##
## loaded via a namespace (and not attached):
## [1] digest_0.6.3   evaluate_0.4.3 formatR_0.7    markdown_0.5.4
## [5] RCurl_1.95-3   stringr_0.6.2  tools_2.15.3   XML_3.95-0
## [9] XMLRPC_0.2-5
This entry was posted in climatology, R, visualisation. Bookmark the permalink.

47 Responses to visualising diurnal wind climatologies

  1. ABC says:

    Hi metvurst
    I like very much this post, and I woudl like to use with my date, but the problem is that the example link doesn’t exist anymore(http://www.bom.gov.au/ntc/IDO70004/IDO70004_). Can you update it please, to use your example?

    Thanks very much

    • Tim Salabim says:

      Hey,
      the link you mention is just the base fragment of the entire link (in the code defined as url) which is pasted together with the respective year and the extension .csv in the line

      read.csv(paste(url, yr[i], “.csv”, sep = “”), na.strings = c(-9999, 999))

      Hence a link like this (base link + year + extension) http://www.bom.gov.au/ntc/IDO70004/IDO70004_1993.csv does indeed work.

      Hope that clarifies.

      Regards
      Tim

  2. ABC says:

    thanks,
    I will check it.

    Regards,
    Alexander

  3. ABC says:

    Hi Tim,
    Here again me, just I would like to post some suggestions for the people who want to use this tutorial, and are beginners like me.

    First of all you have to install the ‘metvurst’ package, and for do it you have to install the Rtools software, is better if you use the R version 3.0.0 because I had many problems trying to install this RTools with the R v. 3.0.1.

    Secondly, you have to run this packages or install them if you don’t have its. (I had installed almost all) :

    library(RColorBrewer)
    library(metvurst)
    library(lattice)
    library(latticeExtra)
    library(spam)
    library(maps)
    library(fields)
    library(abind)
    library(grid)
    library(gridBase)
    library(reshape)
    library(plyr)
    library(RWordPress) ## No installed
    library(rgdal)
    library(raster)
    library(sp)
    library(knitr)

    library(digest)
    library(evaluate)
    library(formatR)
    library(markdown)
    library(bitops)
    library(RCurl)
    library(stringr)
    library(tools)
    library(XML)
    library(XMLRPC) ### No installed

    library(parallel)
    library(stats)
    library(graphics)
    library(grDevices)
    library(utils)
    library(methods)
    library(base)

    bu with all of this list, still I can get the plots like this tutorial.
    Can you give an idea of what is the problem?

    because after typing all the code, at the end, I get this message:
    …….

    ..
    > windContours(hour = hr,
    + wd = fiji$Wind.Direction,
    + ws = fiji$Wind.Speed,
    + keytitle = “hourly wind frequencies [%]”)

    Error in grid.Call.graphics(L_downviewport, name$name, strict) :
    Viewport ‘plot_02.panel.1.1.off.vp’ was not found
    In addition: There were 12 warnings (use warnings() to see them)

    and additional there is not plot, I got only the titles and this message in the middle of the box:

    Error using packet 1
    e is no. Internal function “filledcontour”

    I know that this was a hard work for the Author, but if somebody want to use it, I want to show how complicate is it.

    Thanks,
    Alexander

  4. Tim Salabim says:

    Hey Alexander,
    thanks for pointing this out!

    see here

    http://stackoverflow.com/questions/16812528/filled-contour-in-r-3-0-x-throws-error

    apparently there has been a change in the base graphics C code as a result of the R 3.0.0 release. This means that the .Internal() calls are no longer functional. I will address this tomorrow and update the metvurst version on GitHub. In the meanwhile, if you follow the directions given in the link above, the code will work. Note, however, that in the standard plotting device things may not look as intended (as a result of mixing base and grid graphics). If you save your plot to the drive using png (or similar devices), it should come out correct.

    Btw, for some time now I have been considering to completely rewrite this function, so this might just be the perfect opportunity…

    Also, you do not need all he packages you mentioned for the code to work.
    The dependencies are written at the beginning of the function call:

    stopifnot(require(“latticeExtra”))
    stopifnot(require(“fields”))
    stopifnot(require(“abind”))
    stopifnot(require(“gridBase”))
    stopifnot(require(“RColorBrewer”))

    These are the packages that are needed for the code of this post to work

    Cheers
    Tim

  5. Tim Salabim says:

    UPDATE: windContours() has been updated on github. If you re-install metvurst from there the example code provided here (which has been updated so the function is no longer sourced from my staff page) should work again nicely.

  6. ABC says:

    Many Thanks for your help and update, but unfortunately I still have exactly the same problem.

    Have a nice day,
    Alexander

  7. ABC says:

    Hi Tim

    Suddenly, today I have tried it again, and now the example of this post works perfectly 🙂
    It is maybe because the update took effect after my PC was turned off.

    Thanks very much Tim, it is a great package.

    Now I am going to try it with my climate data. If I have questions I will post it because I have still many problems with the date time configuration.

    My best regards,
    Alexander

  8. ABC says:

    Hi Tim,

    I have used your metvurst package and it works very well,
    but I have some questions:

    1. What means the numbers ” + 12 * 60 * 60″ after format ?

    ## CREATE POSIX DATETIME AND CONVERT UTC TO LOCAL FIJI TIME
    dts <- as.POSIXct(strptime(fiji$Date…UTC.Time,
    format = "%d-%b-%Y %H:%M")) + 12 * 60 * 60

    because when I use theses my hour date changes to inverse position.

    2. How can I plot the month names in English if I have this date-time format:?

    "%d.%m.%Y %H:%M" e.g.: 27.05.2007 01:00
    because in my plotted graph I get the months always in Spanish.

    Thanks,
    Alexander

    • Tim Salabim says:

      1. This is as it says in the comment above the line. The UTC time of the data is converted to local Fiji time. Fiji is 12 hours ahead of UTC, so we need to add 12 hrs. As POSIXct is in seconds, we need 60*60*12 to get hrs. So, if your data is in local time not UTC, then you need to remove these numbers to use the original dates of your data.

      2. I am not sure about your second question, but I think this has to do with the system settings of your computer. Maybe this one here helps:

      http://mito.air-nifty.com/mitoakiyoshiblog/2011/01/how-to-change-l.html

      Cheers
      Tim

  9. ABC says:

    Thanks very much for your answer, I will check the link.

    Ein schöner Tag,
    Alexander

  10. ABC says:

    Hi Tim,
    Sorry, another question:

    What means the number 12 and 13 in this code:

    ## CREATE CONDITIONING VARIABLE (IN THIS CASE HOUR)
    hr <- substr(as.character(dts), 12, 13)

    Thanks,
    Alexander

  11. Tim Salabim says:

    Hi Alexander,
    substr means substring. With this function you can extract certain parts of a character string. For example if you have a character string

    x <- "abcdfghijk"

    then substr(x, 9, 10) would be the ninth and tenth position of this string, that is "jk".

    In the code above I am simply extracting the relevant positions of the hour values of the datetime object dts.

    Hope that clarifies.

    Tim

  12. ABC says:

    Thanks Tim,
    Thanks for your clarification.

    and how I should cite your package or function?

    Many thanks,
    Alexander

  13. Tim Salabim says:

    Unfortunately there is no official document about the package (yet) that you could cite. What you could do is the following:

    Appelhans, T. et al.: metvurst R package. Published under GNU GPL v3 and available online at https://github.com/tim-salabim/metvurst.

    This should be appropriate.

    Cheers
    Tim

    If I might ask, what are you using the package for?

  14. ABC says:

    ok, I will use like that.

    Of course you can ask it, I’m using it to analyze my climate data to write a paper for my PhD, because I like very much how this package makes the Plots.

    I was thinking if is possible to make the plot with WindContours showing the Months instead of hours, and if it is possible how can I do it?. Sorry for many questions.

    Cheers,
    Alexander

    • Tim Salabim says:

      Nice, what’s the PhD about? And where do you study?

      It should be quite easy to modify the function so that we can plot months vs. direction. Give me a couple of days to rework the code and update the package on GitHub.

      Cheers
      Tim

      • Tim Salabim says:

        In the meantime you could try this (lines 1- 213 is the function definition – example with random data at the end):

        
        windContours <- function (month = month, 
                                  wd = wd, 
                                  ws = ws,
                                  add.var,
                                  smooth.contours = 1.2,
                                  smooth.fill = 1.2,
                                  spacing = 2,
                                  centre = "S",
                                  speedlim = 7,
                                  labels = T,
                                  stripname = "",
                                  keytitle = "",
                                  keyint = c(0, 15),
                                  keyspacing = 1,
                                  ncuts = 0.1,
                                  gapcolor = "grey50",
                                  colour = brewer.pal(9, "Greys"),
                                  ...) {
          
          
          stopifnot(require("latticeExtra"))
          stopifnot(require("fields"))
          stopifnot(require("abind"))
          stopifnot(require("gridBase"))
          stopifnot(require("RColorBrewer"))
          
          cols <- colorRampPalette(colour)
          
          dircat_s <- ordered(ceiling(wd/10), levels=1:36, labels=1:36)
          dircat_n <- ordered(ceiling(wd/10), levels=c(19:36, 1:18), labels=1:36)
          dircat_w <- ordered(ceiling(wd/10), levels=c(10:36, 1:9), labels=1:36)
          dircat_e <- ordered(ceiling(wd/10), levels=c(28:36, 1:27), labels=1:36)
          
          dircat <- {if (centre=="N") dircat_n else
            if (centre=="E") dircat_e else
              if (centre=="S") dircat_s else
                dircat_w }
          
          labels_s <- c(45,90,135,180,225,270,315,360)
          labels_n <- c(225,270,315,360,45,90,135,180)
          labels_e <- c(315,360,45,90,135,180,225,270)
          labels_w <- c(135,180,225,270,315,360,45,90)
          
          label <- {if (centre=="N") labels_n else
            if (centre=="E") labels_e else
              if (centre=="S") labels_s else
                labels_w }
          
          tab.wd <- xtabs(~ dircat + month)
          tab.wd_smooth <- image.smooth(tab.wd, theta = smooth.contours, 
                                        xwidth = 0, ywidth = 0)
          
          freq.wd <- matrix(prop.table(tab.wd_smooth$z,2)[, 12:1]*100,
                            nrow=36,ncol=12)
          
          tab.add <- if (missing(add.var)) tab.wd else
            xtabs(add.var ~ dircat + month) / tab.wd
          
          tab.add_smooth <- image.smooth(tab.add, theta = smooth.fill, 
                                         xwidth = 0, ywidth = 0)
          
          mat.add <- if (missing(add.var)) 
            matrix(prop.table(tab.add_smooth$z, 2)[, 12:1] * 100, 
                   nrow = 36, ncol = 12) else
                     tab.add_smooth$z[, 12:1]
          
          zlevs.fill <- if (missing(keyint)) seq(floor(min(mat.add)), 
                                                 ceiling(max(mat.add)),
                                                 by = ncuts)
          else seq(keyint[1], keyint[2], by = ncuts)
          
          zlevs.conts <- if (missing(keyint)) seq(floor(min(freq.wd)), 
                                                  ceiling(max(freq.wd)),
                                                  by = spacing)
          else seq(keyint[1], keyint[2], by = spacing)
          
          panel.filledcontour <- function(x, y, z, subscripts, at, fill.cont = T,
                                          col.regions = cols, 
                                          contours = T, 
                                          col = col.regions(length(zlevs.fill)), 
                                          ...)
          {
            stopifnot(require("gridBase"))
            z <- matrix(z[subscripts],
                        nrow = length(unique(x[subscripts])),
                        ncol = length(unique(y[subscripts])))
            if (!is.double(z)) storage.mode(z) <- "double"
            opar <- par(no.readonly = TRUE)
            on.exit(par(opar))
            if (panel.number() > 1) par(new = TRUE)
            par(fig = gridFIG(), omi = c(0, 0, 0, 0), mai = c(0, 0, 0, 0))
            cpl <- current.panel.limits()
            plot.window(xlim = cpl$xlim, ylim = cpl$ylim,
                        log = "", xaxs = "i", yaxs = "i")
            # paint the color contour regions
            if (isTRUE(fill.cont)) 
              .filled.contour(as.double(do.breaks(cpl$xlim, 
                                                  nrow(z) - 1)),
                              as.double(do.breaks(cpl$ylim, 
                                                  ncol(z) - 1)),
                              z, levels = as.double(zlevs.fill), 
                              col = col)
            else NULL
            if (isTRUE(fill.cont)) 
              .filled.contour(as.double(do.breaks(cpl$xlim, 
                                                  nrow(z) - 1)),
                              as.double(do.breaks(cpl$ylim, 
                                                  ncol(z) - 1)),
                              z, levels = as.double(seq(0,0.2,0.1)), 
                              col = gapcolor)
            else NULL
            #add contour lines
            if (isTRUE(contours)) 
              contour(as.double(do.breaks(cpl$xlim, nrow(z) - 1)),
                      as.double(do.breaks(cpl$ylim, ncol(z) - 1)),
                      z, levels = as.double(zlevs.conts), 
                      add=T,
                      col = "grey10", # color of the lines
                      drawlabels = labels  # add labels or not
              )
            else NULL
            if (isTRUE(contours))
              contour(as.double(do.breaks(cpl$xlim, nrow(z) - 1)),
                      as.double(do.breaks(cpl$ylim, ncol(z) - 1)),
                      z, levels = as.double(0.5), 
                      add=T,
                      col = "grey10", lty = 3,# color of the lines
                      drawlabels = labels  # add labels or not
              )
            else NULL
          }
          
          out.fill <- levelplot(mat.add, 
                                panel = function(fill.cont, contours, ...) {
                                  grid.rect(gp=gpar(col=NA, fill=gapcolor))
                                  panel.filledcontour(fill.cont = T, 
                                                      contours = F, ...)
                                },
                                col.regions = cols,
                                plot.args = list(newpage = FALSE))
          
          out.conts <- levelplot(freq.wd, 
                                 panel = function(fill.cont, contours, ...) {
                                   panel.filledcontour(fill.cont = F, 
                                                       contours = T, ...)
                                 },
                                 col.regions = cols,
                                 plot.args = list(newpage = FALSE),
                                 colorkey = list(space = "top", at = zlevs.fill, 
                                                 width = 1, height = 0.75, 
                                                 labels = 
                                                   list(at = 
                                                          seq(zlevs.fill[1],
                                                              zlevs.fill[length(zlevs.fill)],
                                                              spacing),
                                                        cex = 0.7),
                                                 col = cols))
          
          out.speed <- bwplot(rev(month) ~ ws, xlim = c(-0.25, speedlim), 
                              ylim = 12.5:0.5, scales = list(x = list(draw = T), 
                                                             y=list(draw = F)), 
                              xlab = NULL, ylab = NULL)
          
          out.blank <- xyplot(month ~ ws, xlim = c(-0.5, speedlim), ylim = 12.5:0.5, 
                              scales = list(x = list(draw = T), y=list(draw= F )), 
                              xlab = NULL, ylab = NULL, type = "n")
          
          addvar.combo <- c(out.fill, out.blank, x.same = F, y.same = F)
          addvar.out <- update(addvar.combo, layout = c(2, 1))
          conts.combo <- c(out.conts, out.speed, x.same = F, y.same = F)
          
          out.global <- update(conts.combo, layout = c(2, 1), strip = F, 
                               strip.left = strip.custom(
                                 bg = "grey40", par.strip.text = list(col = "white", 
                                                                      font = 2), 
                                 strip.names = F, strip.levels = T, 
                                 factor.levels = c("A", stripname)),
                               scales = list(x = list(draw = F), y = list(draw = F)),
                               par.settings = list(
                                 layout.heights = list(axis.xlab.padding = 6), 
                                 layout.widths = list(strip.left = c(0, 1)),
                                 plot.symbol = list(pch = "*", col = "black"), 
                                 box.umbrella = list(lty = 1, col = "grey40"),
                                 box.rectangle = list(col = "grey40")),
                               pch = 20, fill = "grey70", cex = 0.7,
                               xlab = list(c("Direction [degrees]", 
                                             "Speed [m/s]"), cex = 1), 
                               ylab = "Month\n\n", main = list(keytitle, cex = 1))
          
          y.at <- seq(11, 1, -2)
          y.labs <- seq(2, 12, 2)
          
          axislabGLOBAL <-  function() {  
            trellis.focus("panel", 1, 1, clip.off = T, highlight = F)
            panel.axis(side = "bottom", outside = T, at = seq(4.5, 36 ,by = 4.5), 
                       labels = label, text.cex = 0.8)
            panel.axis(side = "left", outside = T, at = y.at, labels = y.labs, 
                       text.cex = 0.8, check.overlap = T)
            trellis.focus("panel", 2, 1, clip.off = T, highlight = F)
            panel.axis(side = "bottom", outside = T, 
                       at = pretty(0:speedlim), rot = 0,
                       labels = pretty(0:speedlim), text.cex = 0.8)
            panel.axis(side = "right", outside = T, at = y.at, labels = NULL, 
                       text.cex = 0.8)
            trellis.unfocus()
          }
          
          par(bg = "white")
          plot.new()
          print(out.global + as.layer(addvar.out, x.same = F, y.same = T, 
                                      axes = NULL, under = T))
          axislabGLOBAL()
        }
        
        
        ## example
        set.seed(123)
        months <- rep(1:12, 10)
        wd <- rnorm(120, 180, 70)
        ws <- rnorm(120, 7, 2)
        
        windContours(month = months, wd = wd, ws = ws, speedlim = 14)
        
        
  15. ABC says:

    Thanks Tim, I will try using this code because also I would like to see the months in the X-axis.
    My study is about the climate reconstruction with dendrochronological methods in southern Ecuador.

    Herzlischen grüße,
    Alexander

  16. Peter Gibson says:

    Great stuff!
    I am an MSc student supervised by Marwan Katurji (who I think you previously worked with at Canterbury?)- who suggested to me trying to reproduce this sort of thing to analyse the sea breeze in my data set- I then stumbled upon your blog

    I have got this going for the BOM data you suggested. However for my dataset wind speed and wind direction are recorded at 10 minute averages….would I need to modify the windcontour code to readjust for this? – I realize I could convert to hourly averages pretty easy- and just run this code in its current form- but averaging wind directions would seem dodgy to me given the coordinate system?

    Any help would be great

    • Tim Salabim says:

      The package includes helper functions for averaging wind direction.

      If you first run wdws2uv(wd, ws), then aggregate the u&v components to one hour and then reconvert using uv2wd(u, v) you can use the function as above.

      Averaging wind direction via the u and v components in common practice and not dodgy at all.

      Hope this helps,
      Tim

  17. Peter Gibson says:

    Hi Tim,
    Thanks for your help before…I have converted these into hourly wind directions now with the help of those 2 functions, but am having some trouble producing these plots with my data still (I am pretty new to R still so probably an easy fix).

    My new file has just 3 coloms/variables (hour, wd, ws), I have read the data file into R using
    porteous <- read.delim("S:/System/Desktop/mydata/porteous.txt") but I am not sure how much of the above script (that you gave at the start of this blog post) I need to use to get into the correct format to run 'windContours' ie. after reading the data do I need to do the "#turn list into completer dataframe…." and the "#create posix datetime….." and the "#create conditioning variable.." sections?- or can some of these be ignored now given the format of my file?

    Thanks in advanced

  18. Peter Gibson says:

    just to follow up on this… I think all I would need would be:
    porteous <- read.delim("S:/System/Desktop/mydata/porteous.txt")
    windContours(hour = porteous$hour, wd = porteous$wd, ws= porteous$ws, keytitle = "hourly wind frequencies [%]")

    ….seems to be working anyway, and this is on Windows with an oldish version of R
    Cheers

  19. Hello,

    I’m still beginner in R, I wonder how do I read the script data that is on my pc, the data are on the same scale and format of the BOM listed, but I will replace by my data, how do I modify the location the input R?

    • Tim Salabim says:

      If you have a .csv file the easiest is to use read.csv(“/path/to/your/file.csv”).
      I guess you best refer to the help pages or general topics on the R-help lists or some introductory tutorial if you have problems loading your data into R.

      HTH
      Tim

  20. Hi Tim, could be entered in the database, the script looked like this:
    ## LOAD RColorBrewer FOR COLOR CREATION
    library(metvurst)
    library(RColorBrewer)

    ## SET DATA
    setwd(“E:/INICIAÇÃO CIENTÍFICA/Cuiarana/Vento Scripts R/Exemplos/”)

    ## READ DATA
    fijilst <- read.csv("IDO70004_1993.csv", na.strings = c(-9999, 999))

    ## TURN LIST INTO COMPLETE DATAFRAME AND CONVERT NA STRINGS TO NAs
    fiji <- do.call("rbind", fijilst)
    fiji[fiji == -9999] <- NA
    fiji[fiji == -9999] <- NA
    fiji[fiji == 999] <- NA

    ## CREATE POSIX DATETIME AND CONVERT UTC TO LOCAL FIJI TIME
    dts <- as.POSIXct(strptime(fiji$Date…UTC.Time,
    format = "%d-%b-%Y %H:%M")) + 12 * 60 * 60

    ## CREATE CONDITIONING VARIABLE (IN THIS CASE HOUR)
    hr <- substr(as.character(dts), 12, 13)

    windContours(hour = hr,
    wd = fiji$Wind.Direction,
    ws = fiji$Wind.Speed,
    speedlim = 12,
    keytitle = "hourly wind frequencies [%]",
    colour = rev(brewer.pal(11, "Spectral")),
    centre = "N")

    but when it will run the "format ="% d-% b-% Y% H:% M the following error ")) + 12 * 60 * 60" appears: Error in fiji $ Date … UTC.Time: $ operator is invalid for atomic vectors
    How do I solve this problem?

    My goal is to run this script to show the effects of breezes. Had the script as we select a particular month to view the diurnal cycle of winds? I wanted to show a specific month during the wet season, and one for the dry season.

    Thank You!

    • Tim Salabim says:

      Well, it all depends on what your data looks like. The error you get is most likely due to different variable names (i.e. your data variable is not “Date…UTC.Time”).
      To figure out what your data looks like (and what your variables are called) you could use the str() function. See ?str for details.
      In general, the wind variables (wd and ws) need to be numeric and hour needs to be of class POSIXct. Use the respective as.***() functions for conversion.

      As for your last question, use subsets containing data only for the months you want to analyse and plot them separately.

      If you are really stuck, you could maybe send me your data and I have a quick look at how to solve your problem(s).

      Cheers
      Tim

      • What’s your email so I can pass the data?

      • Dear Tim,

        I put the function str (fiji), but apparently is correct Date…UTC.Time, really wish you could check the data to see what error. I just replace the WD and WS for my data, this can cause a problem?

        Here is a piece of data
        Date & UTC Time,Sea Level,Water Temperature,Air Temperature,Barometric Pressure,Residuals,Adjusted Residuals,Wind Direction,Wind Gust,Wind Speed,Lautoka, Fiji
        01-Jan-1993 00:00, 1.812, 28.4, 29.3, 996.3, 0.109,-0.060,58.05 , 6.6, 2.32
        01-Jan-1993 01:00, 1.794, 28.4, 29.6, 996.0, 0.113,-0.057,66.00 , 7.0, 2.26
        01-Jan-1993 02:00, 1.677, 28.4, 29.7, 995.0, 0.114,-0.057,70.31 , 7.5, 1.99
        01-Jan-1993 03:00, 1.507, 28.5, 29.6, 994.3, 0.129,-0.054,72.35 , 7.6, 1.44
        01-Jan-1993 04:00, 1.293, 28.7, 29.6, 993.8, 0.124,-0.065,81.97 , 7.0, 1.07
        01-Jan-1993 05:00, 1.105, 28.6, 29.4, 994.1, 0.120,-0.073,182.73 , 6.3, 1.20
        01-Jan-1993 06:00, 0.981, 28.5, 27.8, 994.3, 0.108,-0.083,185.97 , 6.8, 1.21
        01-Jan-1993 07:00, 0.977, 28.5, 28.0, 994.7, 0.118,-0.070,176.00 , 4.7, 0.89
        01-Jan-1993 08:00, 1.037, 28.5, 28.0, 995.4, 0.097,-0.087,136.53 , 5.5, 0.80
        01-Jan-1993 09:00, 1.183, 28.5, 28.2, 995.6, 0.093,-0.084,127.78 , 5.5, 0.65
        01-Jan-1993 10:00, 1.355, 28.3, 27.4, 995.6, 0.087,-0.088,80.87 , 6.1, 1.33
        01-Jan-1993 11:00, 1.521, 28.3, 26.8, 994.8, 0.098,-0.078,79.02 , 5.9, 1.96
        01-Jan-1993 12:00, 1.648, 28.4, 27.0, 993.8, 0.134,-0.050,45.15 , 5.4, 1.77
        01-Jan-1993 13:00, 1.655, 28.3, 26.3, 993.0, 0.133,-0.061,188.77 , 6.0, 1.68
        01-Jan-1993 14:00, 1.567, 28.4, 26.3, 991.8, 0.129,-0.073,217.63 , 5.2, 1.37
        01-Jan-1993 15:00, 1.417, 28.3, 26.3, 991.2, 0.134,-0.080,202.03 , 8.0, 0.89
        01-Jan-1993 16:00, 1.245, 28.1, 26.7, 990.6, 0.147,-0.073,159.95 , 6.2, 0.71
        01-Jan-1993 17:00, 1.081, 27.7, 27.1, 991.0, 0.151,-0.074,110.24 , 6.9, 0.46
        01-Jan-1993 18:00, 0.962, 27.6, 26.5, 991.4, 0.132,-0.088,230.42 , 7.0, 0.47
        01-Jan-1993 19:00, 0.982, 27.5, 26.4, 991.3, 0.156,-0.062,102.40 , 6.8, 0.35
        01-Jan-1993 20:00, 1.078, 27.5, 27.1, 991.2, 0.155,-0.063,159.85 , 6.3, 0.38
        01-Jan-1993 21:00, 1.220, 27.8, 27.0, 991.0, 0.122,-0.098,138.33 , 8.6, 0.34
        01-Jan-1993 22:00, 1.451, 28.0, 25.8, 991.3, 0.141,-0.079,155.88 , 7.5, 0.57
        01-Jan-1993 23:00, 1.654, 27.9, 24.2, 989.7, 0.139,-0.081,94.47 , 8.7, 0.76
        02-Jan-1993 00:00, 1.825, 27.8, 24.6, 988.6, 0.158,-0.076,65.43 , 6.7, 1.10
        02-Jan-1993 01:00, 1.933, 27.8, 26.1, 986.1, 0.197,-0.050,175.48 , 8.0, 0.62
        02-Jan-1993 02:00, 1.920, 27.9, 26.7, 983.4, 0.219,-0.053,175.18 , 9.2, 0.62
        02-Jan-1993 03:00, 1.793, 28.0, 27.0, 980.7, 0.225,-0.075,160.08 , 10.4, 0.75
        02-Jan-1993 04:00, 1.601, 27.9, 25.8, 978.5, 0.235,-0.089,175.33 , 11.5, 0.56
        02-Jan-1993 05:00, 1.383, 27.9, 24.5, 975.5, 0.245,-0.104,79.33 , 12.2, 0.65
        02-Jan-1993 06:00, 1.197, 27.8, 24.9, 974.1, 0.255,-0.120,67.24 , 13.3, 0.82
        02-Jan-1993 07:00, 1.104, 27.9, 25.4, 970.2, 0.281,-0.112,71.18 , 13.4, 1.12
        02-Jan-1993 08:00, 1.145, 27.9, 24.6, 968.0, 0.340,-0.090,45.05 , 18.6, 2.52
        02-Jan-1993 09:00, 1.141, 27.8, 24.6, 966.4, 0.251,-0.200,39.13 , 16.2, 12.78
        02-Jan-1993 10:00, 1.324, 27.6, 25.4, 965.4, 0.279,-0.188,34.83 , 16.7, 12.68
        02-Jan-1993 11:00, 1.425, 27.4, 25.3, 968.2, 0.195,-0.278,33.11 , 18.8, 12.83
        02-Jan-1993 12:00, 1.463, 27.3, 25.3, 970.8, 0.068,-0.377,31.28 , 16.1, 3.12
        02-Jan-1993 13:00, 1.545, 27.3, 25.7, 973.9, 0.043,-0.375,38.13 , 16.3, 3.29
        02-Jan-1993 14:00, 1.509, 27.3, 25.1, 977.8,-0.011,-0.399,36.45 , 16.8, 3.41
        02-Jan-1993 15:00, 1.424, 27.3, 24.8, 980.7,-0.017,-0.365,30.75 , 12.9, 3.30
        02-Jan-1993 16:00, 1.327, 27.2, 25.1, 981.8, 0.037,-0.286,34.43 , 10.8, 2.64
        02-Jan-1993 17:00, 1.120, 27.2, 25.4, 984.1, 0.015,-0.296,30.24 , 9.0, 2.29
        02-Jan-1993 18:00, 0.937, 27.3, 25.4, 986.1,-0.004,-0.291,33.52 , 10.2, 2.17
        02-Jan-1993 19:00, 0.824, 27.3, 25.5, 987.6,-0.019,-0.288,42.52 , 11.4, 2.09
        02-Jan-1993 20:00, 0.809, 27.3, 25.2, 989.6,-0.033,-0.286,39.86 , 10.5, 2.15
        02-Jan-1993 21:00, 0.877, 27.2, 25.6, 990.4,-0.071,-0.304,49.79 , 10.1, 1.89
        02-Jan-1993 22:00, 1.059, 27.3, 26.0, 990.9,-0.074,-0.300,51.86 , 9.8, 1.57
        02-Jan-1993 23:00, 1.278, 27.3, 26.7, 992.0,-0.080,-0.301,59.18 , 8.6, 1.50

      • Tim Salabim says:

        Michel, just check your email. I just wrote you so you can send me the data and I’ll have a look Cheers Tim

      • Hello Tim,

        I did not receive your email, send to the following e-mail: michellfgermano@gmail.com

        I await your contact.
        Thank you

  21. Jean-Paul Huys says:

    Hello Tim,
    I get the following error message when I run windContours:

    Error in prop.table(tab.wd_smooth$z, 2)[, 24:1] : subscript out of bounds

    I cannot figure out what it means.
    Additionally, is it possible to keep the scale of the “%wind frequencies” constant (the same scale) for different graphs, in order to compare different sites or stations

    Thanks,
    Jean-Paul

    • Tim Salabim says:

      Hey, Jean-Paul,
      are your hours in 1-24? in case they are not (e.g they are in 0-23) try adding one hour and see if that fixes the problem.
      Regarding the fixed scale, I think the ‘levint’ argument is what you’re after. Setting ‘levint = c(0, 12)’ will adjust the colouring to ‘seq(0, 12, by = ncuts)’. ‘ncuts’ can also be set.

      I hope that clarifies.

      Tim

  22. Darwin Alexander says:

    Dear Tim,
    I’m working with seasonal and monthly data, and I would like to make a plot exactly like your Figure 1 and Figure 8 of your article “Appelhans et al. (2012)”. Can you please give me some direction about how to plot multiple figures together sharing the same scale?. I suppose it works with the “lattice” package, but I don’t know exactly how to set a Layout to put all my WindContours figures together. I will be very grateful with your help.

    Kind regards,
    Darwin Alexander

    • Tim Salabim says:

      Hey Darwin,
      I am sorry, but this is currently not possible. The code used to produce those figures has never made it into metvurst (so far), but it has been on my list for a while. I will try to come up with a solution, but cannot promise when. Till then, the only option for you is to produce each plot separately and combine them using some software like Inkscape.

      I am sorry that I have no better news, but I will try to make this happen asap.

      Cheers
      Tim

  23. baris onol says:

    Dear Tim,
    This package is highly efficient but do you have documentation for metvurst?
    It would be nice to have documentation.

    Best

    Baris Onol

    • Tim Salabim says:

      Hey Baris,
      I am sorry but I have been very slack so far regarding the documentation.
      I will try my best to update the documentation soon.
      In the meanwhile, feel free to ask any specific questions you may have here.

      Cheers
      Tim

  24. baris onol says:

    Hi Tim,
    my question is that is there any problem if we use hour data format like “01 02 … 23 24”?
    using 24 instead of 00?
    Can we define color (or contour) levels by our self?

    Best

    Baris

    • Tim Salabim says:

      Baris,
      regarding you first question, I think it does matter, though I have myself not used the function for a long time. Best you try and if you see an error, why not simply shift the hr vector by 1?

      The second question is already answered in the post.

      Cheers
      Tim

      • baris onol says:

        I had a problem since my hour format is 1 2 3… 24. The windContours gave a wrong result. then I realized that the hour format should be definitely like 00 01 02 03 04 … 23 . I solved the problem finally.
        for defining color level, levint or keyin should be specified?

      • Tim Salabim says:

        Baris,
        for defining the the range to be visualised (i.e. the range of the colours) use levint. For adjusting the number of colour regions use ncuts (which denotes the stepsize of the colour change).

        Does this answer your question?

        Cheers
        Tim

  25. baris onol says:

    Thank you for your help Tim. It is working properly now.
    Finally, Is there a way to use irregular level increment?
    Is there a way to change contour levels like 26,27,28,29,30,35,40?
    Best,

    Baris

    • Tim Salabim says:

      Baris,
      at the moment this is not possible. You can specify the minimum and maximum via levint and the step size via ncuts which is then passed to seq(levint[1], levint[2], ncuts). This will obviously create a regular sequence. I will try to add additional functionality over the weekend. I’ll get back to you as soon as I have edited the function.

      Cheers
      Tim

  26. fafa chan says:

    Hi, Tim,

    Your package is really impressive.
    I can run your example without any problem.
    I wonder if I have a wind direction, wind speed data set with every 4 second, can I plot the WindContours by second?
    The data set is something like 2014-12-30 00:00:06, 2014-12-30 00:00:11… something like this.

    Thanks.

    -fafa

    • Tim Salabim says:

      Hey Fafa,
      thanks for the nice words.
      In theory this is no problem. Yet, I would need to implement this first, which may take some time.
      Also, how many seconds did you want to display? The current implementation shows 24 hrs on the y-axis. How many seconds will you end up with? I am asking because this will alter the appearance of the plot drastically.
      I am currently also working on restructuring the code of metvurst, so that it becomes more user friendly. So, please can you file a feature request on the github site, so I don’t forget to address this.

      Best regards,
      Tim

Leave a reply to Tim Salabim Cancel reply