Recent Releases of openair
openair - openair 3.1.0
Dependency Changes
{openair}now suggests{rnaturalearth}over{rnaturalearthdata}.{rnaturalearthdata}is still required for a medium map resolution and{rnaturalearthhires}for a high map resolution, but these are now managed by{rnaturalearth}directly.
Breaking Changes
-
strip.position,x.relation, andy.relationare now no longer function-level arguments and are handled via.... -
The
labelsargument (as paired withbreaks) is deprecated. If passed through...it will be automatically mapped to its new place in thebreakOpts()function.
New Features
-
Refinements to how parameters are passed via
...to plotting functions:-
Graphical parameters are now defined using
ggplot2conventions (e.g.,shapeoverpch). -
base/latticeparamters are automatically remapped to theirggplot2equivalent with a warning. -
nrowandncolcan now be provided to control facet layout. As above,layoutis automatically unpacked intoncolandnrowwith a warning. -
scalescan now be provided to control facet scale restrictions. As above,x.relationandy.relationare automatically combined intoscaleswith a warning. -
space,axes,axis.labels,strip.positionandswitchare now passed toggplot2::facet_wrap()orggplot2::facet_grid(). -
title,subtitle,tag, andcaptioncan be used throughoutopenair(titlereplacingmainandcaptionreplacingsub). All are passed throughquickText()ifauto.text = TRUE. -
lineend,linejoinandlinemitretweak the appearance of line plots; seeggplot2::geom_line()for more information.
-
-
Additional interactions between
...parameters and various plots:-
timePlot()now takesshapeto add markers to the line chart. This can be a vector to vary with pollutant/group. -
timeProp()now takeslinewidthandlinetypeto controlborderstyle. -
TheilSen()now takeslinewidth,linetype,shapeandalpha. -
smoothTrend()now takeslinetype,linewidth,shapeandsize. These can be vectors to vary based on pollutant. The linewidth of the data will always be half of that of the model.
-
-
Refinements to how
ref.xandref.ybehave throughout{openair}:-
ref.xandref.ycan now take a vector rather than a list, which will just use those values as the x/y intercept with default graphical parameters. -
ref.xandref.yhave been added totimeProp()andTheilSen(). -
ref.xandref.ycan now take{ggplot2}-style parameters (intercept,alpha,colour,linetype,linewidth). The old parameter names (h/v,cols,ltyandlwd) are automatically remapped so still work. -
The non-intercept arguments passed to
ref.xandref.y(e.g.,alpha) are now automatically recycled to the length ofintercept, similar to how...parameters are recycled. -
Added
refOpts()to help construct values forref.xandref.y, similar towindflowOpts().
-
-
Refinements to how
breaksare implemented in functions liketrendLevel():-
If
breaksdoesn't cover the full range of the data being binned, the maximum and minimumbreakswill be overwritten so that it does. -
If
breaksis of length1, the colour range will be split intobreakscategories, defaulting to using the same logic as runningcutData()on a numeric column. -
breakscan now take a named list, defined using the newbreakOpts()function. Most significantly, this allows for the method of binning to change for single-valuebreaks(quantiles, equal range bins, user-defined bin widths, approximate 'pretty' breaks and wind direction binning at time of writing). -
polarPlot(),polarAnnulus(),corPlot()andtrajLevel()have gainedbreaks. -
labelsis no longer a top-level argument and can be defined by passing a list tobreaks.labelsgiven to...will be converted with a warning.
-
-
All functions which take
breaksalso now contain thetransargument to perform scale transforms on continuous colour scales. This can takeFALSE(no scale transform),TRUE(an appropriate default transform - usually"log10"), or a{scales}transform object (or string shorthand). -
Refinements to colours in
{openair}:-
openColours()gainsdirection,alpha,begin,end,lightnessandsaturationfor better control over colour palettes. -
Added
colourOpts(). Anycolsargument in{openair}can now take thecolourOpts()function, which tells each plotting function how to use the newopenColours()arguments. -
Added
openSchemes()which returns a table of available colour palettes. -
New palettes:
-
Completed the set of "viridis" palettes with
"rocket"and"mako". -
Added additional palettes by Paul Tol;
"tol.highcontrast","tol.vibrant","tol.mediumcontrast","tol.pale"and"tol.dark". -
Added various palettes based on the work of Fabio Crameri - see
openColours()for more details.
-
-
Added
openColors()andcolorOpts()which are synonymous with their British English equivalentsopenColours()andcolourOpts().
-
-
New Kolmogorov-Zurbenko (KZ) Filter functions
kzFilter()andkzaFilter(). These functions significantly enhance the capability of{openair}by allowing different time components to be separated and analysed separately. ThekzFilter()function is considered a good default for a wide range of problems whereas thekzaFilter()function is the adaptive version that is well-suited to capturing abrupt changes, e.g., through an intervention. The range of uses of the filters will be covered in the{openair}book. -
TheilSen()andsmoothTrend()now use a more straightforward way to input missing data whendeseason = TRUEand missing monthly data are present based on monthly linear regression by month. The user is alerted to the imputation and the monthly plot shows the imputed data as a filled grey circle. -
smoothTrend()will now useloesswhen it has insufficient data to fit a GAM. -
cutData()gains thewd.resargument, which can take one of4,8, or16, defaulting to8.4cuts the data into North, East, South and West.16cuts the data into N, NNE, NE, ENE, etc. All plotting function'stypeargument now responds to this, showing only four panels whenwd.res = 4and a 5x5 grid of sixteen panels whenwd.res = 16. -
trajPlot()andtrajLevel()regain themap.resargument. This is passed tornaturalearth::ne_countries()so can take three different resolutions. -
polarPlot()will now annotate the identity of the radial axis as a caption, ifannotate = TRUE. -
wsand/orwdhave been added topercentileRose(),polarAnnulus(),polarDiff()andpolarFreq()in line withpolarPlot(). -
angle.scalehas been added topolarFreq()in line with all other polar coordinate plots. -
The default
key.positionofcorPlot()is now"right". -
timePlot()has gained thekey.titleargument.
Bug Fixes
-
timeAverage()now has a more robust approach to multi-period averaging time such as "3 day". Bin boundaries are at fixed periods of time, which should ensure consistency across data sets that start at different times. This also means there is less need to use the argumentstart.dateunless there is a need to extend the start date of the data for some reason e.g. to the beginning of a year. THis change may result in slight differences in returned output but should not affect periods such as "day", "hour" and "month". -
calendarPlot()will no longer duplicatewindflowarrows whentype != "default". -
calendarPlot()now supportstype = "wd". -
Fix intercept calculation in
TheilSen(). Updated the intercept formula frommedian(y) - slope * median(x)tomedian(y - slope * x). This resolves a visual bug where trend lines (especially annual aggregations with negative slopes) appeared horizontally displaced due to inaccurate intercept estimates on sparse data. This fix affects the visual display of the trend lines but not the calculated slopes or uncertainties. -
quickText()is once again tolerant of apostrophes. -
windflowOpts()will no longer overwrite the defaultrangeof functions likecalendarPlot()andtrendLevel()ifrangeis not supplied by the user. -
polarPlot()will no longer produce a square-shaped surface whenexclude.missing = FALSE. -
fontsizeis now correctly passed toscatterPlot(),polarAnnulus(),variationPlot(), andtimePlot(). -
Strings with line breaks (e.g., the result of
cutData(type="seasonyear"))) will no longer error when used for facet labels. -
name.polwill now correctly map onto the names ofpollutants intimeVariation(). -
windRose()now respectscolswhenws2andwd2are provided. -
xlimis now correctly passed to the coordinates oftrajLevel().
Natural Resources - Air Quality
- R
Published by jack-davison 14 days ago
openair - openair 3.0.0
Dependency Changes
-
openairnow depends on R v4.1 and, internally, uses the base R pipe (|>). -
openairnow importsggplot2andscalesand suggestssf,geomtextpath,legendryandrnaturalearthdata. -
openairno longer importslattice,latticeExtra,hexbinormapprojnor suggestsmapdataormaps.
Breaking Changes
-
All plotting functions are now written in
ggplot2.latticespecific options and annotations will no longer work, but many can now be achieved usingggplot2::theme()andggplot2::annotate(). -
trajPlot(),trajLevel()andtrajCluster()have had their three projection related arguments removed and replaced with a singlecrsargument, which defaults to lat/lng (4326). -
As the above three functions no longer call
scatterPlot(),scatterPlot()no longer has themapargument. -
drawOpenKey()has been removed due to beinglattice-specific. -
linearRelation()andcalcFno2()have been removed fromopenairdue to using outdated methodology and assumptions. -
summaryPlot()has been removed fromopenair. This function was very old and inconsistent with the rest ofopenair. It is planned to be replaced in the future with new summary functions. -
key.headerandkey.footerhave been replaced with a singlekey.title. This is due toggplot2not supporting a separate "header" and "footer" for guides. -
The
keyargument has been deprecated, as it now only exists to overwritekey.positionwhen it isFALSE. Please usekey.position = "none"going forward. -
Argument names have been standardised throughout
openair. For example, instances ofcolhave been replaced withcols. This may cause some existing code to break, but will ensure each function behaves more similarly going into the future.
New Features
-
timeVariation()has been almost completely rewritten. It is now a thin wrapper around the newvariationPlot(), which can take any arbitraryxvalue - passed to [cutData()] - to use for its x-axis. Furthermore, it has gained the following changes:-
Gained the
panelsargument. This allows for panels other than "hour.weekday", "hour", "month", and "weekday" to be represented in the plot assembly. -
When
keyisFALSE, no key is shown for any of the fourtimeVariation()plots. Previously, any value passed tokeywould cause all four plots to display a key. -
(!) BREAKING: The order of
xlabandylimnow matches the order ofpanels.month.lasthas also been deprecated; if used andTRUE, this will overridepanelswith a warning. The output namesoutput$datawill now vary based onpanels, and thetypecolumn will be named{type}_type(e.g., "hour_type"). -
(!) BREAKING: The names of the
plotanddataobjects returned bytimeVariation()are now named afterpanelsand have a more consistent structure.
-
-
timePlot()refinements:-
groupcan now take a character string, passed to [cutData()] via [timeAverage()]. This works similarly togroupintimeVariation()in that it colours traces within the panel, rather than splitting them into multiple panels. -
Gained the
x.relationargument, allowing for different x ranges on different panels.
-
-
smoothTrend()refinements:-
Gained the
x.relation,date.format, andkey.positionarguments, in line withtimePlot(). -
Gained the
progressargument, passed totimeAverage(). -
avg.timeis also no longer restricted to just three options (anytimeAverage()option is permitted), although too fine a time resolution may obscure the smooth trend for long running data.
-
-
calendarPlot()refinements:-
Gained the
typeargument. This can take onetypeand creates a 2D matrix using month & whatever the user has selected.type = "year"has special handling. -
Gained the
windflowargument, which deprecates passing"ws"or"wd"toannotate. -
Gained the
percentileargument, passed on totimeAverage(). -
Gained the
show.yearargument, defaulting toTRUE. WhenFALSEand only one year of data is given, the strip titles will only read, e.g., "January" instead of "January-2000". This can create cleaner plots, as well as being useful for certain edge cases (e.g., if the calendarPlot is showing day-of-year averages over multiple years). -
When
statistic == "min"andannotation %in% c("ws", "wd"), the ws/wd returned will correspond to the minimum daily pollutant, rather than the minimum daily ws/wd.
-
-
timeProp()refinements:-
proportionis now treated more liketypeinternally. For a user, this means it can now be passed"default"to avoid any conditioning and create a regular period average barchart. -
subcan now be defined via...; setsub = NAto remove the text annotation which appears by default at the bottom of atimeProp()plot. -
Gained the
keyargument to remove a legend. -
"season"is now a permittedavg.timeoption intimeProp(), better aligning it with the options intimeAverage(). -
...is now correctly passed tocutData()when usingtype/proportion.
-
-
corPlot()refinements:-
Added the
annotateargument which can change the correlation annotation to a p-value marker or stars, or remove it entirely. -
Added two new arguments
triangleanddiagonalfor controlling the plot appearance. -
Added arguments
keyandkey.titlefor adding and refining a plot legend.
-
-
trendLevel()refinements:-
(!) BREAKING:
typenow defaults to"default", in line with otheropenairfunctions. -
Added
windflowandmin.binarguments, in line with similar functions. -
Two
typevalues are now supported.
-
-
TaylorDiagram()refinements:- Added the
pos.corargument which controls whether the negative correlation quadrant is shown.
- Added the
-
New function
WhittakerSmooth()to do Whittaker-Eilers Smoothing. This is a fast and general smoothing technique, well-suited to a wide range of problems. The function can be used to flexibly smooth and interpolate missing data. Additionally, the function can flexibly define a baseline (and hence increment) for a time series. -
New function
windflowOpts()which can be passed to thewindflowargument of variousopenairfunctions to thoroughly customise the "windflow" arrows. -
All
openairplotting functions have gainedstrip.positionto control the placement of the facet strip. -
trajPlot()andtrajLevel()have gained thegrid.nxandgrid.nyarguments which can be used to control the number of ticks on the coordinate grid, or remove it altogether. -
cutData()now contains thedropargument. This allows for greater control over factor levels for appended columns. For example, consider a situation in whichdataonly contains dates in March and May andtype = "month"is used:-
drop = "empty"will ensure the resulting vector only has factor levels"March"and"May". -
drop = "none"will ensure the vector has all twelve months (January, February, March, etc.). -
drop = "outside"will retain 'inclusive' factor levels within the range of the data - in this case"March","April", and"May". -
drop = "default"is the existingcutData()behaviour - in the case oftype = "month", it is equivalent todrop = "empty".
-
-
cutData()also gains the"quarter"and"quarteryear"/"yearquarter"typeoptions. These split a year cleanly into quarters, as an alternative to"season"and"seasonyear"/"yearseason". While seasons better align with meteorology, quarters more cleanly fit into a single calendar year and may better align with other relevant periods (e.g., reporting schedules, ratification calendars, economic activity, etc.). -
is.axisnow has an effect onweekday,season,seasonyearandmonthyear. -
quickText()now convertsair_temp(a commonworldmetvariable) into"temperature". -
timeAverage()is much faster with the bulk of the calculations made using C++. -
runRegression()is now much faster with a new algorithm.
Bug Fixes
-
timePlot()now allows duplicate dates whentime.avgis used. The user will still receive a warning fromtimeAverage(), which is used internally, but the plot will still be created. -
The
windflowargument oftimePlot()now works when"ws"and/or"wd"are inpollutant. -
importUKAQ()now closes itsurl()connections and generally fails more gracefully whendata_type %in% c("annual", "monthly", "daqi"). This was already the case for other data types. -
timeAverage()will no longer leaveUuandVvcolumns behind whenstatistic = "data.cap". -
timeAverage()now correctly passes...tocutData(). -
timeAverage()now properly calculates wind speed and direction whenvector.ws = TRUE. -
selectByDate()now correctly handles theenddate if supplied when in a date format (i.e., dd/mm/yyyy) and selects all hours in that day if present.
Natural Resources - Air Quality
- R
Published by jack-davison 2 months ago
openair - openair 2.19.0
Deprecations
importEurope() relies on the same back-end database as the saqgetr package (https://github.com/skgrange/saqgetr), which was retired in February 2024. importEurope() will now warn users of this, and outright error if year >= 2025. Users are instead encouraged to use the EEA Air Quality Download Service https://eeadmz1-downloads-webapp.azurewebsites.net to obtain European data for the time being. An R package, https://github.com/openair-project/euroaq, has been developed to facilitate its use.
New Features
Data Access
-
The
sourceargument ofimportUKAQ()now defaults toNULL. This option allows the function to assign thesourceof eachsiteitself, with some caveats:-
Ambiguous codes (e.g.,
"AD1", which corresponds to a SAQN and locally managed site) will preferentially import from the national networks (AURN, then AQE/SAQN/WAQN/NIAQN) over locally-managed networks. To override this users should manually definesource. -
Incorrect codes not found in
importMeta()will error ifimportUKAQ()is left to assign thesource. -
When
data_typeis one of the aggregate types (e.g.,"annual") and asiteisn't defined, asourcemust be provided. -
It is likely slightly slower for the function to assign
sourceitself than for users to specify it themselves.
-
-
The specific metadata columns appended when
importUKAQ(meta = TRUE)can now be controlled using themeta_columnsargument. For example, settingmeta_columnstoc("zone", "agglomeration")will append the zone/agglomeration information instead of the default site type/latitude/longitude. -
DAQI information imported using
importUKAQ(data_type = "daqi")will be returned with the relevant DAQI band appended as an additional factor column; either "Low" (1-3), "Moderate" (4-6), "High" (7-9), or "Very High" (10). See https://uk-air.defra.gov.uk/air-pollution/daqi for more information. -
importImperial()has been added, supersedingimportKCL(). They are functionally identical, but reflect that londonair is now managed by Imperial College London. Function arguments have been renamed inimportImperial()to better matchimportUKAQ().
Utility Functions
-
cutData()gained numerous new features:-
Added the
namesargument to specify the name of the appended columns. For example,cutData(mydata, "wd", names = c("windDir"))will append a column named "windDir". -
Added the
suffixargument as an alternative tonames. If a new column would otherwise overwrite an existing column,suffixwill be appended. For example,cutData(mydata, c("nox", "o3"), suffix = "_cuts")would appendnox_cutsando3_cutscolumns. -
cutData()is now less destructive and better cleans up after itself. For example, whentype = "yearseason", it will no longer leave 'year' and 'season' columns behind, or overwrite existing 'year' and 'season' columns. -
cutData()will now give an informative error message if the user provides atypewhich is in neither an in-built option nor a column in their dataframe.
-
-
calcPercentile()gained the following arguments:-
Added the
typeargument, in line withtimeAverage(). -
Added the
prefixargument to control the naming of the returned columns.
-
-
binData()gained the following arguments:-
Added the
typeargument, passed tocutData(). -
Added the
Bandconf.intarguments, passed tobootMeanDF().
-
-
selectRunning()gained the following arguments:-
Added the
typeargument, passed tocutData(). -
Added the
nameargument, which changes the name of the new column appended by the function. -
Added the
modeargument, which allowsselectRunning()to filter the dataset rather than append a column.
-
-
rollingMean()has gained thetypeargument. This will likely be of most use for distinguishing between - and calculating separate statistics for - different monitoring stations within the same data frame. -
splitByDate()can now more consistently takeDate/POSIXctinputs as well as characters, and provides more flexibility over inputs with a newformatargument. -
aqStats()gained theprogressargument, in line withtimeAverage(). -
Many 'data utility' functions will now either warn or error if duplicate dates are detected, which is suggestive of a mix of either sites or averaging times within the same dataframe. The following functions have new behaviour:
-
selectRunning()androllingMean()will error (duplicate dates break the logic of 'rolling window' functions). -
aqStats()will also error, as it relies onrollingMean(). -
timeAverage()will warn the user but proceed with calculations, as averaging across different sites may be a legitimate action. -
Functions which rely on
timeAverage()will also warn but not error (notablycalcPercentile()but also many plotting functions withavg.timearguments).
-
Plotting Functions
-
Added new features for
openColours():-
Added new qualitative colour palettes: the "tol" family are colour-blind friendly palettes based on the work of Paul Tol, and "tableau" and "observable" provide access to the "Tableau10" and "Observable10" palettes to aid in consistency with plots made in those platforms.
-
When
nisn't defined for a qualitative palette (e.g., "Dark2"), the full qualitative palette will be returned. Previously this errored with the default of100. -
openColours()will now check whether the providedschemeis either a known scheme name or a vector of valid R colours, and provide an informative error if this is not the case.
-
-
polarDiff()has gained thetypeargument, and correctly responds tomain,key.footerandkey.headervia the...options. -
trendLevel()has gained newstatistictypes to matchtimeAverage(), including"mean","median","min","max","sd","sum","frequency"and"percentile". -
trendLevel()will now automatically generate appropriatelabelsifbreaksare provided. Thelabelsargument can still be used to provide custom labels per break. -
The
formula.labelargument ofpolarPlot()will now control whether concentration information is printed whenstatistic = "cpf". -
Added
calm.threshas an option towindRose(). This change allows users to set a non-zero wind speed threshold that is considered as calm. -
Added the
map.lwd,map.ltyandmap.borderarguments totrajPlot(),trajLevel()andtrajCluster()for greater control over the 'basemap' of each plot.
Bug fixes
-
Fixed repeated day number in
calendarPlot()whenstatistic = max. -
Fixed
annotate = FALSEinwindRose()where axes and labels were not shown -
Fixed an issue wherein
importUKAQ()would drop sites if importing fromlocalsites and another network. -
polarCluster()will no longer error with multiplepollutants and a singlen.clusters. -
importUKAQ()will correctly append site meta data whenmeta = TRUE,sourceis a length greater than 1, and a single site is repeated in more than one source (e.g.,importUKAQ(source = c("waqn", "aurn"), data_type = "daqi", year = 2024L))) -
calcPercentile()will now correctly pass its arguments (e.g.,date.start) totimeAverage(). -
timeAverage()will now more consistently returnNAvalues rather thanNaNorInfwhen all values areNA. This specifically affects the"mean"and"min"statistics. -
importUKAQ()will now correctly label a measurement as ratified when it is on the day ofratified_to. i.e., if a site is ratified to2020/01/01, the measurement at2020/01/01 23:00will now be labelled as ratified. -
Fixed
importImperial()URLs.
Natural Resources - Air Quality
- R
Published by jack-davison 9 months ago