Dieses Dokument beschreibt die Vorprozessierung und explorative Analyse des Datensatzes, der Grundlage des auf srf.ch veröffentlichten Artikel Wo die Bandschmieden der Schweiz liegen ist.
SRF Data legt Wert darauf, dass die Datenvorprozessierung und -Analyse nachvollzogen und überprüft werden kann. SRF Data glaubt an das Prinzip offener Daten, aber auch offener und nachvollziehbarer Methoden. Zum anderen soll es Dritten ermöglicht werden, auf dieser Vorarbeit aufzubauen und damit weitere Auswertungen oder Applikationen zu generieren.
Als Basis für die folgenden Auswertungen dienen Daten der Musikplattform Mx3.ch. Die vorliegenden Daten wurden von der öffentlichen API der SRG SSR abgerufen.
Die Endprodukte des vorliegenden Scripts, neben der vorliegenden explorativen Analyse, sind die entsprechenden Tabellen und Plots, die im Ordner output
gespeichert werden (Datenbeschreibung siehe unten):
banddichte_kantone.csv
: Bands pro tausend Einwohner je Kanton (AR und AI zusammengefasst).kulturförderung_banddichte.jpg
: Scatterplot von Banddichte und Kantonale Kulturausgaben.city_broadcast_ratio.jpg
: Anteil an Bands im Radio der zehn grössten Schweizer Städte.genre-mix_Basel.jpg
: Genre Mix in Prozent für die Stadt Basel.genre-mix_Genf.jpg
: Genre Mix in Prozent für die Stadt Genf.genre-mix_Lugano.jpg
: Genre Mix in Prozent für die Stadt Lugano.genre-mix_Luzern.jpg
: Genre Mix in Prozent für die Stadt Luzern.genre-mix_Zürich.jpg
: Genre Mix in Prozent für die Stadt Zürich.Die Vorprozessierung und Analyse wurde im Statistikprogramm R vorgenommen. Das zugrunde liegende Script sowie die prozessierten Daten können unter diesem Link heruntergeladen werden. Durch Ausführen von main.Rmd
kann der hier beschriebene Prozess nachvollzogen und der für den Artikel verwendete Datensatz generiert werden. Dabei werden Daten aus dem Ordner input
eingelesen und Ergebnisse in den Ordner output
geschrieben.
SRF Data verwendet das rddj-template von Timo Grossenbacher als Grundlage für seine R-Scripts. Entstehen bei der Ausführung dieses Scripts Probleme, kann es helfen, die Anleitung von rddj-template zu studieren.
Debug-Informationen: This report was generated on 2018-12-07 10:52:59. R version: 3.4.4 on x86_64-pc-linux-gnu. For this report, CRAN packages as of 2017-09-01 were used.
Der Code für die vorliegende Datenprozessierung ist auf https://github.com/srfdata/2017-11-bands zur freien Verwendung verfügbar.
2017-11-bands von SRF Data ist lizenziert unter einer Creative Commons Namensnennung - Weitergabe unter gleichen Bedingungen 4.0 International Lizenz.
Code & Daten von SRF Data sind unter http://srfdata.github.io verfügbar.
Die veröffentlichten Informationen sind sorgfältig zusammengestellt, erheben aber keinen Anspruch auf Aktualität, Vollständigkeit oder Richtigkeit. Es wird keine Haftung übernommen für Schäden, die durch die Verwendung dieses Scripts oder der daraus gezogenen Informationen entstehen. Dies gilt ebenfalls für Inhalte Dritter, die über dieses Angebot zugänglich sind.
In der spezifischen API von Mx3.ch können die Band-Daten über die Band-ID durch den GET-Request «band-id-get» bezogen werden. Die Daten liegen im XML Format vor und müssen vor der Prozessierung mit R geparsed werden. Dieser Schritt kann ebenfalls mit R und den entsprechenden Packages (httr
, jsonlite
, purrr
) implementiert werden, ist aber hier nicht näher dokumentiert. Weiterführende Informationen zur API können der API-Dokumentation von Mx3.ch entnommen werden.
input/band_data_raw.csv
(aus XML geparste Band-Daten von Mx3.ch)Attribut | Typ | Beschreibung |
---|---|---|
id | int | Identifikationsnummer, einmalig je Band |
name | Factor | Bandname |
created_at | Factor | Datum und Uhrzeit der Profilerstellung |
city | Factor | Andgabe der Stadt (kein Pflichtfeld) |
profile_views_count | int | Anzahl Profilaufrufe bis zum Stichtag |
playlist_count | in | Anzahl Songs in auf Mx3.ch erstellten Playlists |
categories.id | int | Identifikationsnummer des Genres |
categories.name | Factor | Genre-Name gemäss Mx3.ch |
state.name | Factor | Kantonsname |
state.code | Factor | Kantonskürzel |
listening_count | int | Anzahl Plays über alle Songs auf einem Bandprofil |
listening_count_last_period | int | Anzahl Plays in spez. Zeitraum |
is_broadcasted | logi | TRUE: wurde mindestens einmal auf einem Mx3-Radiosender gespielt / FALSE: wurde nie gespielt |
singles_count | int | Anzahl Songs auf dem Bandprofil |
Die Daten des BFS zur öffentlichen Kulturfinanzierung wurden für die Jahre 2008 - 2014 gemittelt, da die Abweichungen innerhalb einzelner Jahre teilweise gross sind. Anschliessend wurden die gemittelten Kulturausgaben anhand der Einwohnerzahlen aus dem Jahr 2015 an den Einwohnerzahlen der Kantone normalisiert, um Pro-Kopf-Ausgaben zu erhalten.
Die Daten zu den Kantonalen Einwohnerzahlen des BFS wurden den Ausgewählten Indikatoren im regionalen Vergleich, 2017 entnommen und zeigen den Stand von 2015 auf. Anhand dieser Bevölkerungszahlen wurden die Anzahl Bands und die Kulturförderungsausgaben normalisiert.
## [1] "package package:rmarkdown detached"
# von https://mran.revolutionanalytics.com/web/packages/checkpoint/vignettes/using-checkpoint-with-knitr.html
# alle Packages, die nicht gebraucht werden, können hier entfernt werden (auskommentieren reicht nicht!)
# tidyverse: see https://blog.rstudio.org/2016/09/15/tidyverse-1-0-0/
cat("
library(tidyverse) # ggplot2, dplyr, tidyr, readr, purrr, tibble
library(magrittr) # pipes
library(stringr) # string manipulation
library(readxl) # excel
library(scales) # scales for ggplot2
library(jsonlite) # json
library(forcats) # easier factor handling,
library(lintr) # code linting, auf keinen Fall entfernen ;-)
library(rmarkdown) # for CLI knitting
library(ggrepel) # repelling text labels for ggplot
",
file = "manifest.R")
# if checkpoint is not yet installed, install it (for people using this
# system for the first time)
if (!require(checkpoint)) {
if (!require(devtools)) {
install.packages("devtools", repos = "http://cran.us.r-project.org")
require(devtools)
}
devtools::install_github("RevolutionAnalytics/checkpoint",
ref = "v0.3.2", # could be adapted later,
# as of now (beginning of July 2017
# this is the current release on CRAN)
repos = "http://cran.us.r-project.org")
require(checkpoint)
}
## Loading required package: checkpoint
##
## checkpoint: Part of the Reproducible R Toolkit from Microsoft
## https://mran.microsoft.com/documents/rro/reproducibility/
# nolint start
if (!dir.exists("~/.checkpoint")) {
dir.create("~/.checkpoint")
}
# nolint end
# install packages for the specified CRAN snapshot date
checkpoint(snapshotDate = package_date,
project = path_to_wd,
verbose = T,
scanForPackages = T,
use.knitr = F,
R.version = R_version)
## Scanning for packages used in this project
## rmarkdown files found and will not be parsed. Set use.knitr = TRUE
## - Discovered 12 packages
## All detected packages already installed
## checkpoint process complete
## ---
rm(package_date)
source("manifest.R")
## Loading tidyverse: ggplot2
## Loading tidyverse: tibble
## Loading tidyverse: tidyr
## Loading tidyverse: readr
## Loading tidyverse: purrr
## Loading tidyverse: dplyr
## Conflicts with tidy packages ----------------------------------------------
## filter(): dplyr, stats
## lag(): dplyr, stats
##
## Attaching package: 'magrittr'
## The following object is masked from 'package:purrr':
##
## set_names
## The following object is masked from 'package:tidyr':
##
## extract
##
## Attaching package: 'scales'
## The following object is masked from 'package:purrr':
##
## discard
## The following object is masked from 'package:readr':
##
## col_factor
##
## Attaching package: 'jsonlite'
## The following object is masked from 'package:purrr':
##
## flatten
unlink("manifest.R")
sessionInfo()
## R version 3.4.4 (2018-03-15)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.1 LTS
##
## Matrix products: default
## BLAS: /opt/R/R-3.4.4/lib64/R/lib/libRblas.so
## LAPACK: /opt/R/R-3.4.4/lib64/R/lib/libRlapack.so
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
## [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] ggrepel_0.6.5 rmarkdown_1.6 lintr_1.0.1 forcats_0.2.0
## [5] jsonlite_1.5 scales_0.5.0 readxl_1.0.0 stringr_1.2.0
## [9] magrittr_1.5 dplyr_0.7.2 purrr_0.2.3 readr_1.1.1
## [13] tidyr_0.7.0 tibble_1.3.4 ggplot2_2.2.1 tidyverse_1.1.1
## [17] checkpoint_0.4.0
##
## loaded via a namespace (and not attached):
## [1] Rcpp_0.12.12 cellranger_1.1.0 compiler_3.4.4 plyr_1.8.4
## [5] bindr_0.1 tools_3.4.4 digest_0.6.12 lubridate_1.6.0
## [9] evaluate_0.10.1 nlme_3.1-131.1 gtable_0.2.0 lattice_0.20-35
## [13] pkgconfig_2.0.1 rlang_0.1.2 rex_1.1.1 psych_1.7.5
## [17] yaml_2.1.14 parallel_3.4.4 haven_1.1.0 bindrcpp_0.2
## [21] xml2_1.1.1 httr_1.3.1 knitr_1.17 hms_0.3
## [25] rprojroot_1.2 grid_3.4.4 glue_1.1.1 R6_2.2.2
## [29] foreign_0.8-69 modelr_0.1.1 reshape2_1.4.2 backports_1.1.0
## [33] htmltools_0.3.6 rvest_0.3.2 assertthat_0.2.0 mnormt_1.5-5
## [37] colorspace_1.3-2 stringi_1.1.5 lazyeval_0.2.0 munsell_0.4.3
## [41] broom_0.4.2
# function for preserving percent sum 100 adapted from biostatmatt.com
round_preserve_sum <- function(df, digits = 0) {
x <- df$ratio
up <- 10 ^ digits
df <- x * up
y <- floor(x)
indices <- tail(order(x - y), round(sum(x)) - sum(y))
y[indices] <- y[indices] + 1
y / up
}
theme_srf <- function(base_size = 10, ...) {
theme_bw() +
theme(
title = element_text(size = 12, face = "bold"),
text = element_text(color = "#555555"),
legend.text = element_text(size = 8),
legend.title = element_text(size = 8),
legend.spacing = unit(0, "cm"),
axis.line = element_blank(),
legend.box = "vertical",
panel.border = element_blank(),
plot.background = element_rect(fill = "#f5f5f2"),
panel.background = element_rect(fill = "#f5f5f2"),
legend.background = element_rect(fill = "#f5f5f2"),
legend.key = element_blank(),
legend.key.width = unit(c(0.7), units = "cm"),
legend.key.height = unit(c(0.5), units = "cm"),
panel.grid.minor = element_blank(),
panel.spacing = unit(c(0.4), units = "mm"),
plot.margin = unit(c(0.9, 0.9, 0.9, 0.9), "cm"),
axis.title.y = element_text(size = 10, vjust = 2),
axis.title.x = element_text(size = 10, vjust = -1),
axis.text.y = element_text(size = 10),
axis.text.x = element_text(size = 10),
complete = TRUE,
...
)
}
# 9 ditinct colors
srf_colors <- c("#c91024", "#f28b02", "#19a067", "#1a7ac5",
"#bc399f", "#9d44c1", "#199a9f", "#579d39",
"#949f19")
# read API data (cleaned) of mx3.ch
bands_raw <- read.csv("input/band_data_raw.csv")
# read bfs data (total population per canton)
einw_kant <- read_xls("input/Einwohner_Kanton_2017.xls", skip = 3)
# read bfs data (cultural budget per canton)
df <- data.frame()
# read all sheets (2008 - 2014)
for (i in 1:7){
df <- rbind(df, read_xls("input/KulturausgabenCH_Kte_Gde_2008-2014.xls",
range = "A6:C32", sheet = i))
}
kultur_budget <- df
rm(i, df)
U.a. umbenennen von Variablen, Entfernung von Duplikaten, Beibehaltung nur von aktiven Bands (mindestens ein Song hochgeladen), Entfernung von Bands, die im Registrationsprozess den Kanton AR angegeben, aber unpassende Wohnorte angegeben haben (Kanton AR ist die erste Antwortmöglichkeit im Registrationsprozess), möglichst passende Zusammenfassung von Genres mit anteilsmässig wenig Bands.
# duplicate bands_raw df
bands <- bands_raw
# add date & time variable
bands$created_at_date <-
as.Date(substring(bands$created_at, 1, 10))
bands$created_at_time <-
as.POSIXct(strptime(substring(bands$created_at, 12, 19), "%H:%M:%S"))
# add profile age in days
today <- as.Date(Sys.time())
bands$profile_age <- as.integer(today - bands$created_at_date)
# rename variables
bands %<>%
rename(created_at_date = created_at_date,
created_at_time = created_at_time,
genre_id = categories.id,
genre_name = categories.name,
state_name = state.name,
state_code = state.code,
profile_views = profile_views_count) %>%
arrange(id)
# order columns
bands %<>%
select(id, name, state_name, state_code, city, genre_id,
genre_name, profile_views, listening_count,
listening_count_last_period, playlists_count,
singles_count, is_broadcasted, created_at,
created_at_date, created_at_time, profile_age)
# remove is duplicates (produced when reading the API in overlapping junks)
bands %<>% distinct(id, .keep_all = T)
# only keep bands who uploaded a song (17423 remaining, for better data quality)
bands %<>%
filter(singles_count > 0)
# filter out any obvious external cities for canton (& keep NAs) (17353 remaining)
# remove exterior bands from canton AR (dataqquality-reason: first choice in registration procedure)
bands <- bands[-which ( (bands$state_code == "AR") & bands$city %in% grep("germany|abidjan|monaco|almere|auriol|avignon|annecy|hersfeld|bellevaux|beziers|bordeaux|boulogne|casablanca|brooklyn|cuenca|dordogne|dresden|düren|epinal|evry|grenoble|italia|argentina|kingston|pleubian|london|lüdenscheid|lyon|marseille|carrara|melun|metz|mons|montpellier|mulhouse|münchen|nancy|nantes|moscow|oakland|ornans|paris|zagreb|piacenza|brasil|sacramento|egreve|vallons|soresina|saint-pargoire|laprairie|pau|toscana|tours|morbegno|ales|trashington|crest|niemandsland|romanshorn|gallen|luzern|g-town",
bands$city, ignore.case = T, value = T) & !is.na(bands$city)), ]
# filter for bands that have been broadcasted (2690 remain)
bands_broadcasted <- bands %>%
filter(is_broadcasted == T)
# combine related genres for better overview
levels(bands$genre_name)[levels(bands$genre_name) %in%
c("Techno dj dance", "Electro trip hop - ambient")] <- "Techno, Electro"
levels(bands$genre_name)[levels(bands$genre_name) %in%
c("Jazz - musiques improvisées", "Funk R&B Soul")] <- "Jazz, Funk, Soul"
levels(bands$genre_name)[levels(bands$genre_name) %in%
c("Easy listening - Film score - Instrumental", "Reggae ragga ska dub",
"World latin traditionnel")] <- "World, Reggae, Film, Easy Listening"
# rename remaining genres
levels(bands$genre_name)[4] <- "Folk, Country"
levels(bands$genre_name)[6] <- "Hip-Hop"
levels(bands$genre_name)[7] <- "Metal, Punk"
# remove unused variable & df
rm(today)
Falls eine Band eine Stadt als Wohnort angegeben hat, wird hier überprüft, ob sie sich im richtigen Kanton befindet und der Name der Stadt vereinheitlicht.
# create vector with 1) canton & 2) city (list of cultural cities in CH (members of skk))
canton_city <- c("AG", "Aarau", "aarau",
"AG", "Baden", "baden",
"BS", "Basel", "basel|bâle|basilea",
"BE", "Bern", "bern",
"BE", "Biel", "biel|bienne",
"BE", "Burgdorf", "burgdorf",
"GR", "Chur", "chur|coira|cuira",
"JU", "Delémont", "delémont",
"SH", "Frauenfeld", "frauenfeld",
"FR", "Fribourg", "freiburg|fribourg",
"GE", "Genf", "genf|genève|geneve",
"JU", "La Chaux-de-Fonds", "chaux-de-fonds",
"VD", "Lausanne", "lausanne|lausane",
"TI", "Lugano", "lugano",
"LU", "Luzern", "luzern|lucern",
"NE", "Neuchâtel", "neuenburg|neuchatel|neuchâtel",
"VD", "Nyon", "nyon",
"VD", "Renens", "renens",
"VS", "Sion", "sion|sitten",
"SG", "St. Gallen", "gall",
"BE", "Thun", "thun",
"ZH", "Uster", "uster",
"VD", "Vevey", "vevey",
"ZH", "Winterthur", "winterthur",
"VD", "Yverdon", "yverdon",
"ZG", "Zug", "zug|zoug",
"ZH", "Zürich", "zürich|zurich|zurigo|turitg")
# create empty df
bands_with_city <- data.frame()
# loop through vector for usage in filter & add city name
for (i in seq(1, 26 * 3 + 3, by = 3)){
temp_city <- bands %>%
# only include band, if city matches with canton
filter(state_code == canton_city[i] & city %in%
grep(canton_city[i + 2], bands$city,
ignore.case = T, value = T)) %>%
mutate(band_city = canton_city[i + 1])
# bind rows to data frame
bands_with_city %<>% rbind(temp_city)
}
# remove unused variables
rm(canton_city, temp_city, i)
Für alle Bands, die einer oben erwähnten Stadt zugewiesen werden können, wird nun berechnet, wie viele Bands in einer Stadt einem bestimmten Genre angehören.
# create df with genres per city
city_genres <- bands_with_city %>%
group_by(band_city, genre_name) %>%
summarise(bands_in_genre = n()) %>%
mutate(sum_city = sum(bands_in_genre)) %>%
mutate(ratio = round(bands_in_genre / sum_city * 100, 2)) %>%
ungroup()
# generate vector with unique cities
unique_cities <- unique(city_genres$band_city)
# initialize variable/vector
temp_v <- as.integer()
# loop through cities & apply function round_preserve_sum()
for (i in 1:length(unique_cities)){
temp <-
round_preserve_sum(city_genres %>% filter(band_city == unique_cities[i]))
temp_v <- append(temp_v, temp)
}
# add to df
city_genres %<>% mutate(ratio_round = temp_v)
# test should match up to 100 for each city
city_genres %>%
group_by(band_city) %>%
summarise(sum = sum(ratio_round))
## # A tibble: 25 x 2
## band_city sum
## <chr> <dbl>
## 1 Aarau 100
## 2 Baden 100
## 3 Basel 100
## 4 Bern 100
## 5 Biel 100
## 6 Burgdorf 100
## 7 Chur 100
## 8 Delémont 100
## 9 Fribourg 100
## 10 Genf 100
## # ... with 15 more rows
# remove unused variables
rm(unique_cities, temp_v, temp, unique_cities, i, x)
Bereinigung des Excel mit den Bevölkerungsdaten.
# clean up df
einw_kant <- einw_kant[-c(1, 2, 3), -c(1, 2, 3)]
einw_kant <- einw_kant[1, ]
# transform row/col, rename vars, add total number of inhabitants
einw_kant <- gather(einw_kant)
einw_kant$value <- as.numeric(einw_kant$value)
einw_kant$key <- as.factor(einw_kant$key)
einw_kant %<>%
mutate(state_code = key) %>%
mutate(Einw = value * 1000) %>%
select(state_code, Einw)
Audaddieren aller Bands pro Kanton und Normalisierung mit Bevölkerungsdaten. Da die Datenqualität im Kanton AR potenziell schlecht ist (siehe oben), werden AR und AI vorher zusammengefasst.
# make df with genre ratios of bands against population per canton
bands_genre <- bands %>%
group_by(state_code, genre_name) %>%
summarise(total_bands = n()) %>%
mutate(sum_cant = sum(total_bands)) %>%
mutate(ratio = round(total_bands / sum_cant * 100, 2))
# total number bands per canton
density_bands <- bands_genre %>%
group_by(state_code) %>%
summarise(total = sum(total_bands))
# join wit BFS cantonal population data
density_bands <- left_join(density_bands, einw_kant, by = "state_code")
# Add AR & AI merge AI/AR (Appenzell)
density_bands[2, ] <- density_bands[2, ] + density_bands[3, ]
density_bands <- density_bands[-3, ]
density_bands$state_code <- as.character(density_bands$state_code)
density_bands$state_code[2] <- "AI/AR"
density_bands$state_code <- as.factor(density_bands$state_code)
# relative ratio per canton
density_bands %<>% select(state_code, total, Einw) %>%
mutate(percent_bands = round(total * 100 / Einw, 3)) %>%
arrange(percent_bands) %>%
mutate(bands_per_thousand = percent_bands * 10) %>%
mutate(category = cut(bands_per_thousand,
breaks = c(0.5, 1.0, 1.5, 2.0,
2.5, 3.0, 3.5, 4.0),
labels = c("0.5 - 1 %", "1 - 1.5 %",
"1.5 - 2 %", "2 - 2.5 %",
"2.5 - 3 %", "3 - 3.5 %",
"3.5 - 4 %")))
# save band density per canton to csv
density_bands %>%
write.csv("output/banddichte_kantone.csv", row.names = F)
Der Kulturausgaben-Datensatz enthält beim Kanton BS noch Fussnoten, diese werden im ersten Schritt entfernt.
Die Kulturausgaben werden für die Jahre 2008 - 2014 gemittelt, da die Abweichungen innerhalb einzelner Jahre teilweise gross sind. Anschliessend werden die gemittelten Kulturausgaben anhand der Einwohnerzahlen aus dem Jahr 2015 an den Einwohnerzahlen der Kantone normalisiert, um Pro-Kopf-Ausgaben zu erhalten. Auch hier werden die beiden Appenzeller Halbkantone wiederum zusammengefasst.
# equalize canton name in df
kultur_budget[12, 1] <- "Basel-Stadt"
kultur_budget[38, 1] <- "Basel-Stadt"
kultur_budget[64, 1] <- "Basel-Stadt"
kultur_budget[90, 1] <- "Basel-Stadt"
kultur_budget[116, 1] <- "Basel-Stadt"
kultur_budget[142, 1] <- "Basel-Stadt"
kultur_budget[168, 1] <- "Basel-Stadt"
# clean up df & take mean cultural expenses per canton over the last seven years
kultur_budget %<>%
select(-X__3) %>%
rename(Kanton = X__1,
Ausgaben_tsd = X__2) %>%
group_by(Kanton) %>%
summarise(Ausgaben_tsd = sum(Ausgaben_tsd)) %>%
mutate(Ausgaben_tsd = Ausgaben_tsd / 7) %>%
mutate(Kantone_code = c("AG", "AR", "AI", "BL", "BS", "BE", "FR", "GE", "GL",
"GR", "JU", "LU", "NE", "NW", "OW", "SH", "SZ", "SO",
"SG", "TI", "TG", "UR", "VD", "VS", "ZG", "ZH"))
# join budget & population data
kultur_budget <-
left_join(kultur_budget, einw_kant,
by = c("Kantone_code" = "state_code"))
# add temp df for adding canton AI & AR
appenzell <- kultur_budget %>%
filter(Kantone_code %in% c("AI", "AR"))
# sum values of canton appenzell & add strings
appenzell <- colSums(appenzell[, c(2, 4)])
appenzell <- c(Kanton = "Appenzell", appenzell[1],
Kantone_code = "AI/AR", appenzell[2])
# bind to initial df, remove unique canton values & change data type
kultur_budget <- rbind(kultur_budget, appenzell)
kultur_budget <- kultur_budget[-c(2:3), ]
kultur_budget$Ausgaben_tsd <- as.numeric(kultur_budget$Ausgaben_tsd)
kultur_budget$Einw <- as.numeric(kultur_budget$Einw)
# calculate cultural budget per person
kultur_budget %<>% mutate(pro_kopf = Ausgaben_tsd * 1000 / Einw)
# join with df density_bands
kultur_budget <- left_join(kultur_budget, density_bands,
by = c("Kantone_code" = "state_code"))
# tidy df
kultur_budget %<>%
select(Kanton, Ausgaben_tsd, Kantone_code,
Einw.x, pro_kopf, total, bands_per_thousand) %>%
mutate(Einw = Einw.x)
# remove unused df
rm(appenzell)
# plot total number of bands per canton
ggplot(density_bands, aes(x = reorder(state_code, -total),
y = total)) +
geom_bar(stat = "identity", fill = "black") +
scale_y_continuous(breaks = c(seq(0, 5000, by = 500))) +
ggtitle("Anzahl Bands pro Kanton") +
ylab("Anzahl Bands") +
xlab("Kantone") +
theme_srf()
# plot band density per canton
ggplot(density_bands, aes(x = reorder(state_code, -bands_per_thousand),
y = bands_per_thousand)) +
geom_bar(stat = "identity", fill = "black") +
scale_y_continuous(breaks = c(seq(0, 4, by = 0.5))) +
ggtitle("Kantonale Banddichte der Schweiz (Bands pro 1000 Einwohner)") +
ylab("Bands auf 1000 Einwohner") +
xlab("Kantone") +
theme_srf()
# plot budget per canton vs band density
ggplot(kultur_budget,
aes(y = bands_per_thousand,
x = pro_kopf, label = Kantone_code)) +
geom_smooth(method = lm, formula = y ~ splines::bs(x, 2),
size = 0.3, color = "#555555", se = F) +
geom_point() +
geom_text_repel(size = 4) +
scale_y_continuous(limits = c(0.5, 4), breaks = seq(0, 5, by = 0.5)) +
scale_x_continuous(limits = c(50, 950), breaks = seq(0, 1000, by = 100)) +
labs(title = "Kulturförderung pro Kopf und Band-Dichte",
x = "Kulturausgaben pro Kopf (in CHF, Durchschnitt von 2008 - 2014)",
y = "Bands pro 1000 Einwohner (Stand Einwohner: 2015)") +
theme_srf() +
theme(axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 12),
axis.title.y = element_text(size = 12),
axis.title.x = element_text(size = 12),
title = element_text(size = 16))
ggsave("output/kulturförderung_banddichte.jpg", device = "jpg",
units = "cm", width = 623 / 22, height = 468 / 22, bg = "#f5f5f2")
# create city vector
cities <- c("Basel", "Zürich", "Genf", "Lugano", "Luzern")
# add linebreaks to specific levels of genre_name
levels(city_genres$genre_name)[c(2, 3, 7)] <-
gsub(" ", "\n", levels(city_genres$genre_name)[c(2, 3, 7)])
# loop through cities, create & save genre-city plots
for (i in 1:5){
t_city <- city_genres %>% filter(!genre_name %in% c("")) %>%
filter(band_city == cities[i])
# create genre-city plot
ggplot(t_city, aes(x = genre_name, y = ratio_round, fill = genre_name)) +
geom_bar(position = "dodge", stat = "identity") +
geom_text(aes(x = genre_name,
y = ratio_round + ifelse(ratio_round > 10, -2.5, 2),
label = paste0(ratio_round, "%")),
color = ifelse(t_city$ratio_round > 10, "#f5f5f2", "#555555"),
size = 3.5) +
xlab("") +
labs(genre_name = "Genres (mx3.ch)") +
ggtitle(paste0("Der Genre-Mix von ", cities[i])) +
scale_fill_manual(values = srf_colors, guide = F) +
coord_polar() +
theme_srf() +
theme(axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.text.x = element_text(size = 14),
plot.title = element_text(size = 20, hjust = 0.5),
plot.background = element_rect(color = "#f5f5f2")) +
scale_y_continuous(limits = c(0, 40), breaks = c(seq(0, 40, by = 10)))
# save plots
ggsave(paste0( "output/genre-mix_", cities[i], ".jpg"),
device = "jpg", units = "cm",
width = 623 / 27, height = 468 / 27, bg = "#f5f5f2")
}
Nachfolgend wird für die zehn grössten Schweizer Städte der Anteil der Bands berechnet, der mindestens einmal auf einem Mx3-Radiosender gespielt wurde. Dafür werden wiederum nur die Bands verwendet, die eindeutig einer Stadt zugeordnet werden können.
# broadcast ratio per city: prepare df
city_broadcast_ratio_1 <-
as.data.frame(table(bands_with_city$is_broadcasted,
bands_with_city$band_city))
city_broadcast_ratio_2 <-
as.data.frame(table(bands_with_city$is_broadcasted,
bands_with_city$band_city))
city_broadcast_ratio_1 %<>%
filter(Var1 == T) %>%
rename(Freq_01 = Freq,
is_true = Var1,
city_1 = Var2)
city_broadcast_ratio_2 %<>%
filter(Var1 == F) %>%
rename(Freq_02 = Freq,
is_false = Var1,
city_2 = Var2)
# bind data in df for further use
city_broadcast_ratio <-
cbind(city_broadcast_ratio_1, city_broadcast_ratio_2)
# remove unused dfs
rm(city_broadcast_ratio_1, city_broadcast_ratio_2)
# filter for 10 biggest CH cities & rename variables
city_broadcast_ratio %<>%
filter(city_1 %in% c("Zürich", "Genf", "Basel", "Bern",
"Lausanne", "Winterthur", "Luzern",
"St. Gallen", "Lugano", "Biel")) %>%
rename(city = city_1,
broadcasted_bands = Freq_01,
not_broadcasted_bands = Freq_02) %>%
mutate(total_bands = broadcasted_bands + not_broadcasted_bands) %>%
mutate(broadcast_ratio = broadcasted_bands / total_bands * 100) %>%
select(city, broadcasted_bands, total_bands, broadcast_ratio)
# check number of bands in 10 largest CH cities (4866)
sum(city_broadcast_ratio$total_bands)
## [1] 4863
# add percent data for plot
city_broadcast_ratio %<>%
mutate(broadcast_ratio_2 = broadcast_ratio / 100)
# plot broadcast ratio for 10 biggest CH cities
city_broadcast_plot <- ggplot(city_broadcast_ratio,
aes(x = reorder(city, -broadcast_ratio_2),
y = broadcast_ratio_2)) +
geom_bar(stat = "identity", width = 0.5, fill = "#555555") +
theme_minimal() +
scale_y_continuous(limits = c(0, 0.32),
breaks = seq(0, 0.50, by = 0.05),
labels = percent) +
theme_srf() +
theme(panel.grid.major.x = element_blank(),
axis.title.y = element_blank(),
axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 12),
title = element_text(size = 16)) +
labs(title = "Anteil Bands im Radio: Die zehn grössten Schweizer Städte",
x = "")
# save plots
ggsave(paste0( "output/city_broadcast_ratio.jpg"), city_broadcast_plot,
device = "jpg", units = "cm",
width = 623 / 22, height = 468 / 22, bg = "#f5f5f2")
Der Code in diesem RMarkdown wird mit lintr automatisch auf den Wickham’schen tidyverse style guide überprüft.
lintr::with_defaults(commented_code_linter = NULL) # does not work yet
lintr::lint("main.Rmd")
## main.Rmd:358:1: style: lines should not be more than 80 characters.
## bands <- bands[-which ( (bands$state_code == "AR") & bands$city %in% grep("germany|abidjan|monaco|almere|auriol|avignon|annecy|hersfeld|bellevaux|beziers|bordeaux|boulogne|casablanca|brooklyn|cuenca|dordogne|dresden|düren|epinal|evry|grenoble|italia|argentina|kingston|pleubian|london|lüdenscheid|lyon|marseille|carrara|melun|metz|mons|montpellier|mulhouse|münchen|nancy|nantes|moscow|oakland|ornans|paris|zagreb|piacenza|brasil|sacramento|egreve|vallons|soresina|saint-pargoire|laprairie|pau|toscana|tours|morbegno|ales|trashington|crest|niemandsland|romanshorn|gallen|luzern|g-town",
## ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~