Time Series and Trends
Examine how pollutant concentrations change with time.
ggopenair-trends.Rmd
library(ggopenair)
library(ggplot2)
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
Time Plots
Unlike in openair, ggopenair
does not have a dedicated time_plot()
function. This is because creating time series in ggplot2
is already so simple. The “legacy” timePlot()
looks like
this:
timePlot(marylebone, pollutant = "nox", avg.time = "month")
The equivalent in ggplot2 is shown below.
plt <-
marylebone %>%
time_average(avg_time = "month") %>%
ggplot(aes(x = date, y = nox)) +
geom_line() +
theme_bw() +
labs(x = NULL, y = quickText("nox"))
#> Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in
#> dplyr 1.1.0.
#> ℹ Please use `reframe()` instead.
#> ℹ When switching from `summarise()` to `reframe()`, remember that `reframe()`
#> always returns an ungrouped data frame and adjust accordingly.
#> ℹ The deprecated feature was likely used in the ggopenair package.
#> Please report the issue to the authors.
#> This warning is displayed once every 8 hours.
#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
#> generated.
While there are more lines of code to achieve the same thing, a
ggplot2 plot is much more customisable.
ggopenair even contains tools to help with common issues.
For example, we can add limit values using the
scale_y_limitval()
function.
plt +
scale_y_limitval(c(150, 350), "red", c("Getting\nHigher", "Too high!"), c(2, 1))
There is also no equivalent for smoothPlot()
as that is
already well served by geom_smooth()
.
plt + geom_smooth()
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
Temporal Variations
trend_variation()
works much the same way as
timeVariation()
, but returns a patchwork assemblage. These
can be treated similarly to a ggplot2 object, but the
ampersand (&
) symbol is used to style all plots
together.
trend_variation(marylebone, c("no2", "pm2.5"), normalise = TRUE) &
theme_bw() &
scale_fill_discrete(
aesthetics = c("colour", "fill"),
labels = scales::label_parse()(c("NO[2]", "PM[2.5]"))
)
The return
argument can be used to obtain specific
panels. This could be useful if not all panels are meaninful for your
data, or you want to customise individual panels.
hour_panel <- trend_variation(marylebone, "o3", return = "hour")
avg <- mean(hour_panel$data$Mean)
hour_panel +
theme_classic() +
scale_color_manual(values = "hotpink", aesthetics = c("colour", "fill")) +
scale_y_limitval(marker_values = avg, marker_labels = paste0("Mean (", round(avg, 2), ")")) +
theme(legend.position = "none")
Time Proportion Plots
trend_prop()
behaves almost identically to
timeProp()
, albeit with fewer arguments as more can be
controlled using labs()
, scales_*_*()
, and so
on.
marylebone %>%
filter(format(date, "%Y") == 2019) %>%
trend_prop(
pollutant = "pm10",
avg_time = "3 day",
proportion = "wd"
) +
theme_bw() +
scale_fill_brewer(palette = "Dark2")
#> Warning: 432 missing wind direction line(s) removed
proportion
behaves similarly to facet
(type
in the original openair
). If a column
isn’t present in the data set (or it is numeric), it will use
openair::cutdata()
to parse it and work out how it can be
used to cut the data. The recommendation, however, is to get your
categories in order before you use proportion
—
then you have full control over and understanding of the output. For
example, in the below plot, we use cut_wd()
to pre-cut the
wind directions into bins — in this case, fewer bins by setting
resolution
to “low”.
Trend Heat Maps
Much like with the time proportion plots, trend_level()
is very similar to trendLevel()
.
plt <-
trend_level(marylebone, "nox", "hour", "month", "year") +
scale_opencolours_c() +
theme_minimal() +
labs(fill = quickText("Mean NOx"), y = NULL)
plt
A minor exception is that, when possible, axes are automatically parsed as numeric/integer rather than always being factors. This avoids label overlap, and allows users to use continuous scales for further transformations and annotations. For example, here each day is split into four, 6-hour segments.
plt +
scale_x_continuous(breaks = seq(0, 24, 6)) +
geom_vline(xintercept = c(6, 12, 18))
Calendar Plots
Calendar plots once again behave similarly, but the annotations are dealt with using bespoke functions. These make it easier to customise or layer the annotations on top of one another.
marylebone |>
openair::selectByDate(year = 2019) |>
trend_calendar("nox") +
annotate_calendar_text("date") +
annotate_calendar_wd(colour = "black") +
scale_opencolours_c()
An extra feature of trend_calendar()
is that multiple
years can now be easily plotted. Instead of a normal calendar, a
year-month matrix is produced.
library(scales)
marylebone |>
trend_calendar("nox") +
scale_opencolours_c(limits = c(0, 600), oob = squish)
TheilSen
There is currently no version of theilSen in
ggopenair. This is open for discussion, but it will
either take the form of an openair
-like function (e.g.,
trend_theilsen()
) or a more
ggplot2-esque geom_theil()
. Until this
functionality has been developed, feel free to use
openair::theilSen()
, optionally re-plotting in
ggplot2 if desired.