ggplot2 Erweiterungen: Diagramme kombinieren, Kartenerstellung und interaktive Grafiken

Data Science 1 - Programmieren & Visualisieren

Saskia Otto

Universität Hamburg, IMF

Wintersemester 2023/2024

Lernziele

Am Ende dieser VL- und Übungseinheit werden Sie

  • ggplot2 Diagramme mit dem Paket gridExtra oder cowplot kombinieren können.
  • einfache Karten mit dem ggplot2 Paket erstellen können.
  • einen Überblick über weitere, aktuell beliebte R Pakete zu statischen Karten haben.
  • interaktive Karten mit dem Paket leaflet erstellen können.
  • statische Diagramme und Karten von ggplot2 zu interaktiven plotly Grafiken konvertieren können.

Diagramme kombinieren

Übersicht an R Paketen und Funktionen

  • Für ‘ggplot’ Objekte funktionieren die Standard R Funktionen par() und layout() nicht
  • Alternative Funktionen:
  • Alle diese Funktionen verwenden intern folgende Rasterspezifikationen (in ‘npc’ Einheiten):

Demo-Diagramme

Jede Herangehensweise wird mit 3 verschiedenen Diagramme vom bshydro15 Datensatz demonstriert:

Code
summer <- bshydro15 |>
  filter(pres <= 5,  month %in% c("May", "Jun", "Jul", "Aug"))

a <- summer |>
  select(sampling_id, month) |>
  distinct()  |>
  ggplot(aes(x = month)) +
    geom_bar(aes(fill = month)) +
    guides(fill = "none") +
    scale_fill_brewer(palette = "Set1") +
    guides(x = guide_axis(angle = 90)) +
  theme_classic() 

sss_sum <-summer |>
  # Bildung des Temperaturmittelwerts über die 5m
  group_by(ices_sd, station, lat, long, date_time, month, day) |>
  summarise(psal = mean(psal, na.rm = TRUE)) |>
  ungroup() |>
  drop_na()

b <- ggplot(sss_sum, aes(x = long, y = psal, col = ices_sd)) +
  geom_point() +
  scale_colour_brewer(palette = "Paired") +
  guides(colour = "none") +
  theme_classic() 

c <- sst_sum |>
  filter(month %in% c("May", "Aug")) |>
  ggplot(aes(long,lat))+
    geom_point(aes(colour = temp)) +
    scale_colour_gradient(low = "white", high = "red") +
    facet_grid(. ~ month) +
    theme_classic() 
a

Säulendiagramm - Anzahl der Messungen pro Sommermonat

b

Streudiagramm - Beziehung zwischen Längengrad & Salzgehalt (pro Teilgebiet)

c

Streudiagramm - Räumliche Verteilung der Oberflächentemperaturen (Mai-August)

Kombinieren mehrerer Diagramme | 1

→ mit grid.arrange()

library(gridExtra)
grid.arrange(
  a, b, c, 
  nrow = 2, ncol = 2)

  • erstellt ein sogenanntes ‘gtable’ Layout um mehrere grafische Objekte (=‘grobs’) auf einer Seite zu platzieren.
  • nimmt für das Gitter-Layout Anzahl der Zeilen und Spalten als Argumente.

Kombinieren mehrerer Diagramme | 2

→ eigene Aufteilung mit arrangeGrob() zusätzlich

library(gridExtra)
grid.arrange(
  arrangeGrob(a, b, ncol = 2), c, 
  nrow = 2, ncol = 1)

  • Um einzelne Zeilen oder Spalten noch weiter aufzuteilen, verwende die Helferfunktion arrangeGrob() beim Auflisten der Plotobjekte.
  • Diese Funktion nimmt auch die Anzahl der Zeilen oder Spalten als Input.
  • Im Beispiel rechts werden a und b als ein grafisches Objekt gehandelt und bekommen den gleichen Platz zugesprochen wie c allein (jeweils eine Zeile).

Kombinieren mehrerer Diagramme | 3

→ noch flexibler als die Funktion arrangeGrob() ist das Argument layout_matrix:

Erstellung der Layout-Matrix
my_mat <- matrix(c(1,2,2,3,3,3), 
  nrow = 2, byrow = TRUE)
my_mat
     [,1] [,2] [,3]
[1,]    1    2    2
[2,]    3    3    3

6 Rasterzellen sind in der Matrix spezifiziert:

  • Plot a bekommt 1 Zelle (Zeile 1, Spalte 1)
  • Plot b bekommt 2 Zellen (Zeile 1, Spalte 2-3)
  • Plot c bekommt 3 Zellen (Zeile 2, Spalte 1-3)
Übergabe der Layout-Matrix
grid.arrange(a, b, c, layout_matrix = my_mat)

Das ‘cowplot’ Paket

  • bietet ein publikationsfertiges Design für ‘ggplot2’
  • hat seine eigene, eingebaute Layoutvorlage: weißer Hintergrund ohne Raster (ähnlich zu theme_classic()), verschiedene Schriftgrößen
  • Die Funktion plot_grid() ist eine Kurzform mit limitierten Einstellungen:
