# Kartendaten mit Python
Wir verwenden unsere Data-Processing-Fertigkeiten, um Kartendaten zu modifizieren und darzustellen.
### Teil 1: Gemeindedaten in einem Dictionary speichern:
Die Gemeinde-Daten (Einwohner, Fläche) aus `gemeinden.csv` sollen über den Gemeindenamen als Schlüssel abrufbar sein. Verwende den Code von [[gf_informatik:daten:processing:dictionaries#aufgabe_2csv_in_ein_dictionary_einlesen|Dictionaries: Aufgabe 2]] und ändere ihn so, dass die Gemeindedaten über Gemeindenamen erfragbar sind.
Dazu gibt es zwei Möglichkeiten - welche gefällt dir besser?
#### Zwei separate Dictionaries
`population` speichert für jede Gemeinde die Anzahl Einwohner, `area` die Fläche.
population = {
'Amriswil': 11365,
'Egnach': 4672,
...
}
area = {
'Amriswil': 9.83,
'Egnach': 12.74,
...
}
#### Ein einziges, verschachteltes Dictionary
Das einzige Dictionary enthält für jede Gemeinde ein kleines Dictionary mit zwei Einträgen:
town_data = {
'Amriswil' : { 'population': 11365, 'area': 9.83 },
'Egnach' : { 'population': 4672, 'area': 12.74 },
...
}
++++Lösung:|
def load_town_data():
data = {}
with open('gemeinden.csv', 'r') as infile:
for line in infile:
values = line.split(',')
try:
town = values[0]
canton = values[1]
population = int(values[2])
area = float(values[3])
data[town] = {'canton': canton, 'population' : population, 'area': area}
except ValueError:
pass
return data
++++
### Teil 2: Haltestellen-Daten einlesen und filtern
Die Haltestellen-Daten der SBB sind in der Datei [[https://kantonsschuleromanshorn.sharepoint.com/:x:/s/FSInformatik/Ee--2g8cf1FJqSwr9V-WVOMB4CiKukEqXjMQi7jhdojD3Q?download=1|sbb.csv]] verfügbar. Die Daten enthalten den Namen der Haltestelle sowie deren Koordinaten als geographische Breite (`Latitude`) und Länge (`Longitude`).
**Achtung**: diese CSV-Datei benützt Semikolons als Separator, nicht Kommas (weil die Haltestellen oft mit Kommas getrennt sind: `Romanshorn, Bahnhof`):
```
Name;Latitude;Longitude
Frauenfeld;47.55606;8.89795
Romanshorn, Bahnhof;47.549999;9.300004
```
Wir filtern eine Anzahl Haltestellen heraus, und geben sie in einer neuen Datei im gleichen Format wieder aus. Damit Google Maps die Datei lesen kann, müssen wir wieder Kommas als Separator verwenden.
Damit Namen mit Kommas trotzdem richtig angezeigt werden, müssen sie in Anführungszeichen (`"`) eingefasst werden:
```
Name,Latitude,Longitude
Frauenfeld,47.55606,8.89795
"Romanshorn, Bahnhof",47.549999,9.300004
```
Zum Beispiel:
* Grosse Ortschaften mit mehr als 10000 Einwohnern (mit Lookup im Dictionary `town_data` / `population`)
* Ortschaften im Kanton Thurgau (mit Lookup - dazu muss neben Bevölkerungszahl und Fläche auch der Kanton gespeichert werden)
* Ortschaften innerhalb eines geographischen Bereichs (Koordinaten innerhalb der unteren linken und der oberen rechten Ecke).
++++Lösung:|
Mit der Funktion `load_town_data` von [[gf_informatik:daten:processing:maps#ein_einziges_verschachteltes_dictionary|Teil 1]]:
def filter_by_population(min_pop):
town_data = load_town_data()
with open('sbb.csv', 'r') as stops, open('filtered.csv', 'w') as filtered:
filtered.write("Name,Latitude,Longitude\n")
for line in stops:
values = line.split(';') # Semikolon!
name = values[0]
try:
lat = float(values[1])
lng = float(values[2])
if name in town_data:
if town_data[name]['population'] >= min_pop:
name = '"' + name + '"' # Namen in "" einpacken
filtered.write(name + "," + str(lat) + "," + str(lng) + '\n')
except ValueError:
pass
filter_by_population(10000)
def filter_by_rectangle(lower_left, upper_right):
with open('sbb.csv', 'r') as stops, open('filtered.csv', 'w') as filtered:
filtered.write("Name,Latitude,Longitude\n")
for line in stops:
values = line.split(';') # Semikolon!
name = values[0]
try:
lat = float(values[1])
lng = float(values[2])
if lat > lower_left[0] and lat < upper_right[0]:
if lng > lower_left[1] and lng < upper_right[1]:
name = '"' + name + '"' # Namen in "" einpacken
filtered.write(','.join([name,str(lat),str(lng)]) + '\n')
except ValueError:
pass
thurgau_ll = (47.37956193869952, 8.63275694257301)
thurgau_ur = (47.701252984008455, 9.451238355155777)
filter_by_rectangle(thurgau_ll, thurgau_ur)
++++
### Teil 3: Die generierte Datei in Google Maps importieren.
Erstelle eine neue Karte auf [[https://www.google.com/maps/d/?hl=de|Google Maps]] und importiere deine CSV-Datei.
Teile deine Karte mit der Lehrperson!
[[https://www.google.com/maps/d/edit?mid=1PY-1HifOIMr7-Z-VFHQs6CRNLmlFEvI&usp=sharing|Beispiel]]
### Teil 4: Optimieren
Zürich wird nie dargestellt, wenn wir die Haltestellen mit den Gemeinde-Daten kombinieren. Weshalb? Wie könnten wir das Problem lösen?
++++Lösung:|
* Es gibt keine Haltestelle "Zürich", nur "Zürich HB" - darum wird diese in den Gemeinden nie gefunden.
* Abhilfe: wir könnten jeweils nach dem ersten Wort des Haltestellennamens suchen (`name.split()[0]`)...
* ... und aufpassen, dass wir dann nicht alle Tramhaltestellen Zürichs darstellen
++++