Erstellen von Diagrammen für Ostluft Auswertungen und Berichte mit Bezug zu Luftschadstoffen und Meteorologie. Einige Funktionen sind aus dem package openair abgeleitet. Alle plot-Funktionen sind grundsätzlich auf das ggplot2 package bezogen.
Der Quellcode von rOstluft.plot ist auf github gehosted. Die einfachste Variante ist die Installation mit Hilfe des Packages devtools:
#install.packages("devtools")
devtools::install_github("Ostluft/rOstluft.plot")
library(rOstluft.plot)
library(rOstluft)
library(rOstluft.data)
library(ggplot2)
library(dplyr)
library(lubridate)
library(tibble)
library(purrr)
library(scales)
library(openair)
data <-
rOstluft.data::f("Zch_Stampfenbachstrasse_2010-2014.csv") %>%
rOstluft::read_airmo_csv() %>%
rOstluft::rolf_to_openair() %>%
openair::cutData(date, type = "daylight") %>%
tibble::as_tibble() %>%
dplyr::mutate(
wday = lubridate::wday(date, label = TRUE, week_start = 1),
year = lubridate::year(date)
)
bb <- bbox_lv95(2683141, 1249040, 500)
bg <- get_stadia_map(bb)
ggwindrose(data, ws, wd, ws_max = 4, bg = bg, ) +
theme(
panel.grid.major = element_line(linetype = 2, color = "black", size = 0.5)
)
# Für Facetten müssen die facet Variablen in groupings enthalten sein:
ggwindrose(data, ws, wd, ws_max = 4, groupings = grp(daylight)) +
facet_wrap(vars(daylight))
# y Achse kann wie gewohnt mit einer scale_y_continuous angepasst werden
# das untere Limit sollte auf 0 gesetzt werden
ggwindrose(data, ws, wd, ws_max = 4, groupings = grp(daylight)) +
facet_wrap(vars(daylight)) +
scale_y_continuous(
limits = c(0, NA),
expand = expand_scale(),
labels = scales::percent_format(1),
breaks = seq(0, 0.3, 0.05)
)
# Simpler Radarplot
ggradar(data, wd, NOx, fill = "gray30", alpha = 0.5, show.legend = FALSE)
# mehrere Statistik Funktionen
q05 <- function(x, ...) quantile(x, 0.05, ...)
q95 <- function(x, ...) quantile(x, 0.95, ...)
stat_reorder <- function(stat) {
factor(stat, levels = rev(c("perc05", "median", "mean", "perc95")))
}
ggradar(data, wd, NOx,
fun = list("perc05" = q05, "median", "mean", "perc95" = q95),
fun_reorder = stat_reorder, color = NA, alpha = 0.9) +
scale_y_continuous(limits = c(0,120)) +
scale_fill_viridis_d(begin = 0.2)
# Karte als Hintergrund
bb <- bbox_lv95(2683141, 1249040, 500)
bg <- get_stadia_map(bb)
ggradar(data, wd, NOx, bg = bg, lwd = 1,
color = "steelblue", fill = "steelblue", alpha = 0.5) +
theme(
panel.grid.major = element_line(linetype = 1, color = "white"),
axis.text.x = element_text(color = "gray10")
)
fs <- scale_fill_gradientn_squished(
limits = c(0,50), breaks = seq(0,50,10),
na.value = NA, colors = matlab::jet.colors(20)
)
ggpolarplot(data, wd = wd, ws = ws, z = NOx, ws_max = 4,
bg = bg, alpha = 0.6,
fill_scale = fs, smooth = TRUE, breaks = c(0,2,4)
) +
theme(
panel.grid.major = element_line(linetype = 2, color = "black", size = 0.5)
)
ggyearday(data, time = "date", z = "O3")
Kalender der max Stundenwerte des Tages von Ozon
statstable <- tibble::tribble(
~parameter, ~statistic, ~from, ~to,
"O3", "mean", "input", "h1",
"O3", "max", "h1", "d1"
)
data_d1 <-
rOstluft.data::f("Zch_Stampfenbachstrasse_2010-2014.csv") %>%
rOstluft::read_airmo_csv() %>%
dplyr::filter(starttime < lubridate::ymd(20130101)) %>%
rOstluft::calculate_statstable(statstable) %>%
purrr::pluck("d1") %>%
rOstluft::rolf_to_openair()
ggcalendar(data_d1, z = "O3_max_h1") +
scale_fill_viridis_c(direction = -1, option = "magma", na.value = NA) +
cal_month_border(size = 1) +
stat_filter(
aes(filter = O3_max_h1 > 120), size = 1,
color = "white", fill = "white", shape = 21,
position = position_nudge(y = 0.25)
) +
cal_label(aes(label = round(O3_max_h1,0)), fontface = "bold")
fn <- system.file("extdata", "2017_ZH-Kaserne-hysplit.rds", package = "rOstluft.data")
traj <- readRDS(fn)
traj <- dplyr::filter(traj,
dplyr::between(lubridate::as_date(date), lubridate::ymd("2017-03-08"), lubridate::ymd("2017-03-14"))
)
# simple
ggtraj(traj)
# Schadstoff statt Trajektorienhöhe
# Interessant für den Transport von Schadstoffen wie EC. In diesem Beispiel wird PM2.5
# verwendet weil keine EC Daten in den Beispieldaten enthalten sind.
data_2017 <-
rOstluft.data::f("Zch_Stampfenbachstrasse_min30_2017.csv") %>%
rOstluft::read_airmo_csv() %>%
rOstluft::rolf_to_openair()
data_traj <-
dplyr::select(data_2017, -site) %>%
dplyr::right_join(traj, by = "date")
ggtraj(data_traj, aes(color = PM2.5),
color_scale = ggplot2::scale_color_viridis_c(direction = -1))
Messdaten enthalten oft Extremwerte von ausserordentlichen Episoden oder Ereignissen. Als Beispiel Feuwerwerke oder Inversionen in den PM10 Daten:
ggyearday(data, time = date, z = PM10)
In einem ggplot2 Diagramm kann bei continuous scales mit Hilfe dem
Argument oob
eine Funktion übergeben werden, was mit Werten ausserhalb
des Limits geschieht. Mit Hilfe der Funktion scales::squish()
werden
diese Werte auf das Minima, bzw. Maxima der Limits gesetzt. In
rOstluft.plot sind die Hilfsfunktionen scale_fill_viridis_squished()
,
scale_color_viridis_squished()
, scale_fill_gradientn_squished()
und
scale_color_gradientn_squished()
enthalten:
fill_scale <- scale_fill_viridis_squished(
breaks=c(0, 20, 40, 60, 80),
limits = c(0, 80),
direction = -1,
na.value = NA,
option = "A"
)
ggyearday(data, time = date, z = PM10, fill_scale = fill_scale)
Teilweise ist es für Klassierungen praktisch alle Werte über einem
Maximum in einer zusätzlichen Klasse zusammen zu fassen. Die Funktion
cut_ws()
beinhaltet diese Funktionalität, hat jedoch gewisse
Einschränkungen (Negative Werte werden zu NA, Breite der Klasse fix):
pm10_right <- cut_ws(data$PM10, binwidth = 20, ws_max = 80)
table(pm10_right)
#> pm10_right
#> [0,20] (20,40] (40,60] (60,80] >80
#> 48146 27874 6162 1191 476
pm10_left <- cut_ws(data$PM10, 20, 80, right = FALSE)
# bei der Umwandlung der Ausgabe nach HTML wird "≥80" in "=80"
# umgewandelt. In Diagrammen und der R Konsole wird das Zeichen
# jedoch korrekt dargestellt. See https://github.com/r-lib/evaluate/issues/59
table(pm10_left)
#> pm10_left
#> [0,20) [20,40) [40,60) [60,80) ≥80
#> 48146 27874 6162 1191 476
Für mehr Flexibilät kann direkt base::cut()
verwendet werden und
breaks mit -Inf
und Inf
definiert werden.
breaks <- c(-Inf, 0, 19, 41, 66, 80, Inf)
pm10_cut <- cut(data$PM10, breaks = breaks, right = TRUE, include.lowest = TRUE)
table(pm10_cut)
#> pm10_cut
#> [-Inf,0] (0,19] (19,41] (41,66] (66,80] (80, Inf]
#> 1141 45516 31079 6164 614 476
Messdaten liegen nicht immer in vollständigen Zeitreihen vor. Für einige
Diagramme ist es jedoch erforderlich, dass für alle Zeitpunkte ein Wert
oder ein NA vorhanden ist. Für Daten im rolf Format können die rOstluft
Funktionen rOstluft::pad()
und rOstluft::pad_year()
verwenden
werden. rOstluft.plot enthält 2 generische padding Funktionen:
fn <- rOstluft.data::f("Zch_Stampfenbachstrasse_min30_2013_Jan.csv")
january <- rOstluft::read_airmo_csv(fn)
january_oa <- rOstluft::rolf_to_openair(january
)
tail(january_oa)
#> # A tibble: 6 × 16
#> date site CO Hr NO NO2 NOx O3 p PM10 RainDur SO2 StrGlo T wd
#> <dttm> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2013-01-31 21:00:00 Zch_S… 0.191 67.3 0.675 7.70 4.57 71.0 970. 7.21 0.583 0.782 0.0138 9.25 244.
#> 2 2013-01-31 21:30:00 Zch_S… 0.195 64.9 0.359 7.72 4.33 69.7 970. 4.89 1.52 0.851 0.0116 9.49 245.
#> 3 2013-01-31 22:00:00 Zch_S… 0.191 65.1 0.424 6.84 3.92 69.0 970. 6.71 1.45 0.842 0.00673 9.33 246.
#> 4 2013-01-31 22:30:00 Zch_S… 0.184 67.3 0.353 5.38 3.09 70.5 970. 5.19 0 0.797 0.0120 9.17 242.
#> 5 2013-01-31 23:00:00 Zch_S… 0.186 67.3 0.634 5.87 3.58 70.2 969. 5.79 0 0.851 0.0118 9.10 242.
#> 6 2013-01-31 23:30:00 Zch_S… 0.189 68.7 0.435 6.76 3.88 67.6 969. 7.92 0 0.749 0.0105 9.1 239.
#> # ℹ 1 more variable: ws <dbl>
# site mit "Zch_Stampfenbachstrasse" füllen
pad_to_year(january_oa, date, "30 min", fill = list(site = "Zch_Stampfenbachstrasse")) %>%
tail()
#> # A tibble: 6 × 16
#> date site CO Hr NO NO2 NOx O3 p PM10 RainDur SO2 StrGlo T wd
#> <dttm> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2013-12-31 21:00:00 Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA NA
#> 2 2013-12-31 21:30:00 Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA NA
#> 3 2013-12-31 22:00:00 Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA NA
#> 4 2013-12-31 22:30:00 Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA NA
#> 5 2013-12-31 23:00:00 Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA NA
#> 6 2013-12-31 23:30:00 Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA NA
#> # ℹ 1 more variable: ws <dbl>
# automatisch alle factor/character columns füllen
pad_to_year_fill(january_oa, date, "30 min") %>%
tail()
#> # A tibble: 6 × 16
#> date site CO Hr NO NO2 NOx O3 p PM10 RainDur SO2 StrGlo T wd
#> <dttm> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2013-12-31 21:00:00 Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA NA
#> 2 2013-12-31 21:30:00 Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA NA
#> 3 2013-12-31 22:00:00 Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA NA
#> 4 2013-12-31 22:30:00 Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA NA
#> 5 2013-12-31 23:00:00 Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA NA
#> 6 2013-12-31 23:30:00 Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA NA
#> # ℹ 1 more variable: ws <dbl>
pad_to_year_fill(january, starttime, "30 min") %>%
tail()
#> # A tibble: 6 × 6
#> starttime site parameter interval unit value
#> <dttm> <fct> <fct> <fct> <fct> <dbl>
#> 1 2013-12-31 21:00:00 Zch_Stampfenbachstrasse WVv min30 m/s NA
#> 2 2013-12-31 21:30:00 Zch_Stampfenbachstrasse WVv min30 m/s NA
#> 3 2013-12-31 22:00:00 Zch_Stampfenbachstrasse WVv min30 m/s NA
#> 4 2013-12-31 22:30:00 Zch_Stampfenbachstrasse WVv min30 m/s NA
#> 5 2013-12-31 23:00:00 Zch_Stampfenbachstrasse WVv min30 m/s NA
#> 6 2013-12-31 23:30:00 Zch_Stampfenbachstrasse WVv min30 m/s NA
# enthalten die Daten jedoch eine Klassifizierungs Spalte
# muss man die zu füllenden Spalten explixit angeben
january_oa <- openair::cutData(january_oa, "month") %>%
dplyr::select(date, month, dplyr::everything())
# Monats Spalte wird falscherweise mit Januar gefüllt
# Ausserdem würden für jeden Monat die Daten multipliziert
pad_to_year_fill(january_oa, date, "30 min") %>%
tail()
#> # A tibble: 6 × 17
#> date month site CO Hr NO NO2 NOx O3 p PM10 RainDur SO2 StrGlo T
#> <dttm> <ord> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2013-12-31 21:00:00 Januar Zch_S… NA NA NA NA NA NA NA NA NA NA NA NA
#> 2 2013-12-31 21:30:00 Januar Zch_S… NA NA NA NA NA NA NA NA NA NA NA NA
#> 3 2013-12-31 22:00:00 Januar Zch_S… NA NA NA NA NA NA NA NA NA NA NA NA
#> 4 2013-12-31 22:30:00 Januar Zch_S… NA NA NA NA NA NA NA NA NA NA NA NA
#> 5 2013-12-31 23:00:00 Januar Zch_S… NA NA NA NA NA NA NA NA NA NA NA NA
#> 6 2013-12-31 23:30:00 Januar Zch_S… NA NA NA NA NA NA NA NA NA NA NA NA
#> # ℹ 2 more variables: wd <dbl>, ws <dbl>
# mit explixiter Defintion der zu füllenden Spalten klappt es
pad_to_year_fill(january_oa, date, "30 min", site) %>%
tail()
#> # A tibble: 6 × 17
#> date month site CO Hr NO NO2 NOx O3 p PM10 RainDur SO2 StrGlo T
#> <dttm> <ord> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2013-12-31 21:00:00 <NA> Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA
#> 2 2013-12-31 21:30:00 <NA> Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA
#> 3 2013-12-31 22:00:00 <NA> Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA
#> 4 2013-12-31 22:30:00 <NA> Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA
#> 5 2013-12-31 23:00:00 <NA> Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA
#> 6 2013-12-31 23:30:00 <NA> Zch_St… NA NA NA NA NA NA NA NA NA NA NA NA
#> # ℹ 2 more variables: wd <dbl>, ws <dbl>
Karten Attribution: Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.