<jupyter_start><jupyter_text>Vizuelizacija podataka na geografskoj mapi >U ovoj svesci ćemo prikazati dva skupa podataka na geografskoj karti: jedan kao koroplet, drugi kao geolokacije. Prikazivanje podataka na geografskoj mapi je tehnički zahtevnije od većine drugih grafičkih prikaza jer u velikoj meri zavisi od eksternih podataka. Nekada je za prikaz potrebno učitati mape sa nekog udaljenog portala (što je bezbednosni rizik), a nekad je potrebno lokalno učitati glomazne fajlove sa geo-podacima. Često je čak potrebno servisima pristupati preko ličnog naloga kako bi se povukle mape. Zato su i instalacije i korišćenje biblioteka za ovu vrstu grafičkog prikaza malo komplikovaniji. Za prikaz podataka u ovog svesci koristićemo dve biblioteke: __geopandas__ i __folium__. Ova prva je posebno zahtevna za instalaciju, dok druga učitava eksterne mape koje GitHub neće prikazati. Zato preporučujemo da je pokrenete kroz [Binder](https://mybinder.org/v2/gh/sverbic/skriptna-obrada-podataka/HEAD) kako biste mogli da radite interaktivno bez lokalne instalacije biblioteka. Ukoliko hoćete samo da čitate sadržaj sveski, možete to da uradite i kroz [nbviewer](https://nbviewer.org/github/sverbic/skriptna-obrada-podataka/blob/main/notebooks/5%20Vizuelizacija%20podataka%20na%20geografskoj%20mapi.ipynb). Konačno, ako hoćete da ipak sve radite na svom računaru, primenite ovo [uputstvo za instalaciju](https://medium.com/analytics-vidhya/fastest-way-to-install-geopandas-in-jupyter-notebook-on-windows-8f734e11fa2b) __geopandas__ biblioteke.    Koroplet Prvi primer vizuelizacije u ovoj svesci je tipa koroplet (eng. _choropleth_). Kod ovog prikaza teritoriju na mapi delimo na manje delove sa jasno određenim konturama pa oblasti unutar kontura bojimo u skladu sa veličinom koju želimo da prikažemo za taj deo teritorije. Mi ćemo koristeći već poznate podatke Republičkog zavoda za statistiku koropletom prikazati prosečnu neto zaradu po opštinama.<jupyter_code>import geopandas as gpd
import pandas as pd
import matplotlib.pyplot as plt<jupyter_output><empty_output><jupyter_text>Fajl koji nam je neophodan za prikazivanje mapa je zbirka kontura oblasti koje hoćemo da prikažemo. Te konture su date kao nizovi koordinata, odnosno poligoni. U tabeli koju smo preuzeli sa sajta Republičkog geodetskog zavoda za svaku opštinu imamo podatke o poligonima u dva formata: _wkt_ i _geometry_. Ta se tabela nalazi u fajlu __opstina.csv__. Pošto su imena opština data i ćirilicom obavezno stavite `encoding='UTF-8'`. Obratite pažnju da csv fajl otvaramo pomoću funkcije `read_file()` biblioteke __geopandas__.<jupyter_code>konture=gpd.read_file('data/opstina.csv', encoding='UTF-8')<jupyter_output><empty_output><jupyter_text>Struktura __konture__ jeste tabela, ali pripada posebnom tipu podataka sa kojim se do sada nismo susretali. Ukoliko učitana tabela sadrži kolonu __geometry__ sa poligonima, Pajton će pomoću funkcije `plot()` znati da ih iscrta čak i bez ikakvih argumenata.<jupyter_code>type(konture)
konture.head(2)<jupyter_output><empty_output><jupyter_text>Ovako izgledaju konture svih 197 opština u Srbiji.<jupyter_code>konture.plot()<jupyter_output><empty_output><jupyter_text>Primetite da koordinate na mapi ne odgovaraju stepenima geografske dužine i širine. Razlog za to je što se u geodeziji više koriste [UTM koordinate](https://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system). Ko hoće može da izvrši konverziju ovih podataka, ali nama sada to nije potrebno. Hoćemo samo mapu. Štaviše, mogli bismo da isključimo okvir jer nam ovde praktično ničemu ne služi.  Povezivanje kontura sa vrednostima Podatke o neto zaradi i konturama opština smo našli u dva različita fajla. Sada je potrebno da povežemo te dve tabele. Za početak, da učitamo i tu drugu tabelu.<jupyter_code>opps=pd.read_csv("data/03IND01.csv",sep=";")
opps.head()<jupyter_output><empty_output><jupyter_text>Ova tabela ima više podataka nego što nam je potrebno. Takođe, u istoj koloni ima različite indikatore. Izdvojićemo samo indikator koji nas interesuje (neto zarada) i ukloniti nepotrebne kolone. U Ekselu bismo ovo uradili pomoću pivot-tabela. U Pajtonu takođe postoji takva funkcija, ali je jednostavnije da novoj promenljivoj **neto_zarada** samo dodelimo ono što nas interesuje.<jupyter_code>neto_zarada=opps[opps['Indikator']=='Просечна нето зарада за месец, према општини пребивалишта запослених']
neto_zarada.head()
neto_zarada=neto_zarada[['idter','nter','vrednost']]
neto_zarada = neto_zarada.astype({'vrednost':float})
neto_zarada<jupyter_output><empty_output><jupyter_text>Ako pažljivo pogledate nazivi opština nisu isti u prvoj i drugoj tabeli. U prvoj (__konture__), na primer, piše "ALEKSANDROVAC" i "АЛЕКСАНДРОВАЦ", dok u drugoj (__neto_zarada__) imamo "Александровац". Povezivanje po imenu opštine bi moglo da bude problematično. Srećom, u obe tabele imamo matične brojeve opština. U prvoj tabeli to je kolona __opstina_maticni_broj__, a u drugoj __idter__. Da bi dalji rad bio jednostavniji, pomoću funkcije `rename()` preimenovaćemo naziv kolone u obe tabele u __MBO__.<jupyter_code>konture=konture.rename(columns={'opstina_maticni_broj':'MBO'})
konture['MBO']=konture['MBO'].astype(int)
neto_zarada=neto_zarada.rename(columns={'idter':'MBO'})
neto_zarada['MBO']=neto_zarada['MBO'].astype(int)<jupyter_output><empty_output><jupyter_text>Povezivanje dve tabele ćemo uraditi pomoću funkcije `merge()` po koloni __MBO__.<jupyter_code>konture2 = pd.merge(konture,neto_zarada,on='MBO')
konture2.head()<jupyter_output><empty_output><jupyter_text>Sada bi za svaku opštinu u tabeli trebalo da imamo i podatke o zaradi i konture. Ostalo je još samo da to prikažemo na mapi tako što ćemo kao argument funkcije `plot()` staviti neto zaradu, odnosno `column='vrednost'`.<jupyter_code>konture2.plot(column='vrednost',legend=True)<jupyter_output><empty_output><jupyter_text>Kada pažljivo pogledate mapu, videćete da podaci za opštine na Kosovu i Metohiji nisu prikazani. Tabela opština sa konturama ima 197 redova, a tabela sa podacima o zaradama 175. Republički zavod za statistiku u svojim izveštajima nema mesečne pokazatelje za KiM. Zbog toga je spojena tabela kraća za ta 24 reda. Imajte u vidu da zvanični podaci različitih državnih organa mogu da se razlikuju po ovom pitanju. Što se estetike mape tiče, istu mapu možemo da prikažemo i sa nešto više detalja. U narednoj ćeliji je primer kako to može da se uradi. Slobodno varirajte parametre i izaberite mapu koja se vama najviše sviđa.<jupyter_code>konture2.plot(column='vrednost', legend=True, cmap="hot", figsize=(15, 10))
plt.axis('off')
plt.title('Prosečna mesečna neto zarada po opštinama', fontdict={'fontsize': '20'})

# navođenje izvora podatka
plt.annotate('Izvori podataka: \nhttp://data.gov.rs (2020)\nhttps://opendata.geosrbija.rs (2021)',
             xy=(0.2, 0.10),  xycoords='figure fraction', horizontalalignment='left', verticalalignment='top', 
             fontsize=10, color='#555555');<jupyter_output><empty_output><jupyter_text>Prikaz geolokacija Mnogi podaci koje imamo u tabelama predstavljaju geo-podatke, odnosno podatke u vezi sa raznim toponimima, npr. državama, opštinama ili lokacijama. To nam omogućava da određene podatke pridružimo geo-lokacijama i predstavimo ih na mapi. Lokacije objekata date sa geografskom dužinom (longitudom) i širinom (latitudom) nazivamo geolokacijama. Fajlovi u kojima se navode geolokacije mogu imati različite formate (CSV, JSON, KML itd.). Koji god da uzmemo, Pajton će znati kako da ga prevede u _DataFrame_.  Ovde ćemo konkretno uzeti [lokacije državnih automatskih mernih stanica za praćenje kvaliteta vazduha u Srbiji](https://data.gov.rs/sr/datasets/metapodatsi-drzhavne-mrezhe-automatskikh-mernikh-stanitsa-za-pratshenje-kvaliteta-vazdukha/). Videćemo tačno koliko ima ovakvih stanica i gde se nalaze. CSV fajl sa ovim podacima je dostupan na Portalu otvorenih podataka. Kopija fajla je u folderu __data__ sa ostalim relevantnim podacima za ovaj praktikum.<jupyter_code>data=pd.read_csv("data/stanice_kvalitet_vazuha.csv")
data.head()<jupyter_output><empty_output><jupyter_text>Za prikaz ovih podataka iskoristićemo biblioteku __folium__ koja zahteva pristup internetu kako bi funkcije preuzele odgovarajuće mape. Ukoliko nemate instaliranu ovu biblioteku, samo učinite to sa `pip install folium`.<jupyter_code>import folium<jupyter_output><empty_output><jupyter_text>Mapa koju kreira funkcija `Map()` je objekat čiji su argumenti centar mape, tip mape i razmera. Dovoljno je da napišemo ime ovog objekta u ćeliji koju izvršavamo da dobijemo detaljnu interaktivnu mapu koju proizvoljno možemo da pomeramo i zumiramo.<jupyter_code>mapa = folium.Map(location=[44,20], tiles="OpenStreetMap", zoom_start=7)
mapa<jupyter_output><empty_output><jupyter_text>Dodavanje lokacija na koje ćemo staviti markere radimo pomoću funkcije `Marker()` čiji su argumenti latituda, longituda i oznaka lokacije. Te detalje onda dodajemo mapi pomoću funkcije `add_to()`.<jupyter_code>for i in range(0,len(data)):
   folium.Marker(
      location=[data.iloc[i]['latitude'], data.iloc[i]['longitude']],
      popup=data.iloc[i]['naziv'],
   ).add_to(mapa)
mapa<jupyter_output><empty_output><jupyter_text>Interaktivnu mapu konačno možemo da snimimo u html fajl pomoću funkcije `save()`.<jupyter_code>mapa.save('output/automatske_merne_stanice.html')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.07493870589489393, 'fraction_numerical': 0.007888284831041467, 'mean_word_length': 6.469745222929936, 'pattern_counts': {'":': 0, '<': 61, '<?xml version=': 0, '>': 62, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '15', 'dir': 'jupyter-structured-clean-dedup', 'id': '414888', 'license': 'MIT', 'n_tokens_mistral': 3967, 'n_tokens_neox': 3878, 'n_words': 1012, 'path': 'notebooks/5 Vizuelizacija podataka na geografskoj mapi.ipynb', 'repo_name': 'sverbic/skriptna-obrada-podataka', 'size': '9381'}