Skip to contents

percentileRose plots percentiles by wind direction with flexible conditioning. The plot can display mutiple percentile lines or filled areas.


  pollutant = "nox",
  wd = "wd",
  type = "default",
  percentile = c(25, 50, 75, 90, 95),
  smooth = FALSE,
  method = "default",
  cols = "default",
  angle = 10,
  mean = TRUE,
  mean.lty = 1,
  mean.lwd = 3,
  mean.col = "grey",
  fill = TRUE,
  intervals = NULL,
  angle.scale = 45,
  auto.text = TRUE,
  key.header = NULL,
  key.footer = "percentile",
  key.position = "bottom",
  key = TRUE,



A data frame minimally containing wd and a numeric field to plot --- pollutant.


Mandatory. A pollutant name corresponding to a variable in a data frame should be supplied e.g. pollutant = "nox". More than one pollutant can be supplied e.g. pollutant = c("no2", "o3") provided there is only one type.


Name of the wind direction field.


type determines how the data are split i.e. conditioned, and then plotted. The default is will produce a single plot using the entire data. Type can be one of the built-in types as detailed in cutData e.g. “season”, “year”, “weekday” and so on. For example, type = "season" will produce four plots --- one for each season.

It is also possible to choose type as another variable in the data frame. If that variable is numeric, then the data will be split into four quantiles (if possible) and labelled accordingly. If type is an existing character or factor variable, then those categories/levels will be used directly. This offers great flexibility for understanding the variation of different variables and how they depend on one another.

Type can be up length two e.g. type = c("season", "weekday") will produce a 2x2 plot split by season and day of the week. Note, when two types are provided the first forms the columns and the second the rows.


The percentile value(s) to plot. Must be between 0--100. If percentile = NA then only a mean line will be shown.


Should the wind direction data be smoothed using a cyclic spline?


When method = "default" the supplied percentiles by wind direction are calculated. When method = "cpf" the conditional probability function (CPF) is plotted and a single (usually high) percentile level is supplied. The CPF is defined as CPF = my/ny, where my is the number of samples in the wind sector y with mixing ratios greater than the overall percentile concentration, and ny is the total number of samples in the same wind sector (see Ashbaugh et al., 1985).


Colours to be used for plotting. Options include “default”, “increment”, “heat”, “jet” and RColorBrewer colours --- see the openair openColours function for more details. For user defined the user can supply a list of colour names recognised by R (type colours() to see the full list). An example would be cols = c("yellow", "green", "blue")


Default angle of “spokes” is when smooth = FALSE.


Show the mean by wind direction as a line?


Line type for mean line.


Line width for mean line.


Line colour for mean line.


Should the percentile intervals be filled (default) or should lines be drawn (fill = FALSE).


User-supplied intervals for the scale e.g. intervals = c(0, 10, 30, 50)


The pollutant scale is by default shown at a 45 degree angle. Sometimes the placement of the scale may interfere with an interesting feature. The user can therefore set angle.scale to another value (between 0 and 360 degrees) to mitigate such problems. For example angle.scale = 315 will draw the scale heading in a NW direction.


Either TRUE (default) or FALSE. If TRUE titles and axis labels will automatically try and format pollutant names and units properly e.g. by subscripting the ‘2’ in NO2.


Adds additional text/labels to the scale key. For example, passing options key.header = "header", key.footer = "footer" adds addition text above and below the scale key. These arguments are passed to drawOpenKey via quickText, applying the auto.text argument, to handle formatting.




Location where the scale key is to plotted. Allowed arguments currently include "top", "right", "bottom" and "left".


Fine control of the scale key via drawOpenKey. See drawOpenKey for further details.


Other graphical parameters are passed onto cutData and lattice:xyplot. For example, percentileRose passes the option hemisphere = "southern" on to cutData to provide southern (rather than default northern) hemisphere handling of type = "season". Similarly, common graphical arguments, such as xlim and ylim for plotting ranges and lwd for line thickness when using fill = FALSE, are passed on xyplot, although some local modifications may be applied by openair. For example, axis and title labelling options (such as xlab, ylab and main) are passed to xyplot via quickText to handle routine formatting.


As well as generating the plot itself,

percentileRose also returns an object of class

“openair”. The object includes three main components:

call, the command used to generate the plot; data, the data frame of summarised information used to make the plot; and plot, the plot itself. If retained, e.g. using

output <- percentileRose(mydata, "nox"), this output can be used to recover the data, reproduce or rework the original plot or undertake further analysis.

An openair output can be manipulated using a number of generic operations, including print, plot and



percentileRose calculates percentile levels of a pollutant and plots them by wind direction. One or more percentile levels can be calculated and these are displayed as either filled areas or as lines.

The wind directions are rounded to the nearest 10 degrees, consistent with surface data from the UK Met Office before a smooth is fitted. The levels by wind direction are optionally calculated using a cyclic smooth cubic spline using the option smooth. If smooth = FALSE then the data are shown in 10 degree sectors.

The percentileRose function compliments other similar functions including windRose, pollutionRose, polarFreq or polarPlot. It is most useful for showing the distribution of concentrations by wind direction and often can reveal different sources e.g. those that only affect high percentile concentrations such as a chimney stack.

Similar to other functions, flexible conditioning is available through the type option. It is easy for example to consider multiple percentile values for a pollutant by season, year and so on. See examples below.

percentileRose also offers great flexibility with the scale used and the user has fine control over both the range, interval and colour.


Ashbaugh, L.L., Malm, W.C., Sadeh, W.Z., 1985. A residence time probability analysis of sulfur concentrations at ground canyon national park. Atmospheric Environment 19 (8), 1263-1270.

See also


David Carslaw


# basic percentile plot
percentileRose(mydata, pollutant = "o3")

# 50/95th percentiles of ozone, with different colours
percentileRose(mydata, pollutant = "o3", percentile = c(50, 95), col = "brewer1")

if (FALSE) {
# percentiles of ozone by year, with different colours
percentileRose(mydata, type = "year", pollutant = "o3", col = "brewer1")

# percentile concentrations by season and day/nighttime..
percentileRose(mydata, type = c("season", "daylight"), pollutant = "o3", col = "brewer1")