library(cowplot)
plot_grid(a,b,c, labels = c("a)", "b)", "c)"), ncol = 3)

Diagramme mit ‘cowplot’

Für weitere Anpassungen (wie Anordnung und Größe) kombiniere folgende Funktionen

  1. ggdraw() → initialisiert eine leere Zeichenleinwand
  2. draw_plot() → platziert ein (Teil-)Diagramm irgendwo auf der Zeichenfläche
  3. draw_plot_label() → fügt die Beschriftungen zu den Diagrammen (voreingestellt ist die obere linke Ecke)

Diagramme mit ‘cowplot’ | Beispiel

(abc <- ggdraw() +
  draw_plot(a, x = 0, y = .5, width = .5, height = .5) +
  draw_plot(b, x = .5, y = .5, width = .5, height = .5) +
  draw_plot(c, x = 0, y = 0, width = 1, height = .5) +
  draw_plot_label(label = c("a)","b)","c)"), x = c(0,.5,0), y=c(1,1,.5), size = 15))

Verschachtelte Diagramme

  • Für das große Diagramm wird die Position auf 0 gesetzt und eine Breite und Höhe von 1 festgelegt (=default).
  • Beim kleineren Diagramm muss die Höhe und Breite entsprechend verringert (<1) und die gewünschte Position gewählt werden.
ggdraw() +
  draw_plot(b) + # Hauptdiagramm
  draw_plot(a, x = 0.4, y = 0.5, 
    width = .4, height = .4)

Speichern von ‘cowplots’

  • Zur Erinnerung: ggsave() (in ‘ggplot2’) kann verwendet werden um ‘ggplots’ als PDF- oder PNG-Datei zu speichern.
  • Eine bessere Lösung für ‘cowplots’ ist: save_plot() (in ‘cowplot’)
    • → das Raster-Layout kann spezifiziert werden, so dass das PDF optimal formatiert und skaliert ist.
save_plot("abc.pdf", abc,
  # spezifiziert das Seitenverhältnis (Breite/Höhe):
  base_asp = 1.3,
  # die Rasterspezifikation passt die Größe an:
  ncol = 2,  nrow = 2 )

Topografische vs. thematische Karten

Topografische Karten (Landkarten)

  • Dienen der Orientierung im Gelände und der Ausmessung von Standorten und anderen sichtbaren Details der Erdoberfläche.
  • Grundlage von Planungszwecke und Forschungsvorhaben.
  • Basis der meisten thematischen Karten.
  • Maßstab ist meist 1:25.000 bis 1:200.000.

Ausschnitt aus der topografischen USGS-Karte von Stowe, Vermont, USA (Maßstab 1:24.000).

Bildquelle: United States Geological Survey (CC0-Lizenz)

Thematische Karten (Kartogramme) | 1

  • Zur Darstellung bestimmter Themen und Merkmale (z.B. Bevölkerungsdichte, Artverbreitung).
  • Darstellung von Zusammenhängen thematischer Ebenen (z.B. zeitliche Änderungen von Merkmalen wie Bevölkerungsdichte).
  • Wesentliche Eigenschaften: Sachbezug, Zeitbezug, Raumbezug
  • Darstellungsmittel: Punkte, Linien und Flächen (in Kombination)

Modell von geografischen Phänomene sowie deren Visualisierungsmöglichkeiten

Flächenkartogramm, Choroplethenkarte

Durchschnittliches Vermögen pro Erwachsenem in US-Dollar im Jahr 2018, basierend auf dem Global Wealth Databook der Credit Suisse.
  • Gesammelte und typischerweise gruppierte Daten (z. B. nach Regionen) werden als Fläche durch Farben, Schattierungen oder Schraffierungen abhängig zum darzustellenden Wert abgebildet.
  • Je nach Art und Weise der Gruppierung (z. B. durch Mittelwertbildung, Median oder Summierung) kann das Ergebnis bzw. der Wert unterschiedlich sein.

Bildquelle: Wikipedia (CC-BY-SA 4.0 Lizenz)

Verhältnissymbolkarte

Punktkartogramm des gesamten Bruttoinlandsprodukts der Länder in Europa im Jahr 2018.
  • engl. ‘Proportional Symbol Map’
  • Punktsymbole unterschiedlicher Größe (Höhe, Länge, Fläche oder Volumen) werden verwendet, um quantitative statistische Werte darzustellen, die mit verschiedenen Bereichen oder Orten innerhalb der Karte verbunden sind.
  • Erfolgt die Anordnung der Punkte auf der Fläche schematisch innerhalb von (administrativen) Bezugsflächen spricht man auch von einem Punktkartogramm.

Bildquelle: Wikipedia (CC-BY-SA 4.0 Lizenz)

