library(tidyverse)
<- read_delim("data/DK.txt", col_names = NULL) %>%
df select(X2, X3, X4, X5, X6, X15)
<- df %>%
df2 mutate(Stednavn = paste(X2, X3, X4, sep = ",")) %>%
select(Stednavn, X5, X6, X15) %>%
mutate(sted = str_split(Stednavn, ",")) %>%
unnest(sted) %>%
rename(længdegrad = X6) %>%
rename(breddegrad = X5) %>%
select(sted, længdegrad, breddegrad, X15)
<- df2 %>%
df2_duplicates filter(duplicated(sted))
<- df2 %>%
df3 anti_join(df2_duplicates)
<- df2_duplicates %>%
df_duplicates_unique filter(X15 > 0) %>%
unique()
<- df3 %>%
df_4 rbind(df_duplicates_unique)
write_csv(df_4, "data/Stedkoordinater.csv")
Første eksperiment med kort
Vores søgeinterface er ordnet kronologisk. Det er på mange måder en konventionel fremstilling, der givetvis vil svare til de fleste brugeres forventning. Imidlertid kan man forestille sig andre indgange til artiklerne. En oplagt mulighed er at forsøge at præsentere materialet på kort. Denne artikel demonstrerer et eksperiment i at spatialisere vores data og skabe en indgang, der tillader en interaktiv indgang til disse data.
Skabelse af et brugbart datasæt over danske stedkoordinater
Der findes ikke noget udtømmende datasæt over stednavne og koordinater på lokaliteter fra starten af 1800-tallet. Til gengæld findes der flere ganske udførlige datasæt med moderne stednavne. I denne guide bruger vi et datasæt over danske stednavne med tilhørende koordinater hentet fra geonames.org. Datasættet har den fordel, at det også indeholder synonymer og stavevariationer for hvert stednavn. Imidlertid er der også mange dubletter og homonymer.
Det følgende kode er et forsøg på at transformere data fra geonames til et format, der kan bruges til vores formål: altså et format, hvor der for hver variation af et stednavn findes et enkelt sæt af koordinater.
Så langt så godt. Imidlertid ved vi også, at datasættet langt fra er komplet. Især på mindre landsbyer er det upræcist af den simple grund, at der findes mange landsbyer med samme navn i Danmark; Astrup, Søby, Borup osv. Som princip valgte vi i tilfælde af homonymi at beholde den lokalitet datasættet har knyttet til flest indbyggere. Dette sker dog først senere i koden.
Join af data
Næste skridt var at flette de to datasæt sammen. Det skete ved at bruge stednavnet som en nøgle.
I samme proces lavede vi en række manuelle tilpasninger og slettede en række stednavne, der enten var systematisk fejlgenkendt eller blev knyttet til forkerte placeringer, fordi de er homonymer. Fejlidentifikationer kunne f.eks. være personnavne, der er identiske med steder.
<- read_csv("Stedkoordinater.csv") %>%
stednavne mutate(sted = str_to_lower(sted)) %>%
na.omit() %>%
group_by(sted) %>%
slice_max(X15, n = 1)
<- read_csv("df_spacy_steder.csv") %>%
df_spacy na.omit() %>%
mutate(sted = str_split(steder, "; ")) %>%
unnest(sted) %>%
mutate(sted = str_replace(sted, "lindholm", "nørresundby")) %>%
left_join(stednavne) %>%
na.omit() %>%
filter(sted != "danmark") %>%
filter(sted != "paris") %>%
filter(sted != "norge") %>%
filter(sted != "holmen") %>%
filter(sted != "tofte") %>%
filter(sted != "tommerup") %>%
filter(sted != "mollerup") %>%
filter(sted != "petersborg") %>%
filter(sted != "lund") %>%
# filter(!str_detect(sted, "strup")) %>%
select(dato, tekst, indeks, seneste_overskrift, længdegrad, breddegrad, sted)
%>% write_csv("data/df_spacy_koordinater.csv") df_spacy
Hele processen medfører et stort tab af data. Hvor stort er svært at sige præcist, men det er stort. Der er naturligvis det åbenlyse tab: Vi har kun stedkoordinater vedr. danske lokaliteter - men avisen har i høj grad et internationalt udsyn. Mindre systematisk er den store mængde af steder, algoritmen ikke kunne identificere i teksterne. Den uindviede risikerer at overse dette tab, fordi den store mængde data betyder, at algoritmen alligevel er lykkedes med at identificere mange - ofte korrekte - lokaliteter. Det fremstår derved som om, at eksperimentet er lykkedes. Men tabet er der som en tavshed. F.eks. ved vi i denne sammenhæng, at en del artikler handler om stormfloden ved Limfjordstangen i 1825. Men algoritmen finder sjældent de relevante steder - Agger og Thyborøn. Derimod findes enkelte af disse artikler knyttet til stednavnet Thy, hvilket betyder, at artiklerne ikke placeres på selve det konkrete sted, de omtaler. Omtaler af landsbyen Toft, der efter stormfloden blev opgivet og slugt af havet, må ydermere sies fra, grundet ordets homonymi. På denne måde illustrerer resultatet både potentialer og farer ved brugen af værktøjer, der ikke er skræddersyet historiske data.
Skabelsen af et kort-app
For at vise mulighederne ved en spatial præsentation, skabte vi et simpelt app-interface til de kortlagte data. Dette tillader, at man klikker på et stednavn og læser den artikel, der omtaler det. Koden til dette interface ses nedenfor.
Det var ikke muligt at præsentere alle artikler på en gang. Der var for mange. Derfor laver vi med koden en filtrering. Vi valgte at vise artikler, der ved hjælp af vores emne-identifikation var identificeret som knyttet til tematikkerne “naturkatastrofer” og “uvejr”. Vi valgte også at filtrere navnestof fra, da dette indeholder en høj grad af fejlidentifikation. Endelig introducerede vi en smule støj til alle koordinater, sådan at artikler med samme koordinater blev spredt ud i en lille sky. Denne offer af visuel præcision blev udført, for at gøre det muligt at klikke på individuelle artikler.
library(tidyverse)
library(shiny)
library(leaflet)
<- read_csv("df_spacy_koordinater.csv") %>%
df_map filter(!str_detect(indeks, "(navn)")) %>%
filter(str_detect(indeks, "(natur|uvejr)")) %>%
mutate(tekst = paste0("<b>Dato:</b> ",
"<br><b>Sted:</b> ",
dato, "<br><b>Tekst:</b> ",
sted, %>%
tekst)) mutate(længdegrad = jitter(længdegrad, amount = 0.04),
breddegrad = jitter(breddegrad, amount = 0.02))
<- fluidPage(
ui leafletOutput("mymap", height = "95vh"),
p()
)
<- function(input, output, session) {
server $mymap <- renderLeaflet({
outputleaflet() %>%
addProviderTiles("Esri.WorldGrayCanvas") %>%
addCircleMarkers(df_map,
lng = df_map$længdegrad,
lat = df_map$breddegrad,
popup = df_map$tekst,
radius = 3,
weight = 0.5,
opacity = 1,
color = "red",
fill = TRUE,
fillOpacity = 0.05,
popupOptions = popupOptions(maxHeight = 300))
})
}
shinyApp(ui, server)
Du kan udforske denne app ved at klikke på dette link: https://hislabaau.shinyapps.io/Kort/
Fodnoter
Devon Mordell, “Critical Questions for Archives as (Big) Data”, Archivaria 87, 2019: s. 140-161.↩︎