Punktstreukarte

  • engl. ‘Dot-Map’
  • Jeder vorhandenen Datensatz wird mit einem Symbol dargestellt.
  • Bei interpolierten Daten wird ein Mittelpunkt gebildet oder es wird an der Stelle dargestellt, wo der Wert am ehesten lokalisiert ist.
  • Ziel: Erfassung des tatsächlichen Verteilungsbilds.

Isoplethenkarte (Konturkarte)

  • Besteht aus einer Menge von interpolierten Isolinien, welche aus Stichprobenpunkten von bekannten Werten generiert werden.

Beispiel von einer Schätzung über die Zahl der einheimischen Arten pro 10.000 km2

Bildquelle: Greg J. Schmidt, Misako Nishino und John Kartes. Density Gradient Map Samples Produced From BONAP’s Floristic Synthesis

Kartenerstellung mit ggplot2

Kartendaten abgreifen mit ‘map_data’

# Weltkarte 1 (Atlantik im Zentrum)
world <- map_data(map = 'world')

# Deutschland aus Weltkarte beim Abgreifen filtern
germany <- map_data(map = 'world', region = 'Germany')
str(germany)
'data.frame':   568 obs. of  6 variables:
 $ long     : num  14.2 14.2 14 13.9 13.9 ...
 $ lat      : num  53.9 53.9 53.9 53.9 53.9 ...
 $ group    : num  1 1 1 1 1 1 1 1 1 1 ...
 $ order    : int  1 2 3 4 5 6 7 8 9 10 ...
 $ region   : chr  "Germany" "Germany" "Germany" "Germany" ...
 $ subregion: chr  "Usedom" "Usedom" "Usedom" "Usedom" ...

Weltkarte erstellen

geom_polygon()

wmap <- ggplot(world, aes(x = long, y = lat)) +
  geom_polygon(aes(group = group, fill = region)) +
  guides(fill = 'none')  +  scale_fill_grey()  +  theme_minimal()
wmap

Städte als Punkte in Karte einzeichnen

+ geom_point()

data(world.cities, package = 'maps')
capitals <- filter(world.cities, capital == 1)
wmap + 
  geom_point(data = capitals, colour = 'dodgerblue4')

Umrisskarte erstellen

+ borders()

# Grundplot (Streudiagramm mit Hauptstädten)
ggplot(capitals, aes(x = long, y = lat)) +
  borders() +
  geom_point() 

Koordinatensystem fixieren

+ coord_fixed(ratio = 1.3)

Nach Europa zoomen mit xlim,ylim
wmap + 
  coord_fixed(ratio = 1.3, 
    xlim = c(-10, 30), ylim = c(35,70)) 

Kartenprojektion | 1

+ coord_map()

Standardprojektion ist 'Mercator'
# ?coord_map

wmap + 
  coord_map(
    projection = 'mercator', # default
    xlim = c(-10, 30), ylim = c(35,70)
  )

Kartenprojektion | 2

Eine recht ansprechende Projektion ist die orthografische Azimutalprojektion welche den Nordpol im Zentrum hat:

projection = 'orthographic'
# Das Zentrum muss in die Mitte des 
# Zoomausschnitts verschoben werden:
# 'orientiation' = c(latitute, 
#             longitude, rotation)
wmap + 
  coord_map(
    projection = 'orthographic', 
    orientation = c(55, 10,0),
    xlim = c(-10, 30), ylim = c(35,70)
  )

Anfügen weiterer Daten

Beispiel für eine Choroplethenkarte

Code
wooded_area <- read.csv("area_of_wooded_land.csv", sep = ";")
# Einfügen der neuen Daten in 'world' data frame
world_wood <- dplyr::left_join(world, wooded_area, by = c("region" = "country"))

# Darstellung der Europakarte mit neuen Daten
wood_map <- ggplot(world_wood, aes(x = long, y = lat)) +
  geom_polygon(aes(group = group, fill = X2020)) + # fill = X2020 ist neu
  # Anpassung der kontinuerlichen Farbskala und Legende
  scale_fill_gradient2(low = "#edf8e9", mid = "#74c476", high = "#005a32",
    midpoint = 10000, guide = "legend", n.breaks = 10) +
  labs(x = "Längengrad", y = "Breitengrad",
    fill = "Bewaldete Fläche in \n2020 (in 1000ha)",
    caption = "Quelle: Eurostat Datenbank (https://ec.europa.eu/eurostat/web/main/home)") +
  coord_map(projection = 'orthographic', orientation = c(55, 10,0),
    xlim = c(-10, 30), ylim = c(35,70)) +
  theme_minimal() +
  theme(panel.border = element_rect(color = "black", fill = NA, linewidth = .5))
wood_map

Weitere Pakete zur Kartenerstellung

Das tmap Paket

tmaps ‘Grammar of graphics’

  • Grammar of Graphics angewandt auf die Visualisierung räumlicher Daten
  • Alternative zu ggplot2:
    • pro: Räumliche Objekte (aus den Paketen sp, raster und sf) können direkt verwendet werden
    • pro: Für Karten optimiertes Layout (z. B. Legende, Kartenattribute)
    • con: Ein weiteres Paket zum Lernen …

tmap | Beispiel - Punktkartogramm

Code
library(tmap)
# Beispieldaten laden 
data(World, metro, rivers, land)

tmap_mode("plot")
## tmap-Modus auf Plotten eingestellt
tm_shape(land) +
    tm_raster("elevation", palette = terrain.colors(10)) +
tm_shape(World) +
    tm_borders("white", lwd = .5) +
    tm_text("iso_a3", size = "AREA") +
tm_shape(metro) +
    tm_symbols(col = "red", size = "pop2020", scale = 1.5) +
tm_legend(show = FALSE)

Das mapsf Paket

mapsf | Beispiel - Punktkartogramm

Code
library(mapsf)
# Beispieldaten laden
mtq <- mf_get_mtq()
# Theme festlegen
mf_init(x = mtq, theme = "candy", expandBB = c(0, 0, 0, .15))
# Schatten erzeugen
mf_shadow(mtq, add = TRUE)
# Gemeinden plotten
mf_map(mtq, add = TRUE)
# Punktsymbole mit Choroplethenfärbung 
mf_map(
  x = mtq,
  var = c("POP", "MED"),
  type = "prop_choro",
  border = "grey50",
  lwd = 1,
  leg_pos = c("topright", "right"),
  leg_title = c("Population", "Median\nIncome\n(in euros)"),
  breaks = "equal",
  nbreaks = 4,
  pal = "Greens",
  leg_val_rnd = c(0, -2),
  leg_frame = c(TRUE, TRUE)
)
# Layout
mf_layout(
  title = "Population & Wealth in Martinique, 2015",
  credits = paste0(
    "Sources: Insee and IGN, 2018\n",
    "mapsf ",
    packageVersion("mapsf")
  ),
  frame = TRUE
)

Interaktive Grafiken

HTML-Widgets | 1

Mithilfe des Softwareentwicklungs-Framework htmlwidgets gibt es nun R Schnittstellen für JavaScript (JS) Visualisierungsbibliotheken wie z.B

HTML-Widgets | 2

  • HTML-Widgets funktionieren genau wie R-Plots, nur dass sie interaktive Webvisualisierungen erzeugen.
  • Eine oder zwei Zeilen R-Code genügen, um eine D3-Grafik oder eine Leaflet-Karte zu erzeugen.
  • HTML-Widgets können sowohl in der R Konsole als auch eingebettet in R Markdown-Berichte und Shiny-Webanwendungen verwendet werden.
  • Alle Pakete arbeiten mit dem Pipe-Operator!

HTML-Widgets | Beispiele 1

leaflet

plotly

HTML-Widgets | Beispiele 2

dygraphs

highcharter

leaflet | Standardweltkarte

leaflet() und addTiles()

library(leaflet)
m <- leaflet() |>   # erstellt das Grundgerüst (ähnlich wie ggplot())
  addTiles()        # hinzufügen einer Karte -> Standard: OpenStreetMap
m

leaflet | Zoomen

setView()

Schwache Vergrößerung: zoom = 5
m |> setView(zoom = 5,
  lng = 9.97874, lat = 53.56745) 
Starke Vergrößerung: zoom = 20
m |> setView(zoom = 20,
  lng = 9.97874, lat = 53.56745) 

leaflet | Weitere Karten

addProviderTiles()

CartoDB.Positron
leaflet() |> setView(zoom = 12,
  lng = 9.97874, lat = 53.54545) |> 
  addProviderTiles(providers$CartoDB.Positron)
Esri.WorldPhysical
leaflet() |> 
  setView(lng = 10, lat = 53, zoom = 4) |> 
  addProviderTiles(providers$Esri.WorldPhysical)

leaflet | Karten kombinieren

Esri.WorldImagery mit OpenRailwayMap
leaflet() |> 
  setView(lng = 11, lat = 55, zoom = 8) |> 
  addProviderTiles(providers$Esri.WorldImagery) |> 
  addProviderTiles(providers$OpenRailwayMap)

Kartenübersicht

names(providers)
  [1] "OpenStreetMap"                         
  [2] "OpenStreetMap.Mapnik"                  
  [3] "OpenStreetMap.DE"                      
  [4] "OpenStreetMap.CH"                      
  [5] "OpenStreetMap.France"                  
  [6] "OpenStreetMap.HOT"                     
  [7] "OpenStreetMap.BZH"                     
  [8] "OpenSeaMap"                            
  [9] "OPNVKarte"                             
 [10] "OpenTopoMap"                           
 [11] "OpenRailwayMap"                        
 [12] "OpenFireMap"                           
 [13] "SafeCast"                              
 [14] "Stadia"                                
 [15] "Stadia.AlidadeSmooth"                  
 [16] "Stadia.AlidadeSmoothDark"              
 [17] "Stadia.OSMBright"                      
 [18] "Stadia.Outdoors"                       
 [19] "Thunderforest"                         
 [20] "Thunderforest.OpenCycleMap"            
 [21] "Thunderforest.Transport"               
 [22] "Thunderforest.TransportDark"           
 [23] "Thunderforest.SpinalMap"               
 [24] "Thunderforest.Landscape"               
 [25] "Thunderforest.Outdoors"                
 [26] "Thunderforest.Pioneer"                 
 [27] "Thunderforest.MobileAtlas"             
 [28] "Thunderforest.Neighbourhood"           
 [29] "CyclOSM"                               
 [30] "Hydda"                                 
 [31] "Hydda.Full"                            
 [32] "Hydda.Base"                            
 [33] "Hydda.RoadsAndLabels"                  
 [34] "Jawg"                                  
 [35] "Jawg.Streets"                          
 [36] "Jawg.Terrain"                          
 [37] "Jawg.Sunny"                            
 [38] "Jawg.Dark"                             
 [39] "Jawg.Light"                            
 [40] "Jawg.Matrix"                           
 [41] "MapBox"                                
 [42] "MapTiler"                              
 [43] "MapTiler.Streets"                      
 [44] "MapTiler.Basic"                        
 [45] "MapTiler.Bright"                       
 [46] "MapTiler.Pastel"                       
 [47] "MapTiler.Positron"                     
 [48] "MapTiler.Hybrid"                       
 [49] "MapTiler.Toner"                        
 [50] "MapTiler.Topo"                         
 [51] "MapTiler.Voyager"                      
 [52] "Stamen"                                
 [53] "Stamen.Toner"                          
 [54] "Stamen.TonerBackground"                
 [55] "Stamen.TonerHybrid"                    
 [56] "Stamen.TonerLines"                     
 [57] "Stamen.TonerLabels"                    
 [58] "Stamen.TonerLite"                      
 [59] "Stamen.Watercolor"                     
 [60] "Stamen.Terrain"                        
 [61] "Stamen.TerrainBackground"              
 [62] "Stamen.TerrainLabels"                  
 [63] "Stamen.TopOSMRelief"                   
 [64] "Stamen.TopOSMFeatures"                 
 [65] "TomTom"                                
 [66] "TomTom.Basic"                          
 [67] "TomTom.Hybrid"                         
 [68] "TomTom.Labels"                         
 [69] "Esri"                                  
 [70] "Esri.WorldStreetMap"                   
 [71] "Esri.DeLorme"                          
 [72] "Esri.WorldTopoMap"                     
 [73] "Esri.WorldImagery"                     
 [74] "Esri.WorldTerrain"                     
 [75] "Esri.WorldShadedRelief"                
 [76] "Esri.WorldPhysical"                    
 [77] "Esri.OceanBasemap"                     
 [78] "Esri.NatGeoWorldMap"                   
 [79] "Esri.WorldGrayCanvas"                  
 [80] "OpenWeatherMap"                        
 [81] "OpenWeatherMap.Clouds"                 
 [82] "OpenWeatherMap.CloudsClassic"          
 [83] "OpenWeatherMap.Precipitation"          
 [84] "OpenWeatherMap.PrecipitationClassic"   
 [85] "OpenWeatherMap.Rain"                   
 [86] "OpenWeatherMap.RainClassic"            
 [87] "OpenWeatherMap.Pressure"               
 [88] "OpenWeatherMap.PressureContour"        
 [89] "OpenWeatherMap.Wind"                   
 [90] "OpenWeatherMap.Temperature"            
 [91] "OpenWeatherMap.Snow"                   
 [92] "HERE"                                  
 [93] "HERE.normalDay"                        
 [94] "HERE.normalDayCustom"                  
 [95] "HERE.normalDayGrey"                    
 [96] "HERE.normalDayMobile"                  
 [97] "HERE.normalDayGreyMobile"              
 [98] "HERE.normalDayTransit"                 
 [99] "HERE.normalDayTransitMobile"           
[100] "HERE.normalDayTraffic"                 
[101] "HERE.normalNight"                      
[102] "HERE.normalNightMobile"                
[103] "HERE.normalNightGrey"                  
[104] "HERE.normalNightGreyMobile"            
[105] "HERE.normalNightTransit"               
[106] "HERE.normalNightTransitMobile"         
[107] "HERE.reducedDay"                       
[108] "HERE.reducedNight"                     
[109] "HERE.basicMap"                         
[110] "HERE.mapLabels"                        
[111] "HERE.trafficFlow"                      
[112] "HERE.carnavDayGrey"                    
[113] "HERE.hybridDay"                        
[114] "HERE.hybridDayMobile"                  
[115] "HERE.hybridDayTransit"                 
[116] "HERE.hybridDayGrey"                    
[117] "HERE.hybridDayTraffic"                 
[118] "HERE.pedestrianDay"                    
[119] "HERE.pedestrianNight"                  
[120] "HERE.satelliteDay"                     
[121] "HERE.terrainDay"                       
[122] "HERE.terrainDayMobile"                 
[123] "HEREv3"                                
[124] "HEREv3.normalDay"                      
[125] "HEREv3.normalDayCustom"                
[126] "HEREv3.normalDayGrey"                  
[127] "HEREv3.normalDayMobile"                
[128] "HEREv3.normalDayGreyMobile"            
[129] "HEREv3.normalDayTransit"               
[130] "HEREv3.normalDayTransitMobile"         
[131] "HEREv3.normalNight"                    
[132] "HEREv3.normalNightMobile"              
[133] "HEREv3.normalNightGrey"                
[134] "HEREv3.normalNightGreyMobile"          
[135] "HEREv3.normalNightTransit"             
[136] "HEREv3.normalNightTransitMobile"       
[137] "HEREv3.reducedDay"                     
[138] "HEREv3.reducedNight"                   
[139] "HEREv3.basicMap"                       
[140] "HEREv3.mapLabels"                      
[141] "HEREv3.trafficFlow"                    
[142] "HEREv3.carnavDayGrey"                  
[143] "HEREv3.hybridDay"                      
[144] "HEREv3.hybridDayMobile"                
[145] "HEREv3.hybridDayTransit"               
[146] "HEREv3.hybridDayGrey"                  
[147] "HEREv3.pedestrianDay"                  
[148] "HEREv3.pedestrianNight"                
[149] "HEREv3.satelliteDay"                   
[150] "HEREv3.terrainDay"                     
[151] "HEREv3.terrainDayMobile"               
[152] "FreeMapSK"                             
[153] "MtbMap"                                
[154] "CartoDB"                               
[155] "CartoDB.Positron"                      
[156] "CartoDB.PositronNoLabels"              
[157] "CartoDB.PositronOnlyLabels"            
[158] "CartoDB.DarkMatter"                    
[159] "CartoDB.DarkMatterNoLabels"            
[160] "CartoDB.DarkMatterOnlyLabels"          
[161] "CartoDB.Voyager"                       
[162] "CartoDB.VoyagerNoLabels"               
[163] "CartoDB.VoyagerOnlyLabels"             
[164] "CartoDB.VoyagerLabelsUnder"            
[165] "HikeBike"                              
[166] "HikeBike.HikeBike"                     
[167] "HikeBike.HillShading"                  
[168] "BasemapAT"                             
[169] "BasemapAT.basemap"                     
[170] "BasemapAT.grau"                        
[171] "BasemapAT.overlay"                     
[172] "BasemapAT.terrain"                     
[173] "BasemapAT.surface"                     
[174] "BasemapAT.highdpi"                     
[175] "BasemapAT.orthofoto"                   
[176] "nlmaps"                                
[177] "nlmaps.standaard"                      
[178] "nlmaps.pastel"                         
[179] "nlmaps.grijs"                          
[180] "nlmaps.luchtfoto"                      
[181] "NASAGIBS"                              
[182] "NASAGIBS.ModisTerraTrueColorCR"        
[183] "NASAGIBS.ModisTerraBands367CR"         
[184] "NASAGIBS.ViirsEarthAtNight2012"        
[185] "NASAGIBS.ModisTerraLSTDay"             
[186] "NASAGIBS.ModisTerraSnowCover"          
[187] "NASAGIBS.ModisTerraAOD"                
[188] "NASAGIBS.ModisTerraChlorophyll"        
[189] "NLS"                                   
[190] "JusticeMap"                            
[191] "JusticeMap.income"                     
[192] "JusticeMap.americanIndian"             
[193] "JusticeMap.asian"                      
[194] "JusticeMap.black"                      
[195] "JusticeMap.hispanic"                   
[196] "JusticeMap.multi"                      
[197] "JusticeMap.nonWhite"                   
[198] "JusticeMap.white"                      
[199] "JusticeMap.plurality"                  
[200] "GeoportailFrance"                      
[201] "GeoportailFrance.plan"                 
[202] "GeoportailFrance.parcels"              
[203] "GeoportailFrance.orthos"               
[204] "OneMapSG"                              
[205] "OneMapSG.Default"                      
[206] "OneMapSG.Night"                        
[207] "OneMapSG.Original"                     
[208] "OneMapSG.Grey"                         
[209] "OneMapSG.LandLot"                      
[210] "USGS"                                  
[211] "USGS.USTopo"                           
[212] "USGS.USImagery"                        
[213] "USGS.USImageryTopo"                    
[214] "WaymarkedTrails"                       
[215] "WaymarkedTrails.hiking"                
[216] "WaymarkedTrails.cycling"               
[217] "WaymarkedTrails.mtb"                   
[218] "WaymarkedTrails.slopes"                
[219] "WaymarkedTrails.riding"                
[220] "WaymarkedTrails.skating"               
[221] "OpenAIP"                               
[222] "OpenSnowMap"                           
[223] "OpenSnowMap.pistes"                    
[224] "AzureMaps"                             
[225] "AzureMaps.MicrosoftImagery"            
[226] "AzureMaps.MicrosoftBaseDarkGrey"       
[227] "AzureMaps.MicrosoftBaseRoad"           
[228] "AzureMaps.MicrosoftBaseHybridRoad"     
[229] "AzureMaps.MicrosoftTerraMain"          
[230] "AzureMaps.MicrosoftWeatherInfraredMain"
[231] "AzureMaps.MicrosoftWeatherRadarMain"   

leaflet | Hinzufügen von Elementen 1

Rechtecke und Markierungspunkte

addMarkers(), addCircleMarkers() und addRectangles()

Code
lng <- 9.9789
lat <- 53.5675
m <- leaflet() |>
  addTiles() |>
  setView(lng = lng, lat = lat, zoom = 20) |>
  # Rechteck:
  addRectangles(
    lng1 = 9.978, lat1 = 53.5671,
    lng2 = 9.9795, lat2 = 53.5679,
    fillColor = "transparent") |> 
  # sog. Icon Markers:
  addMarkers(lng = lng, lat = lat,
    popup = "Eingang des Instituts für Zell- und Systembiologie der Tiere (IZS)", 
    label = "IZS") |>
  # Kreismarkierung:
  addCircleMarkers(lng = 9.97925, lat = 53.56735,
    popup = "Gr. Hörsaal der Zoologie", label = "Unser Standort",
    color = "red", radius = 35, stroke = TRUE, opacity = 0.5,
    weight = 3, fill = TRUE, fillColor = "red", fillOpacity = 0.2)
m

leaflet | Export als HTML- oder Bilddatei

Zum Speichern gibt es 2 Möglichkeiten:

  1. Die GUI von RStudio/Posit nutzen.

  1. Mit der saveWidget() Funktion im Paket htmlwidgets die Karte als HTML-Datei speichern und mit webshot() aus dem webshot2 Paket diese zu PNG umwandeln:
htmlwidgets::saveWidget(widget = m, file = "leaflet-Karte.html")
webshot2::webshot(url = "leaflet-Karte.html", file = "leaflet-Karte.png", 
  vwidth = 805, vheight = 480)

Von ggplot2 zu plotly

  • Mit ggplotply() können ggplot2 Grafiken ganz einfach in interaktive Diagramme umgewandeln werden!
gg_bill <- ggplot(data = palmerpenguins::penguins,  
  aes(x = bill_length_mm , y = body_mass_g, color = species)) + 
  geom_point()
ggplotly(gg_bill) # Umwandlung zu plotly Objekt

plotly | Menüleiste

Features

  • Download als PNG Datei
  • Zoomen
  • Legendenelemente auswählen
  • Hovering um Werte zu erhalten
  • ‘Home’ Schaltfläche
  • Schwenken
  • Automatische Skalierung
  • Reset
  • Vergleich von Datenpunkten beim Hovern


Anpassung

Mit der config() Funktion:

p_bill <- ggplotly(gg_bill)
# Menüleise komplett entfernen
config(p_bill, 
  displayModeBar = FALSE,
  displaylogo = FALSE,
  modeBarButtonsToRemove = c(
    'zoomIn2d', 'zoomOut2d'))

plotly | Anzeige beim ‘Mouseover’ 1

  • Standardmäßig werden alle Infos von Variablen im ‘Tooltip’ angezeigt, die den definierten Aesthetics zugewiesen wurden.
Anpassungen über das 'tooltip' Argument
ggplotly(gg_bill, tooltip = 'all') # Standardeinstellung
ggplotly(gg_bill, tooltip = 'species') # zeigt nur Infos der species Variable
ggplotly(gg_bill, tooltip = 'colour') # Alternativ: Aestheticnamen verwenden
ggplotly(gg_bill, tooltip = c('bill_length_mm', 'species')) # zeigt Infos von 2 Var.

plotly | Anzeige beim ‘Mouseover’ 2

  • Nicht definierte (sichtbare) Variablen, die im Tooltip aber erscheinen sollen, müssen den Aesthetics label, text oder group zugewiesen werden:
Anzeige nicht sichtbarer Variablen
gg_bill2 <- gg_bill +
  aes(group = island, label = body_mass_g , text = sex)     # text zeigt nicht den
ggplotly(gg_bill2, tooltip = c('group', 'label', 'text'))    # Variablennamen an!

plotly | Anzeige beim ‘Mouseover’ 3

  • Hilfreich beim Identifizieren von Datenpunkten ist die Vergabe einer Zeilen-ID, die dann dem Aesthetic ids übergeben wird:
Anzeige der ID im Tooltip
p <- penguins |> 
  mutate(id = 1:nrow(penguins)) |>  # falls es nicht schon eine ID gibt
  ggplot(aes(x = bill_length_mm , y = body_mass_g, color = species, ids = id)) +
  geom_point()
plotly::ggplotly(p)

plotly Grafiken kombinieren

  • Die Funktion subplot() im plotly Paket ist ähnlich wie die Funktion grid.arrange() Funktion aus dem gridExtra Paket
p_bill <- ggplotly(gg_bill)
# Erstelle zweites Diagramm
gg_weight <- drop_na(penguins, sex) |> 
  ggplot(aes(x = species, y = body_mass_g))+
  geom_boxplot(aes(fill = sex))
p_weight <- ggplotly(gg_weight)
# In einer Zeile anordnen und relative Breite ändern, Legende ausblenden
subplot(p_bill, gg_weight, nrows = 1, widths = c(0.7, 0.3)) |> 
  hide_legend()

Animationen mit plotly | Beispiel 1

  • Für Animationen muss das frame Aesthetic definiert werden!
anim_bill <- gg_bill + aes(frame = year)
ggplotly(anim_bill)

Animationen mit plotly | Beispiel 2

gg <- ggplot(gapminder::gapminder, aes(x = gdpPercap, y = lifeExp, 
      color = continent, size = pop, frame = year)) +
  geom_point() + scale_x_log10()
plotly::ggplotly(gg)

plotly | Export als HTML- oder Bilddatei

Zum Speichern gibt es bei plotly 3 Möglichkeiten:

  1. Die GUI von RStudio/Posit nutzen wie bei leaflet.
  2. Die Download-Schaltfläche von Plotlys Menüleiste verwenden.

  1. Mit den saveWidget() und webshot() Funktionen wie bei leaflet:
# Speichern im HTML-Format
htmlwidgets::saveWidget(widget = p_bill, file = "plotly-Diagramm.html")

# Umwandlung von HTML zu PNG, JPG,..
webshot2::webshot(url = "plotly-Diagramm.html", file = "plotly-Diagramm.png", 
  vwidth = 600, vheight = 480)

plotly | Mehr Möglichkeiten

  • Die Möglichkeiten mit ggplot2 und der Konvertierungsfunktion ggplotly() sind begrenzt.
  • Mehr Optionen gibt es bei der Verwendung von plotlys eigener Syntax:
Code
library(reshape2)
library(tidyverse)
library(tidymodels)
library(plotly)
library(kernlab)
library(pracma) # Für meshgrid()

mesh_size <- .02
margin <- 0
X <- iris |> select(Sepal.Width, Sepal.Length)
y <- iris |> select(Petal.Width)

model <- svm_rbf(cost = 1.0) |> 
  set_engine("kernlab") |> 
  set_mode("regression") |> 
  fit(Petal.Width ~ Sepal.Width + Sepal.Length, data = iris)

x_min <- min(X$Sepal.Width) - margin
x_max <- max(X$Sepal.Width) - margin
y_min <- min(X$Sepal.Length) - margin
y_max <- max(X$Sepal.Length) - margin
xrange <- seq(x_min, x_max, mesh_size)
yrange <- seq(y_min, y_max, mesh_size)
xy <- meshgrid(x = xrange, y = yrange)
xx <- xy$X
yy <- xy$Y
dim_val <- dim(xx)
xx1 <- matrix(xx, length(xx), 1)
yy1 <- matrix(yy, length(yy), 1)
final <- cbind(xx1, yy1)
pred <- model |>
  predict(final)

pred <- pred$.pred
pred <- matrix(pred, dim_val[1], dim_val[2])

fig <- plot_ly(iris, x = ~Sepal.Width, y = ~Sepal.Length, z = ~Petal.Width ) |> 
  add_markers(size = 5) |> 
  add_surface(x=xrange, y=yrange, z=pred, alpha = 0.65, type = 'mesh3d', name = 'pred_surface')
fig

Übungsaufgabe

VL-Skript und Fallstudien

  • Explorieren Sie das VL-begleitende R Skript (in Moodle) und experimentieren Sie mit den Einstellungen.
  • Versuchen Sie mindestens eine statische und eine dynamische Karte zu Ihrer Fallstudie zu erstellen (letzteres z.B. über Umwandlung der ggplot2 Karte zu einem plotly Objekt oder Erstellung einer leaflet Karte).

Swirl-Lektionen zur Vertiefung

Kurs DSB-04-Datenvisualisierung mit ggplot2

  • L13-Plots kombinieren
  • L14-Karten erstellen mit ggplot2
  • L15-Umwandlung zur interaktiven plotly_Grafik
  • L16-plotly Objekte besser verstehen

Wie fühlen Sie sich jetzt…?

Total konfus?


Bei weiteren Fragen: saskia.otto(at)uni-hamburg.de

Creative Commons License
Diese Arbeit is lizenziert unter einer Creative Commons Attribution-ShareAlike 4.0 International License mit Ausnahme der entliehenen und mit Quellenangabe versehenen Abbildungen.