Cleanup
This commit is contained in:
parent
16ac53e6af
commit
52df7dc019
82 changed files with 516 additions and 719 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
cache/
|
16
README.md
Normal file
16
README.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# erfamap
|
||||||
|
|
||||||
|
Generate a map similar to https://www.ccc.de/regional from Wikidata and the doku.ccc.de Semantic MediaWiki data.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
For a quick test run, point the script at the cache.example directory:
|
||||||
|
|
||||||
|
```
|
||||||
|
./generate_map.py --cache-directory cache.example
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Fonts
|
||||||
|
|
||||||
|
The font contained in `style/concertone-regular.ttf` was created by Johan Kallas (johankallas@gmail.com) and is licensed unter the terms of the SIL Open Font License v1.10.
|
1
cache.example/chaostreff-info.json
Normal file
1
cache.example/chaostreff-info.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"Regensburg": [12.11902809759291, 49.009833549999996], "Erfurt": [11.039392, 50.9828132], "Amsterdam": [4.870297612903226, 52.36339370322581], "Luxemburg": [6.1226317, 49.6207341], "Kiel": [10.135555, 54.3227085], "Alzey": [8.328899881948397, 49.702704049999994], "Augsburg": [10.886817639154547, 48.35789355], "Backnang": [9.4295622, 48.9487308], "Bayreuth": [11.574946989405685, 49.9477097], "Bern": [7.4484931, 46.9564373], "Bielefeld": [8.533127303708476, 52.038277], "Budapest": [19.059225604898185, 47.489209200000005], "Chemnitz": [12.9298883, 50.8166968], "Coburg": [10.9660664, 50.2633598], "Rapperswil-Jona": [8.83370045, 47.2252042], "Cottbus": [14.3221859, 51.768973], "Flensburg": [9.423505460496958, 54.80446775], "Gie\u00dfen": [8.6790748, 50.5820278], "Graz": [15.450608284226139, 47.0655229], "Halle (Saale)": [11.992221563581825, 51.47991935], "Heidelberg": [8.6660724, 49.4183048], "Hildesheim": [9.9467753, 52.1685013], "Hilpoltstein": [11.19428251600182, 49.1892185], "Ingolstadt": [11.381725, 48.7710702], "Innsbruck": [11.3962816, 47.257827], "Iserlohn": [7.6979603, 51.3743032], "Itzehoe": [9.50196591631791, 53.9379972], "Jena": [11.5826767, 50.929203], "Klaus": [9.6460406, 47.304616], "Ludwigsburg": [9.184755297842258, 48.8958537], "Marburg": [8.7783888, 50.8161331], "M\u00fcnster": [7.6386827, 51.9446182], "N\u00fcrnberg": [11.081815196597816, 49.44836835], "Osnabr\u00fcck": [8.047635, 52.2719595], "Potsdam": [13.078557, 52.3894652], "Recklinghausen": [7.1691246, 51.62435], "Rothenburg ob der Tauber": [10.1779991, 49.3783145], "Rotterdam": [4.433639012034096, 51.9099513], "Schwerin": [11.4182505, 53.6010948], "Villingen-Schwenningen": [8.455686041710013, 48.06480535], "Winterthur": [8.7291498, 47.4991723], "Wuppertal": [7.144908700674055, 51.26671315], "L\u00fcbeck": [10.6713232, 53.8687751], "Bonn": [7.0987248, 50.7387823], "Saarbr\u00fccken": [7.0357391, 49.279199], "Aalen": [10.0931765, 48.8362705], "Trier": [6.6338265, 49.7529551], "Aschaffenburg": [9.1358843, 49.9878536], "Offenburg": [7.9458244, 48.4762239], "L\u00f6rrach": [7.6650755, 47.6155335]}
|
1
cache.example/erfa-info.json
Normal file
1
cache.example/erfa-info.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"Erlangen": [11.0028028, 49.6000372], "Paderborn": [8.7479251, 51.7171873], "Hamburg": [9.9443486, 53.5583644], "Aachen": [6.091774700480718, 50.7715109], "Basel": [7.6342977, 47.5323068], "Berlin": [13.38283, 52.5217046], "Bremen": [8.7879452, 53.0864586], "K\u00f6ln": [6.912896, 50.9505492], "Darmstadt": [8.6511275, 49.8708409], "Dresden": [13.7288095, 51.0811269], "D\u00fcsseldorf": [6.7996122, 51.2125738], "Frankfurt am Main": [8.6362035, 50.1241797], "Freiburg": [7.8405746483681735, 47.99297755], "G\u00f6ttingen": [9.9446185, 51.5453725], "Hannover": [9.717936908887404, 52.38812135], "Karlsruhe": [8.4073787, 49.0066019], "Mannheim": [8.4886818, 49.4636517], "M\u00fcnchen": [11.5607949, 48.153629], "Salzburg": [13.0561199, 47.7939873], "Stuttgart": [9.1800132, 48.7784485], "Ulm": [9.9910884, 48.4005863], "Wien": [16.35611792351422, 48.209451099999995], "Wiesbaden": [8.2295012, 50.0831784], "Z\u00fcrich": [8.5203159, 47.3869751], "Siegen": [8.0044503, 50.8689203], "Kaiserslautern": [7.762277299724986, 49.44049735], "Essen": [7.024639594585695, 51.43860565], "Dortmund": [7.464966783180763, 51.52768425], "Fulda": [9.6775152, 50.5588931], "W\u00fcrzburg": [9.923678752181619, 49.80223915], "Bamberg": [10.89268892402827, 49.90189135], "Kassel": [9.484939, 51.3183203]}
|
1
cache.example/shapes_countries/Q1246.json
Normal file
1
cache.example/shapes_countries/Q1246.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q142.json
Normal file
1
cache.example/shapes_countries/Q142.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q183.json
Normal file
1
cache.example/shapes_countries/Q183.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q184.json
Normal file
1
cache.example/shapes_countries/Q184.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q189.json
Normal file
1
cache.example/shapes_countries/Q189.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q191.json
Normal file
1
cache.example/shapes_countries/Q191.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q20.json
Normal file
1
cache.example/shapes_countries/Q20.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q211.json
Normal file
1
cache.example/shapes_countries/Q211.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q212.json
Normal file
1
cache.example/shapes_countries/Q212.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q21203.json
Normal file
1
cache.example/shapes_countries/Q21203.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"license":"CC0-1.0","description":{"en":"Aruba","en-gb":"Aruba"},"sources":"Part of the Country Polygons as GeoJSON dataset. Available from Datahub: [https://datahub.io/core/geo-countries https://datahub.io/core/geo-countries], under the [https://opendatacommons.org/licenses/pddl/1.0/ Open Data Commons Public Domain Dedication and License].","zoom":8,"latitude":12.499599017202,"longitude":-69.952428,"data":{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"ADMIN":"Aruba","ISO_A3":"ABW"},"geometry":{"type":"Polygon","coordinates":[[[-69.996937629,12.577582098],[-69.936390754,12.531724351],[-69.924672004,12.519232489],[-69.915760871,12.497015692],[-69.88019772,12.453558661],[-69.876820442,12.427394924],[-69.888091601,12.417669989],[-69.908802864,12.417792059],[-69.930531379,12.42597077],[-69.945139127,12.440375067],[-69.924672004,12.440375067],[-69.924672004,12.447211005],[-69.958566861,12.463202216],[-70.027658658,12.522935289],[-70.04808509,12.53115469],[-70.058094856,12.537176825],[-70.062408007,12.54682038],[-70.060373502,12.556952216],[-70.051096158,12.574042059],[-70.048736132,12.583726304],[-70.052642382,12.600002346],[-70.05964108,12.614243882],[-70.061105924,12.625392971],[-70.048736132,12.632147528],[-70.007150845,12.585516669],[-69.996937629,12.577582098]]]}}]}}
|
1
cache.example/shapes_countries/Q213.json
Normal file
1
cache.example/shapes_countries/Q213.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q214.json
Normal file
1
cache.example/shapes_countries/Q214.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q215.json
Normal file
1
cache.example/shapes_countries/Q215.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q217.json
Normal file
1
cache.example/shapes_countries/Q217.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q218.json
Normal file
1
cache.example/shapes_countries/Q218.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q219.json
Normal file
1
cache.example/shapes_countries/Q219.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q221.json
Normal file
1
cache.example/shapes_countries/Q221.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q222.json
Normal file
1
cache.example/shapes_countries/Q222.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q224.json
Normal file
1
cache.example/shapes_countries/Q224.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q225.json
Normal file
1
cache.example/shapes_countries/Q225.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q229.json
Normal file
1
cache.example/shapes_countries/Q229.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q232.json
Normal file
1
cache.example/shapes_countries/Q232.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q233.json
Normal file
1
cache.example/shapes_countries/Q233.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"license":"CC0-1.0","description":{"en":"Malta","en-gb":"Malta"},"sources":"Part of the Country Polygons as GeoJSON dataset. Available from Datahub: [https://datahub.io/core/geo-countries https://datahub.io/core/geo-countries], under the [https://opendatacommons.org/licenses/pddl/1.0/ Open Data Commons Public Domain Dedication and License].","zoom":6,"latitude":35.880148964884,"longitude":14.46350097656,"data":{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"ADMIN":"Malta","ISO_A3":"MLT"},"geometry":{"type":"MultiPolygon","coordinates":[[[[14.567149285,35.845607815],[14.561778191,35.829820054],[14.548024936,35.83600495],[14.532481316,35.821966864],[14.527517123,35.813544012],[14.527517123,35.801214911],[14.511485222,35.806463934],[14.507090691,35.8086612],[14.472666863,35.811428127],[14.42448978,35.823675848],[14.38152103,35.842962958],[14.363047722,35.866685289],[14.359873894,35.869696356],[14.345713738,35.875921942],[14.34262129,35.880682684],[14.34262129,35.911688544],[14.338226759,35.946966864],[14.332530144,35.962836005],[14.322032097,35.973130601],[14.33472741,35.982367255],[14.347504102,35.988714911],[14.361501498,35.99241771],[14.377289259,35.993638414],[14.377289259,35.986232815],[14.368174675,35.984849351],[14.3623153,35.982407945],[14.349375847,35.973130601],[14.42847741,35.965725002],[14.445078972,35.960353908],[14.478688998,35.936957098],[14.507823113,35.928534247],[14.512868686,35.920803127],[14.514008009,35.910834052],[14.513926629,35.900824286],[14.519297722,35.899969794],[14.548024936,35.890041408],[14.563161655,35.870021877],[14.567149285,35.845607815]]],[[[14.277598504,36.016669012],[14.260020379,36.013495184],[14.241465691,36.014634507],[14.220876498,36.019191799],[14.201182488,36.026068427],[14.184906446,36.034613348],[14.187998894,36.045396226],[14.184336785,36.056301174],[14.183604363,36.064764716],[14.195485873,36.068101304],[14.25660241,36.075588283],[14.282562696,36.067857164],[14.314789259,36.051092841],[14.334239129,36.034369208],[14.322032097,36.027167059],[14.304453972,36.026597398],[14.277598504,36.016669012]]]]}}]}}
|
1
cache.example/shapes_countries/Q27.json
Normal file
1
cache.example/shapes_countries/Q27.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q28.json
Normal file
1
cache.example/shapes_countries/Q28.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q29.json
Normal file
1
cache.example/shapes_countries/Q29.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q31.json
Normal file
1
cache.example/shapes_countries/Q31.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q32.json
Normal file
1
cache.example/shapes_countries/Q32.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q33.json
Normal file
1
cache.example/shapes_countries/Q33.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q34.json
Normal file
1
cache.example/shapes_countries/Q34.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q347.json
Normal file
1
cache.example/shapes_countries/Q347.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"license":"CC0-1.0","description":{"en":"Liechtenstein","en-gb":"Liechtenstein"},"sources":"Part of the Country Polygons as GeoJSON dataset. Available from Datahub: [https://datahub.io/core/geo-countries https://datahub.io/core/geo-countries], under the [https://opendatacommons.org/licenses/pddl/1.0/ Open Data Commons Public Domain Dedication and License].","zoom":8,"latitude":47.143963438088,"longitude":9.5553588867188,"data":{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"ADMIN":"Liechtenstein","ISO_A3":"LIE"},"geometry":{"type":"Polygon","coordinates":[[[9.58120284,47.056870423],[9.5606356200001,47.052400412],[9.4995540770001,47.059350891],[9.4770231530001,47.063898417],[9.4758862710001,47.073226014],[9.4875651450001,47.083948874],[9.5028613680001,47.094697572],[9.512369832,47.108030091],[9.5118530680001,47.129372457],[9.5034814860001,47.145392151],[9.4926294350001,47.159809876],[9.4849813230001,47.176346334],[9.487358439,47.210013529],[9.5046183680001,47.243732402],[9.5211548250001,47.262801005],[9.5302498780001,47.253654277],[9.5470963950001,47.24303477],[9.5403784580001,47.229107972],[9.5448226320001,47.220322978],[9.5543310950001,47.211615499],[9.5629093830001,47.197740377],[9.5618758540001,47.190609029],[9.5519539790001,47.175571188],[9.5520573320001,47.166889547],[9.5818229570001,47.154900615],[9.6055941160001,47.132266337],[9.6157226970001,47.106764018],[9.6087980550001,47.080770773],[9.58120284,47.056870423]]]}}]}}
|
1
cache.example/shapes_countries/Q35.json
Normal file
1
cache.example/shapes_countries/Q35.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q36.json
Normal file
1
cache.example/shapes_countries/Q36.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q37.json
Normal file
1
cache.example/shapes_countries/Q37.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q38.json
Normal file
1
cache.example/shapes_countries/Q38.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q39.json
Normal file
1
cache.example/shapes_countries/Q39.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q399.json
Normal file
1
cache.example/shapes_countries/Q399.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q40.json
Normal file
1
cache.example/shapes_countries/Q40.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q41.json
Normal file
1
cache.example/shapes_countries/Q41.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q43.json
Normal file
1
cache.example/shapes_countries/Q43.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q45.json
Normal file
1
cache.example/shapes_countries/Q45.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_countries/Q55.json
Normal file
1
cache.example/shapes_countries/Q55.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_filtered/Q142.json
Normal file
1
cache.example/shapes_filtered/Q142.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_filtered/Q213.json
Normal file
1
cache.example/shapes_filtered/Q213.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_filtered/Q214.json
Normal file
1
cache.example/shapes_filtered/Q214.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_filtered/Q215.json
Normal file
1
cache.example/shapes_filtered/Q215.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_filtered/Q28.json
Normal file
1
cache.example/shapes_filtered/Q28.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_filtered/Q31.json
Normal file
1
cache.example/shapes_filtered/Q31.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_filtered/Q32.json
Normal file
1
cache.example/shapes_filtered/Q32.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_filtered/Q347.json
Normal file
1
cache.example/shapes_filtered/Q347.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"license":"CC0-1.0","description":{"en":"Liechtenstein","en-gb":"Liechtenstein"},"sources":"Part of the Country Polygons as GeoJSON dataset. Available from Datahub: [https://datahub.io/core/geo-countries https://datahub.io/core/geo-countries], under the [https://opendatacommons.org/licenses/pddl/1.0/ Open Data Commons Public Domain Dedication and License].","zoom":8,"latitude":47.143963438088,"longitude":9.5553588867188,"data":{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"ADMIN":"Liechtenstein","ISO_A3":"LIE"},"geometry":{"type":"Polygon","coordinates":[[[9.58120284,47.056870423],[9.5606356200001,47.052400412],[9.4995540770001,47.059350891],[9.4770231530001,47.063898417],[9.4758862710001,47.073226014],[9.4875651450001,47.083948874],[9.5028613680001,47.094697572],[9.512369832,47.108030091],[9.5118530680001,47.129372457],[9.5034814860001,47.145392151],[9.4926294350001,47.159809876],[9.4849813230001,47.176346334],[9.487358439,47.210013529],[9.5046183680001,47.243732402],[9.5211548250001,47.262801005],[9.5302498780001,47.253654277],[9.5470963950001,47.24303477],[9.5403784580001,47.229107972],[9.5448226320001,47.220322978],[9.5543310950001,47.211615499],[9.5629093830001,47.197740377],[9.5618758540001,47.190609029],[9.5519539790001,47.175571188],[9.5520573320001,47.166889547],[9.5818229570001,47.154900615],[9.6055941160001,47.132266337],[9.6157226970001,47.106764018],[9.6087980550001,47.080770773],[9.58120284,47.056870423]]]}}]}}
|
1
cache.example/shapes_filtered/Q35.json
Normal file
1
cache.example/shapes_filtered/Q35.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_filtered/Q36.json
Normal file
1
cache.example/shapes_filtered/Q36.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_filtered/Q38.json
Normal file
1
cache.example/shapes_filtered/Q38.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_filtered/Q39.json
Normal file
1
cache.example/shapes_filtered/Q39.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_filtered/Q40.json
Normal file
1
cache.example/shapes_filtered/Q40.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_filtered/Q55.json
Normal file
1
cache.example/shapes_filtered/Q55.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_states/Q1055.json
Normal file
1
cache.example/shapes_states/Q1055.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"license":"CC0-1.0","description":{"en":"Hamburg","en-gb":"Hamburg"},"sources":"Created from the Natural Earth Admin1 Polygons dataset. Available from Datahub:[https://datahub.io/core/geo-ne-admin1 https://datahub.io/core/geo-ne-admin1], under the [https://opendatacommons.org/licenses/pddl/1.0/ Open Data Commons Public Domain Dedication and License].","zoom":8,"latitude":53.45493,"longitude":10.31263,"data":{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"stroke":"#555555","stroke-width":2,"stroke-opacity":1,"fill":"#555555","fill-opacity":0.5},"geometry":{"type":"MultiPolygon","coordinates":[[[[10.31263,53.45493],[10.31341,53.45524],[10.31496,53.4556],[10.31883,53.45586],[10.32069,53.45565],[10.32317,53.45043],[10.32798,53.43266],[10.28535,53.43266],[10.27599,53.4308],[10.26607,53.42708],[10.24375,53.4094],[10.24158,53.40661],[10.18654,53.40439],[10.16985,53.40661],[10.15357,53.41364],[10.14308,53.42268],[10.1314,53.43059],[10.1112,53.4339],[10.0991,53.43948],[10.08314,53.4509],[10.07601,53.45043],[10.03875,53.44309],[10.03239,53.44098],[10.02945,53.43839],[10.0296,53.43664],[10.03007,53.43452],[10.03069,53.43307],[10.03084,53.43116],[10.03038,53.42919],[10.02789,53.42749],[10.01131,53.42149],[9.98537,53.41506],[9.97529,53.41405],[9.96847,53.41447],[9.95002,53.42201],[9.94501,53.42284],[9.9388,53.42188],[9.91896,53.4156],[9.91291,53.4156],[9.90935,53.41808],[9.90873,53.42155],[9.90811,53.4308],[9.90547,53.44123],[9.90005,53.44661],[9.89571,53.44865],[9.89085,53.44904],[9.88279,53.44723],[9.87752,53.44477],[9.86511,53.43341],[9.86124,53.43224],[9.85721,53.43286],[9.82444,53.45141],[9.81669,53.45694],[9.81065,53.46237],[9.80476,53.46919],[9.80073,53.47524],[9.79607,53.48428],[9.79375,53.48779],[9.79142,53.48981],[9.78522,53.49245],[9.78243,53.49431],[9.78073,53.49658],[9.77933,53.50009],[9.77726,53.50232],[9.76843,53.50816],[9.76471,53.54376],[9.76397,53.54768],[9.76401,53.54767],[9.81902,53.54035],[9.83204,53.54361],[9.81959,53.55663],[9.78207,53.56973],[9.74081,53.57257],[9.74088,53.57275],[9.74889,53.59197],[9.7506,53.59802],[9.75168,53.60469],[9.75277,53.60789],[9.75401,53.61004],[9.75618,53.61182],[9.76021,53.6142],[9.76331,53.61657],[9.76502,53.61887],[9.76657,53.62629],[9.76843,53.62918],[9.77168,53.6297],[9.77649,53.62939],[9.78817,53.62758],[9.79654,53.62463],[9.79871,53.62324],[9.80693,53.61988],[9.81003,53.61786],[9.81049,53.61507],[9.80755,53.6065],[9.80646,53.6019],[9.80615,53.59905],[9.80693,53.59714],[9.80801,53.59611],[9.8091,53.59528],[9.81049,53.59461],[9.81251,53.59389],[9.81607,53.59311],[9.82863,53.59725],[9.92733,53.64567],[9.95281,53.65037],[9.9804,53.64673],[9.98428,53.64688],[9.98986,53.64856],[9.99405,53.65143],[10.00371,53.6668],[10.00821,53.67068],[10.01363,53.673],[10.02588,53.67551],[10.03286,53.67628],[10.03906,53.67626],[10.05223,53.67486],[10.06019,53.67796],[10.06515,53.68081],[10.07818,53.7129],[10.08205,53.71636],[10.08639,53.71889],[10.08872,53.71972],[10.09027,53.72008],[10.0929,53.72018],[10.14225,53.71331],[10.14799,53.71367],[10.15357,53.71564],[10.17109,53.7253],[10.17688,53.72721],[10.18199,53.72778],[10.18742,53.72752],[10.19192,53.72657],[10.19378,53.72509],[10.19486,53.72254],[10.19285,53.7177],[10.19114,53.71517],[10.17982,53.70561],[10.16985,53.6936],[10.16582,53.68737],[10.16473,53.68453],[10.16597,53.6821],[10.16923,53.67864],[10.20478,53.66282],[10.2054,53.66236],[10.20649,53.65698],[10.2068,53.65047],[10.20912,53.64479],[10.21455,53.64184],[10.21889,53.64024],[10.22153,53.63781],[10.22277,53.63365],[10.22122,53.62618],[10.21998,53.62288],[10.21672,53.61771],[10.21533,53.6142],[10.21331,53.60169],[10.21238,53.58815],[10.2116,53.58557],[10.21067,53.58435],[10.20866,53.58303],[10.20602,53.58187],[10.19595,53.57921],[10.17812,53.57652],[10.17548,53.57544],[10.17316,53.57378],[10.17285,53.57053],[10.17409,53.56598],[10.18075,53.54963],[10.1823,53.54097],[10.18215,53.53405],[10.18323,53.52896],[10.18664,53.52531],[10.1975,53.52175],[10.21393,53.51883],[10.22277,53.51301],[10.24762,53.48878],[10.26979,53.48149],[10.27785,53.47751],[10.31263,53.45493]]]]}}]}}
|
1
cache.example/shapes_states/Q1194.json
Normal file
1
cache.example/shapes_states/Q1194.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_states/Q1196.json
Normal file
1
cache.example/shapes_states/Q1196.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_states/Q1197.json
Normal file
1
cache.example/shapes_states/Q1197.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_states/Q1198.json
Normal file
1
cache.example/shapes_states/Q1198.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_states/Q1199.json
Normal file
1
cache.example/shapes_states/Q1199.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_states/Q1200.json
Normal file
1
cache.example/shapes_states/Q1200.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_states/Q1201.json
Normal file
1
cache.example/shapes_states/Q1201.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"license":"CC0-1.0","description":{"en":"Saarland","en-gb":"Saarland"},"sources":"Created from the Natural Earth Admin1 Polygons dataset. Available from Datahub:[https://datahub.io/core/geo-ne-admin1 https://datahub.io/core/geo-ne-admin1], under the [https://opendatacommons.org/licenses/pddl/1.0/ Open Data Commons Public Domain Dedication and License].","zoom":8,"latitude":49.56354,"longitude":7.21913,"data":{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"stroke":"#555555","stroke-width":2,"stroke-opacity":1,"fill":"#555555","fill-opacity":0.5},"geometry":{"type":"MultiPolygon","coordinates":[[[[7.21913,49.56354],[7.23788,49.56617],[7.24719,49.56834],[7.25592,49.57232],[7.26181,49.57599],[7.26755,49.5785],[7.27065,49.5778],[7.27328,49.57672],[7.27344,49.56168],[7.27948,49.54891],[7.29096,49.53434],[7.29235,49.52519],[7.29235,49.51191],[7.29359,49.50711],[7.29576,49.50427],[7.29979,49.50396],[7.30382,49.50323],[7.30584,49.50251],[7.30723,49.50044],[7.30816,49.49726],[7.30909,49.49026],[7.30847,49.4854],[7.30537,49.48204],[7.29514,49.47879],[7.28755,49.47548],[7.27917,49.47078],[7.25979,49.4545],[7.25478,49.45166],[7.25091,49.45099],[7.2461,49.44613],[7.2523,49.43099],[7.27638,49.41213],[7.29344,49.39859],[7.29576,49.39425],[7.29499,49.39342],[7.29452,49.39254],[7.29344,49.39146],[7.29142,49.38882],[7.30119,49.38484],[7.35116,49.37931],[7.3754,49.37337],[7.38516,49.36967],[7.39059,49.36071],[7.38485,49.35384],[7.38423,49.35166],[7.38346,49.34815],[7.38687,49.34386],[7.38795,49.3404],[7.38733,49.33683],[7.38253,49.33084],[7.37881,49.32743],[7.37462,49.32464],[7.3631,49.31898],[7.35845,49.31567],[7.35674,49.31273],[7.35426,49.3018],[7.35271,49.29771],[7.34961,49.29472],[7.34279,49.291],[7.34,49.28883],[7.33736,49.28609],[7.33581,49.28299],[7.33473,49.27921],[7.33333,49.27182],[7.32992,49.26418],[7.32325,49.25674],[7.32062,49.25451],[7.3186,49.25299],[7.31674,49.25193],[7.31457,49.2511],[7.31194,49.25043],[7.30739,49.25007],[7.30584,49.25017],[7.30491,49.25033],[7.30398,49.25053],[7.30243,49.25079],[7.3001,49.25095],[7.29654,49.25048],[7.29576,49.2502],[7.29421,49.24842],[7.28817,49.2402],[7.28662,49.23555],[7.28693,49.23079],[7.29034,49.22278],[7.29235,49.217],[7.2939,49.20726],[7.29468,49.20516],[7.33023,49.1794],[7.34914,49.16868],[7.36919,49.16904],[7.37126,49.16661],[7.37163,49.16617],[7.36759,49.16537],[7.35095,49.15917],[7.3463,49.15421],[7.33907,49.13969],[7.334,49.13416],[7.32646,49.13183],[7.30599,49.13013],[7.2971,49.12811],[7.2908,49.1231],[7.28026,49.10899],[7.27437,49.10501],[7.26806,49.10563],[7.24119,49.1139],[7.15499,49.11442],[7.13928,49.11793],[7.12358,49.12331],[7.08533,49.14155],[7.07986,49.14201],[7.07076,49.13612],[7.07159,49.13059],[7.07479,49.12537],[7.07324,49.12031],[7.04255,49.1076],[7.02053,49.11897],[7.00896,49.14641],[7.00947,49.1817],[6.98787,49.18243],[6.92545,49.20558],[6.91439,49.20666],[6.88524,49.2048],[6.84349,49.21105],[6.83346,49.20945],[6.82768,49.19555],[6.83522,49.17938],[6.83904,49.16279],[6.82178,49.14775],[6.80907,49.14584],[6.77011,49.1553],[6.72556,49.15555],[6.71378,49.15886],[6.70097,49.17287],[6.70376,49.18511],[6.70882,49.19777],[6.70252,49.21364],[6.69848,49.21359],[6.68505,49.2078],[6.6806,49.20749],[6.67792,49.21105],[6.67595,49.21891],[6.67482,49.22113],[6.67161,49.22532],[6.66376,49.24387],[6.65952,49.24676],[6.64567,49.25002],[6.6403,49.25276],[6.63916,49.25679],[6.64123,49.26692],[6.63968,49.27115],[6.57317,49.31312],[6.55643,49.3264],[6.55012,49.33802],[6.5556,49.34717],[6.57338,49.34774],[6.57772,49.3558],[6.57431,49.36179],[6.52573,49.39549],[6.51881,49.40215],[6.52077,49.40257],[6.52056,49.40815],[6.51788,49.41642],[6.51167,49.42474],[6.49452,49.43554],[6.40274,49.46546],[6.39168,49.4667],[6.38352,49.46463],[6.3645,49.4561],[6.35385,49.45476],[6.34531,49.45535],[6.34538,49.46272],[6.34228,49.493],[6.34881,49.52529],[6.35649,49.52592],[6.48997,49.53382],[6.60511,49.53021],[6.66981,49.54938],[6.69352,49.54793],[6.6973,49.54809],[6.71233,49.55031],[6.85972,49.59449],[6.9364,49.62715],[6.94214,49.62793],[6.94881,49.62746],[6.96214,49.62359],[6.97113,49.61868],[6.97862,49.61958],[6.99878,49.62948],[7.06022,49.60751],[7.06518,49.60493],[7.072,49.60354],[7.13283,49.60201],[7.13794,49.6009],[7.15954,49.5871],[7.19659,49.57005],[7.19959,49.56731],[7.20223,49.56545],[7.20843,49.56437],[7.21913,49.56354]]]]}}]}}
|
1
cache.example/shapes_states/Q1202.json
Normal file
1
cache.example/shapes_states/Q1202.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_states/Q1205.json
Normal file
1
cache.example/shapes_states/Q1205.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_states/Q1206.json
Normal file
1
cache.example/shapes_states/Q1206.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_states/Q1208.json
Normal file
1
cache.example/shapes_states/Q1208.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_states/Q1209.json
Normal file
1
cache.example/shapes_states/Q1209.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"license":"CC0-1.0","description":{"en":"Bremen","en-gb":"Bremen"},"sources":"Created from the Natural Earth Admin1 Polygons dataset. Available from Datahub:[https://datahub.io/core/geo-ne-admin1 https://datahub.io/core/geo-ne-admin1], under the [https://opendatacommons.org/licenses/pddl/1.0/ Open Data Commons Public Domain Dedication and License].","zoom":8,"latitude":53.21257,"longitude":8.56059,"data":{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"stroke":"#555555","stroke-width":2,"stroke-opacity":1,"fill":"#555555","fill-opacity":0.5},"geometry":{"type":"MultiPolygon","coordinates":[[[[8.56059,53.21257],[8.56447,53.21179],[8.56633,53.21184],[8.58509,53.21541],[8.5902,53.21536],[8.61785,53.20484],[8.67681,53.19037],[8.6903,53.18843],[8.70115,53.18911],[8.70363,53.18952],[8.70472,53.18993],[8.70658,53.19112],[8.71046,53.19177],[8.73314,53.19267],[8.74554,53.19161],[8.74756,53.19076],[8.74895,53.1896],[8.74988,53.18833],[8.75019,53.18688],[8.74988,53.18549],[8.74926,53.18389],[8.75144,53.18146],[8.75655,53.17872],[8.77862,53.17027],[8.78373,53.169],[8.81164,53.16957],[8.82389,53.16807],[8.82575,53.16714],[8.84068,53.15794],[8.86052,53.14926],[8.89499,53.13885],[8.90398,53.13761],[8.90941,53.13851],[8.91236,53.13934],[8.91437,53.14063],[8.91577,53.14234],[8.9167,53.14397],[8.91778,53.14694],[8.91933,53.14978],[8.92398,53.1566],[8.92631,53.15934],[8.92848,53.16112],[8.93297,53.16298],[8.93623,53.1628],[8.93938,53.16182],[8.94946,53.15603],[8.97302,53.13955],[8.97535,53.13702],[8.97519,53.13469],[8.97209,53.13247],[8.96047,53.12606],[8.9583,53.1233],[8.95783,53.12193],[8.96155,53.11583],[8.98605,53.10007],[8.98822,53.09717],[8.98992,53.09361],[8.98822,53.09159],[8.9814,53.08593],[8.97907,53.08167],[8.97674,53.07562],[8.97535,53.06188],[8.97411,53.05637],[8.97271,53.05258],[8.95768,53.0426],[8.9229,53.02744],[8.91453,53.02462],[8.86595,53.04751],[8.86564,53.04687],[8.86549,53.04539],[8.86595,53.04265],[8.86595,53.03973],[8.86316,53.03728],[8.85804,53.03568],[8.84409,53.0332],[8.83448,53.03353],[8.82466,53.03501],[8.77707,53.05335],[8.7718,53.05464],[8.76833,53.05464],[8.75857,53.05211],[8.7195,53.04793],[8.70487,53.04955],[8.70394,53.05048],[8.70239,53.05113],[8.70255,53.0517],[8.7027,53.05273],[8.70239,53.05436],[8.7027,53.07986],[8.70177,53.08343],[8.6996,53.08586],[8.69294,53.0881],[8.65382,53.11572],[8.63801,53.1303],[8.63583,53.13391],[8.63382,53.13898],[8.63335,53.14141],[8.63149,53.15957],[8.61723,53.17686],[8.61103,53.18006],[8.58922,53.17898],[8.57806,53.17978],[8.55444,53.1896],[8.513,53.19975],[8.50458,53.21107],[8.50137,53.21706],[8.49605,53.22404],[8.51868,53.22611],[8.52954,53.22466],[8.56059,53.21257]]],[[[8.56245,53.60626],[8.58431,53.60394],[8.62529,53.605],[8.63087,53.60396],[8.6318,53.602],[8.62824,53.59936],[8.62529,53.59681],[8.62297,53.59399],[8.62173,53.59148],[8.62018,53.58761],[8.62111,53.58226],[8.62359,53.57709],[8.63149,53.56753],[8.63521,53.55988],[8.64188,53.53932],[8.64266,53.5319],[8.64188,53.52531],[8.64064,53.51989],[8.63909,53.51666],[8.62359,53.50221],[8.60281,53.49048],[8.60106,53.49002],[8.59951,53.48973],[8.59749,53.49059],[8.59501,53.49219],[8.58834,53.50017],[8.58788,53.50033],[8.58741,53.50035],[8.58555,53.50033],[8.57827,53.49924],[8.573,53.50185],[8.5609,53.5157],[8.5572,53.51994],[8.56577,53.5467],[8.5608,53.5517],[8.53517,53.59077],[8.52752,53.59663],[8.5171,53.61017],[8.51304,53.6171],[8.51341,53.61701],[8.56245,53.60626]]]]}}]}}
|
1
cache.example/shapes_states/Q64.json
Normal file
1
cache.example/shapes_states/Q64.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"license":"CC0-1.0","description":{"en":"Berlin","en-gb":"Berlin"},"sources":"Created from the Natural Earth Admin1 Polygons dataset. Available from Datahub:[https://datahub.io/core/geo-ne-admin1 https://datahub.io/core/geo-ne-admin1], under the [https://opendatacommons.org/licenses/pddl/1.0/ Open Data Commons Public Domain Dedication and License].","zoom":8,"latitude":52.48703,"longitude":13.62633,"data":{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"stroke":"#555555","stroke-width":2,"stroke-opacity":1,"fill":"#555555","fill-opacity":0.5},"geometry":{"type":"MultiPolygon","coordinates":[[[[13.62633,52.48703],[13.66452,52.48977],[13.67754,52.48553],[13.6963,52.4708],[13.7362,52.4598],[13.74255,52.45636],[13.75092,52.45029],[13.75092,52.44688],[13.74953,52.44486],[13.74302,52.4415],[13.73976,52.43949],[13.73852,52.43631],[13.73806,52.43313],[13.73852,52.42665],[13.73666,52.42277],[13.73434,52.41964],[13.71604,52.41039],[13.71232,52.40791],[13.7086,52.40461],[13.70452,52.39789],[13.70452,52.39197],[13.70689,52.38316],[13.70669,52.37804],[13.70534,52.37427],[13.70348,52.37195],[13.70142,52.37001],[13.70002,52.36905],[13.69801,52.36812],[13.69615,52.36755],[13.67336,52.36285],[13.67119,52.3621],[13.667,52.35965],[13.65398,52.34234],[13.64447,52.34203],[13.64354,52.34352],[13.64261,52.34479],[13.64261,52.34748],[13.64121,52.36073],[13.63734,52.37598],[13.63238,52.38187],[13.62649,52.3844],[13.61501,52.38347],[13.6099,52.38378],[13.58473,52.3889],[13.56582,52.39567],[13.52809,52.40492],[13.51972,52.40486],[13.51445,52.40368],[13.51197,52.40166],[13.50918,52.3999],[13.50608,52.39879],[13.50313,52.39815],[13.49492,52.39794],[13.48438,52.39866],[13.47952,52.40047],[13.4758,52.40365],[13.47332,52.40752],[13.46805,52.4137],[13.46309,52.4159],[13.45812,52.41675],[13.44898,52.4159],[13.43363,52.4123],[13.43006,52.41109],[13.42712,52.40946],[13.42495,52.40734],[13.42402,52.40445],[13.42412,52.40161],[13.42474,52.39887],[13.42691,52.3937],[13.42753,52.3907],[13.42753,52.38812],[13.42567,52.38109],[13.39405,52.38122],[13.37575,52.38657],[13.37151,52.38952],[13.36552,52.39546],[13.35462,52.40192],[13.34935,52.4059],[13.34578,52.4074],[13.33663,52.40595],[13.31271,52.4005],[13.30919,52.40109],[13.3048,52.40228],[13.29922,52.41029],[13.29596,52.41401],[13.29426,52.4151],[13.2924,52.41484],[13.29116,52.41411],[13.28573,52.41202],[13.25824,52.40551],[13.25219,52.40476],[13.24816,52.40507],[13.23964,52.41106],[13.22677,52.41592],[13.21964,52.41711],[13.21406,52.41706],[13.17261,52.40517],[13.16951,52.40368],[13.16657,52.40156],[13.16331,52.39815],[13.15928,52.39711],[13.15649,52.39685],[13.12171,52.40114],[13.11799,52.40202],[13.11194,52.40399],[13.09489,52.41199],[13.09272,52.41326],[13.0921,52.4137],[13.09179,52.41422],[13.09164,52.41525],[13.0921,52.41675],[13.09365,52.41871],[13.10311,52.42584],[13.10419,52.42683],[13.10543,52.42832],[13.10528,52.4299],[13.10574,52.43228],[13.10745,52.43453],[13.10977,52.43654],[13.11241,52.4383],[13.11675,52.44047],[13.11691,52.4415],[13.11179,52.44737],[13.11055,52.44987],[13.10915,52.4554],[13.10915,52.45858],[13.11055,52.46501],[13.11287,52.47111],[13.11442,52.4738],[13.1166,52.47597],[13.11954,52.4777],[13.12652,52.48],[13.12962,52.4816],[13.1568,52.50103],[13.15649,52.50419],[13.15664,52.50695],[13.14093,52.52429],[13.14331,52.55193],[13.14781,52.56653],[13.14843,52.57571],[13.14745,52.58098],[13.14486,52.58516],[13.14548,52.588],[13.14683,52.59051],[13.14889,52.59286],[13.1523,52.59793],[13.15478,52.59955],[13.15742,52.6003],[13.16486,52.59819],[13.20755,52.58676],[13.21685,52.58744],[13.21685,52.58945],[13.21607,52.59144],[13.21499,52.59302],[13.21189,52.59622],[13.21034,52.59839],[13.20925,52.60087],[13.20925,52.60382],[13.21003,52.60676],[13.21127,52.60961],[13.22072,52.62599],[13.22351,52.62725],[13.25266,52.62989],[13.26155,52.63307],[13.27255,52.63916],[13.27674,52.64392],[13.28,52.64841],[13.28248,52.65397],[13.28589,52.65606],[13.28914,52.65712],[13.3003,52.65694],[13.30279,52.65619],[13.30186,52.6548],[13.3003,52.65322],[13.29968,52.65131],[13.30263,52.64715],[13.30372,52.64454],[13.3031,52.63529],[13.30449,52.63307],[13.30697,52.63115],[13.31023,52.62966],[13.32656,52.62521],[13.36423,52.62361],[13.3742,52.6249],[13.37978,52.62627],[13.38211,52.62831],[13.38335,52.63084],[13.38877,52.63689],[13.41203,52.64872],[13.4313,52.64095],[13.4341,52.64095],[13.43844,52.64159],[13.44014,52.64438],[13.44247,52.64728],[13.4451,52.64971],[13.46851,52.66332],[13.47378,52.66356],[13.47673,52.66162],[13.47942,52.65777],[13.48355,52.65415],[13.49972,52.64526],[13.50127,52.64351],[13.50236,52.64087],[13.50251,52.63854],[13.50081,52.6294],[13.49926,52.62428],[13.49926,52.61942],[13.50003,52.61389],[13.5005,52.61307],[13.50329,52.61017],[13.56907,52.56341],[13.59093,52.55338],[13.60308,52.55051],[13.6116,52.54524],[13.62649,52.54113],[13.64757,52.53927],[13.6485,52.53163],[13.62509,52.49809],[13.62339,52.49065],[13.62633,52.48703]]]]}}]}}
|
1
cache.example/shapes_states/Q980.json
Normal file
1
cache.example/shapes_states/Q980.json
Normal file
File diff suppressed because one or more lines are too long
1
cache.example/shapes_states/Q985.json
Normal file
1
cache.example/shapes_states/Q985.json
Normal file
File diff suppressed because one or more lines are too long
488
generate_map.py
Normal file → Executable file
488
generate_map.py
Normal file → Executable file
|
@ -2,24 +2,83 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
import urllib.parse
|
||||||
import json
|
import json
|
||||||
import base64
|
import base64
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from lxml import etree
|
||||||
import pyproj
|
import pyproj
|
||||||
from SPARQLWrapper import SPARQLWrapper, JSON
|
|
||||||
from geopy import Nominatim
|
from geopy import Nominatim
|
||||||
|
import tqdm
|
||||||
|
import cairosvg
|
||||||
|
from PIL import Image, ImageFont
|
||||||
|
from PIL.ImageDraw import ImageDraw
|
||||||
|
|
||||||
|
|
||||||
BOUNDING_BOX = [(4.27775, 46.7482713), (19.2403594, 54.9833021)]
|
USER_AGENT = 'Erfamap/v0.1 (https://git.kabelsalat.ch/s3lph/erfamap)'
|
||||||
|
|
||||||
|
|
||||||
|
class CachePaths:
|
||||||
|
|
||||||
|
def __init__(self, path: str):
|
||||||
|
if os.path.exists(path) and not os.path.isdir(path):
|
||||||
|
raise AttributeError(f'Path exists but is not a directory: {path}')
|
||||||
|
os.makedirs(path, exist_ok=True)
|
||||||
|
self.shapes_states = os.path.join(path, 'shapes_states')
|
||||||
|
self.shapes_countries = os.path.join(path, 'shapes_countries')
|
||||||
|
self.shapes_filtered = os.path.join(path, 'shapes_filtered')
|
||||||
|
self.erfa_info = os.path.join(path, 'erfa-info.json')
|
||||||
|
self.chaostreff_info = os.path.join(path, 'chaostreff-info.json')
|
||||||
|
|
||||||
|
|
||||||
|
#BOUNDING_BOX = [(4.27775, 46.7482713), (19.2403594, 54.9833021)]
|
||||||
|
# --bbox 4.27775 46.7482713 19.2403594 54.9833021
|
||||||
|
|
||||||
|
|
||||||
ERFA_URL = 'https://doku.ccc.de/Spezial:Semantische_Suche/format%3Djson/limit%3D50/link%3Dall/headers%3Dshow/searchlabel%3DJSON/class%3Dsortable-20wikitable-20smwtable/sort%3D/order%3Dasc/offset%3D0/-5B-5BKategorie:Erfa-2DKreise-5D-5D-20-5B-5BChaostreff-2DActive::wahr-5D-5D/-3FChaostreff-2DCity/-3FChaostreff-2DPhysical-2DAddress/-3FChaostreff-2DPhysical-2DHousenumber/-3FChaostreff-2DPhysical-2DPostcode/-3FChaostreff-2DPhysical-2DCity/-3FChaostreff-2DCountry/mainlabel%3D/prettyprint%3Dtrue/unescape%3Dtrue'
|
ERFA_URL = 'https://doku.ccc.de/Spezial:Semantische_Suche/format%3Djson/limit%3D50/link%3Dall/headers%3Dshow/searchlabel%3DJSON/class%3Dsortable-20wikitable-20smwtable/sort%3D/order%3Dasc/offset%3D0/-5B-5BKategorie:Erfa-2DKreise-5D-5D-20-5B-5BChaostreff-2DActive::wahr-5D-5D/-3FChaostreff-2DCity/-3FChaostreff-2DPhysical-2DAddress/-3FChaostreff-2DPhysical-2DHousenumber/-3FChaostreff-2DPhysical-2DPostcode/-3FChaostreff-2DPhysical-2DCity/-3FChaostreff-2DCountry/mainlabel%3D/prettyprint%3Dtrue/unescape%3Dtrue'
|
||||||
|
|
||||||
CHAOSTREFF_URL = 'https://doku.ccc.de/Spezial:Semantische_Suche/format%3Djson/limit%3D50/link%3Dall/headers%3Dshow/searchlabel%3DJSON/class%3Dsortable-20wikitable-20smwtable/sort%3D/order%3Dasc/offset%3D0/-5B-5BKategorie:Chaostreffs-5D-5D-20-5B-5BChaostreff-2DActive::wahr-5D-5D/-3FChaostreff-2DCity/-3FChaostreff-2DPhysical-2DAddress/-3FChaostreff-2DPhysical-2DHousenumber/-3FChaostreff-2DPhysical-2DPostcode/-3FChaostreff-2DPhysical-2DCity/-3FChaostreff-2DCountry/mainlabel%3D/prettyprint%3Dtrue/unescape%3Dtrue'
|
CHAOSTREFF_URL = 'https://doku.ccc.de/Spezial:Semantische_Suche/format%3Djson/limit%3D50/link%3Dall/headers%3Dshow/searchlabel%3DJSON/class%3Dsortable-20wikitable-20smwtable/sort%3D/order%3Dasc/offset%3D0/-5B-5BKategorie:Chaostreffs-5D-5D-20-5B-5BChaostreff-2DActive::wahr-5D-5D/-3FChaostreff-2DCity/-3FChaostreff-2DPhysical-2DAddress/-3FChaostreff-2DPhysical-2DHousenumber/-3FChaostreff-2DPhysical-2DPostcode/-3FChaostreff-2DPhysical-2DCity/-3FChaostreff-2DCountry/mainlabel%3D/prettyprint%3Dtrue/unescape%3Dtrue'
|
||||||
|
|
||||||
def fetch_wikidata_states(target='shapes_states'):
|
|
||||||
sparql = SPARQLWrapper('https://query.wikidata.org/sparql')
|
def sparql_query(query):
|
||||||
sparql.setQuery('''
|
headers = {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
'User-Agent': USER_AGENT,
|
||||||
|
'Accept': 'application/sparql-results+json',
|
||||||
|
}
|
||||||
|
body = urllib.parse.urlencode({'query': query}).encode()
|
||||||
|
req = urllib.request.Request('https://query.wikidata.org/sparql', headers=headers, data=body)
|
||||||
|
with urllib.request.urlopen(req) as resp:
|
||||||
|
resultset = json.load(resp)
|
||||||
|
results = {}
|
||||||
|
for r in resultset.get('results', {}).get('bindings'):
|
||||||
|
basename = None
|
||||||
|
url = None
|
||||||
|
for k, v in r.items():
|
||||||
|
if k == 'item':
|
||||||
|
basename = os.path.basename(v['value'])
|
||||||
|
elif k == 'map':
|
||||||
|
url = v['value']
|
||||||
|
results[basename] = url
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_geoshapes(target, shape_urls):
|
||||||
|
os.makedirs(target, exist_ok=True)
|
||||||
|
for item, url in tqdm.tqdm(shape_urls.items()):
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(url) as resp:
|
||||||
|
with open(os.path.join(target, item + '.json'), 'wb') as f:
|
||||||
|
f.write(resp.read())
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_wikidata_states(target):
|
||||||
|
shape_urls = sparql_query('''
|
||||||
|
|
||||||
PREFIX wd: <http://www.wikidata.org/entity/>
|
PREFIX wd: <http://www.wikidata.org/entity/>
|
||||||
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
|
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
|
||||||
|
@ -30,20 +89,12 @@ SELECT DISTINCT ?item ?map WHERE {
|
||||||
wdt:P3896 ?map
|
wdt:P3896 ?map
|
||||||
}
|
}
|
||||||
''')
|
''')
|
||||||
sparql.setReturnFormat(JSON)
|
print('Retrieving state border shapes')
|
||||||
results = sparql.query().convert()
|
fetch_geoshapes(target, shape_urls)
|
||||||
|
|
||||||
shape_urls = {result['item']['value'].split('/')[-1]: result['map']['value'] for result in results["results"]["bindings"]}
|
|
||||||
|
|
||||||
os.makedirs(target, exist_ok=True)
|
def fetch_wikidata_countries(target):
|
||||||
for item, url in shape_urls.items():
|
shape_urls = sparql_query('''
|
||||||
with urllib.request.urlopen(url) as resp:
|
|
||||||
with open(os.path.join(target, item + '.json'), 'wb') as f:
|
|
||||||
f.write(resp.read())
|
|
||||||
|
|
||||||
def fetch_wikidata_countries(target='shapes_countries'):
|
|
||||||
sparql = SPARQLWrapper('https://query.wikidata.org/sparql')
|
|
||||||
sparql.setQuery('''
|
|
||||||
|
|
||||||
PREFIX wd: <http://www.wikidata.org/entity/>
|
PREFIX wd: <http://www.wikidata.org/entity/>
|
||||||
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
|
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
|
||||||
|
@ -60,25 +111,15 @@ SELECT DISTINCT ?item ?map WHERE {
|
||||||
FILTER (?euroclass = wd:Q46 || ?euroclass = wd:Q8932).
|
FILTER (?euroclass = wd:Q46 || ?euroclass = wd:Q8932).
|
||||||
}
|
}
|
||||||
''')
|
''')
|
||||||
sparql.setReturnFormat(JSON)
|
print('Retrieving country border shapes')
|
||||||
results = sparql.query().convert()
|
fetch_geoshapes(target, shape_urls)
|
||||||
|
|
||||||
shape_urls = {result['item']['value'].split('/')[-1]: result['map']['value'] for result in results["results"]["bindings"]}
|
|
||||||
|
|
||||||
os.makedirs(target, exist_ok=True)
|
def filter_boundingbox(source, target, bbox):
|
||||||
for item, url in shape_urls.items():
|
|
||||||
try:
|
|
||||||
with urllib.request.urlopen(url) as resp:
|
|
||||||
with open(os.path.join(target, item + '.json'), 'wb') as f:
|
|
||||||
f.write(resp.read())
|
|
||||||
except BaseException as e:
|
|
||||||
print(e)
|
|
||||||
print(url)
|
|
||||||
|
|
||||||
def filter_boundingbox(source='shapes_countries', target='shapes_filtered'):
|
|
||||||
files = os.listdir(source)
|
files = os.listdir(source)
|
||||||
os.makedirs(target, exist_ok=True)
|
os.makedirs(target, exist_ok=True)
|
||||||
for f in files:
|
print('Filtering countries outside the bounding box')
|
||||||
|
for f in tqdm.tqdm(files):
|
||||||
if not f.endswith('.json') or 'Q183.json' in f:
|
if not f.endswith('.json') or 'Q183.json' in f:
|
||||||
continue
|
continue
|
||||||
path = os.path.join(source, f)
|
path = os.path.join(source, f)
|
||||||
|
@ -91,8 +132,8 @@ def filter_boundingbox(source='shapes_countries', target='shapes_filtered'):
|
||||||
geo['coordinates'] = [geo['coordinates']]
|
geo['coordinates'] = [geo['coordinates']]
|
||||||
for poly in geo['coordinates']:
|
for poly in geo['coordinates']:
|
||||||
for point in poly[0]:
|
for point in poly[0]:
|
||||||
if point[0] >= BOUNDING_BOX[0][0] and point[1] >= BOUNDING_BOX[0][1] \
|
if point[0] >= bbox[0][0] and point[1] >= bbox[0][1] \
|
||||||
and point[0] <= BOUNDING_BOX[1][0] and point[1] <= BOUNDING_BOX[1][1]:
|
and point[0] <= bbox[1][0] and point[1] <= bbox[1][1]:
|
||||||
keep = True
|
keep = True
|
||||||
break
|
break
|
||||||
if keep:
|
if keep:
|
||||||
|
@ -102,18 +143,38 @@ def filter_boundingbox(source='shapes_countries', target='shapes_filtered'):
|
||||||
sf.write(shapedata)
|
sf.write(shapedata)
|
||||||
|
|
||||||
|
|
||||||
def address_lookup(erfa):
|
def address_lookup(name, erfa):
|
||||||
locator = Nominatim(user_agent='foobar')
|
locator = Nominatim(user_agent=USER_AGENT)
|
||||||
city = erfa['printouts']['Chaostreff-City'][0]
|
number = erfa['Chaostreff-Physical-Housenumber']
|
||||||
country = erfa['printouts']['Chaostreff-Country'][0]
|
street = erfa['Chaostreff-Physical-Address']
|
||||||
address = f'{city}, {country}'
|
zipcode = erfa['Chaostreff-Physical-Postcode']
|
||||||
response = locator.geocode(address)
|
acity = erfa['Chaostreff-Physical-City']
|
||||||
if response is None:
|
city = erfa['Chaostreff-City'][0]
|
||||||
return None
|
country = erfa['Chaostreff-Country'][0]
|
||||||
return response.longitude, response.latitude
|
|
||||||
|
formats = [
|
||||||
|
# Muttenz, Schweiz
|
||||||
|
f'{city}, {country}'
|
||||||
|
]
|
||||||
|
if zipcode and acity:
|
||||||
|
# 4132 Muttenz, Schweiz
|
||||||
|
formats.insert(0, f'{zipcode[0]} {acity[0]}, {country}')
|
||||||
|
if zipcode and acity and number and street:
|
||||||
|
# Birsfelderstrasse 6, 4132 Muttenz, Schweiz
|
||||||
|
formats.insert(0, f'{street[0]} {number[0]}, {zipcode[0]} {acity[0]}, {country}')
|
||||||
|
|
||||||
|
for fmt in formats:
|
||||||
|
response = locator.geocode(fmt)
|
||||||
|
if response is not None:
|
||||||
|
return response.longitude, response.latitude
|
||||||
|
|
||||||
|
print(f'No location found for {name}, tried the following address formats:')
|
||||||
|
for fmt in formats:
|
||||||
|
print(f' {fmt}')
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def fetch_erfas(target='erfa-info.json', url=ERFA_URL, bbox=None):
|
def fetch_erfas(target, url):
|
||||||
userpw = os.getenv('DOKU_CCC_DE_BASICAUTH')
|
userpw = os.getenv('DOKU_CCC_DE_BASICAUTH')
|
||||||
if userpw is None:
|
if userpw is None:
|
||||||
print('Please set environment variable DOKU_CCC_DE_BASICAUTH=username:password')
|
print('Please set environment variable DOKU_CCC_DE_BASICAUTH=username:password')
|
||||||
|
@ -123,44 +184,189 @@ def fetch_erfas(target='erfa-info.json', url=ERFA_URL, bbox=None):
|
||||||
req = urllib.request.Request(url, headers={'Authorization': f'Basic {auth}'})
|
req = urllib.request.Request(url, headers={'Authorization': f'Basic {auth}'})
|
||||||
with urllib.request.urlopen(req) as resp:
|
with urllib.request.urlopen(req) as resp:
|
||||||
erfadata = json.loads(resp.read().decode())
|
erfadata = json.loads(resp.read().decode())
|
||||||
for name, erfa in erfadata['results'].items():
|
print('Looking up addresses')
|
||||||
location = address_lookup(erfa)
|
for name, erfa in tqdm.tqdm(erfadata['results'].items()):
|
||||||
|
location = address_lookup(name, erfa['printouts'])
|
||||||
if location is None:
|
if location is None:
|
||||||
print(f'WARNING: No location for {name}')
|
print(f'WARNING: No location for {name}')
|
||||||
city = erfa['printouts']['Chaostreff-City'][0]
|
city = erfa['printouts']['Chaostreff-City'][0]
|
||||||
erfas[city] = location
|
erfas[city] = location
|
||||||
if len(bbox) == 0:
|
|
||||||
bbox.append(location)
|
|
||||||
bbox.append(location)
|
|
||||||
else:
|
|
||||||
bbox[0] = (min(bbox[0][0], location[0]), min(bbox[0][1], location[1]))
|
|
||||||
bbox[1] = (max(bbox[1][0], location[0]), max(bbox[1][1], location[1]))
|
|
||||||
with open(target, 'w') as f:
|
with open(target, 'w') as f:
|
||||||
json.dump(erfas, f)
|
json.dump(erfas, f)
|
||||||
|
|
||||||
def fetch_chaostreffs(target='chaostreff-info.json', bbox=None):
|
|
||||||
fetch_erfas(target=target, url=CHAOSTREFF_URL, bbox=bbox)
|
def compute_bbox(ns):
|
||||||
|
if ns.bbox is not None:
|
||||||
|
return [
|
||||||
|
(min(ns.bbox[0], ns.bbox[2]), min(ns.bbox[1], ns.bbox[3])),
|
||||||
|
(max(ns.bbox[0], ns.bbox[2]), max(ns.bbox[1], ns.bbox[3]))
|
||||||
|
]
|
||||||
|
|
||||||
|
print('Computing map bounding box')
|
||||||
|
bounds = []
|
||||||
|
for path in tqdm.tqdm([ns.cache_directory.erfa_info, ns.cache_directory.chaostreff_info]):
|
||||||
|
with open(path, 'r') as f:
|
||||||
|
erfadata = json.load(f)
|
||||||
|
for lon, lat in erfadata.values():
|
||||||
|
if len(bounds) == 0:
|
||||||
|
bounds.append(lon)
|
||||||
|
bounds.append(lat)
|
||||||
|
bounds.append(lon)
|
||||||
|
bounds.append(lat)
|
||||||
|
else:
|
||||||
|
bounds[0] = min(bounds[0], lon)
|
||||||
|
bounds[1] = min(bounds[1], lat)
|
||||||
|
bounds[2] = max(bounds[2], lon)
|
||||||
|
bounds[3] = max(bounds[3], lat)
|
||||||
|
return [
|
||||||
|
(bounds[0] - ns.bbox_margin, bounds[1] - ns.bbox_margin),
|
||||||
|
(bounds[2] + ns.bbox_margin, bounds[3] + ns.bbox_margin)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def create_svg(source_states='shapes_states', source_countries='shapes_filtered', source_erfa='erfa-info.json', source_ct='chaostreff-info.json'):
|
class BoundingBox:
|
||||||
transformer = pyproj.Transformer.from_crs('epsg:4326', 'epsg:4258')
|
|
||||||
scalex = 130
|
def __init__(self, left, top, right, bottom):
|
||||||
scaley = 200
|
self.left = left
|
||||||
blt = transformer.transform(*BOUNDING_BOX[0])
|
self.top = top
|
||||||
trt = transformer.transform(*BOUNDING_BOX[1])
|
self.right = right
|
||||||
jtm_bounding_box = [
|
self.bottom = bottom
|
||||||
|
|
||||||
|
def __contains__(self, other):
|
||||||
|
if isinstance(other, BoundingBox):
|
||||||
|
if other.right < self.left or other.left > self.right:
|
||||||
|
return False
|
||||||
|
if other.bottom < self.top or other.top > self.bottom:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
elif isinstance(other, tuple) or isinstance(other, list):
|
||||||
|
if len(other) != 2:
|
||||||
|
raise TypeError()
|
||||||
|
if self.left > other[0] or self.right < other[0]:
|
||||||
|
return False
|
||||||
|
if self.top > other[1] or self.bottom < other[1]:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
raise TypeError()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def width(self):
|
||||||
|
return self.right - self.left
|
||||||
|
|
||||||
|
@property
|
||||||
|
def height(self):
|
||||||
|
return self.bottom - self.top
|
||||||
|
|
||||||
|
def with_margin(self, margin):
|
||||||
|
return BoundingBox(self.left - margin, self.top - margin, self.right + margin, self.bottom + margin)
|
||||||
|
|
||||||
|
|
||||||
|
def optimize_text_layout(ns, erfas, chaostreffs, size, svg):
|
||||||
|
font = ImageFont.truetype(ns.font, ns.font_size)
|
||||||
|
pil = ImageDraw(Image.new('P', size))
|
||||||
|
|
||||||
|
lboxes = {}
|
||||||
|
rboxes = {}
|
||||||
|
for city, location in erfas.items():
|
||||||
|
lbox = pil.textbbox((location[0] + ns.font_distance, location[1] - ns.font_size/2), city, font=font, anchor='lt')
|
||||||
|
lbox = BoundingBox(*lbox)
|
||||||
|
rbox = pil.textbbox((location[0] - ns.font_distance, location[1] - ns.font_size/2), city, font=font, anchor='rt')
|
||||||
|
rbox = BoundingBox(*rbox)
|
||||||
|
lboxes[city] = lbox
|
||||||
|
rboxes[city] = rbox
|
||||||
|
|
||||||
|
if ns.debug:
|
||||||
|
dr1 = etree.Element('rect', x=str(lbox.left), y=str(lbox.top), width=str(lbox.width), height=str(lbox.height))
|
||||||
|
dr1.set('class', 'debugleft')
|
||||||
|
dr2 = etree.Element('rect', x=str(rbox.left), y=str(rbox.top), width=str(rbox.width), height=str(rbox.height))
|
||||||
|
dr2.set('class', 'debugright')
|
||||||
|
svg.append(dr1)
|
||||||
|
svg.append(dr2)
|
||||||
|
|
||||||
|
|
||||||
|
unfinished = {c for c in erfas.keys()}
|
||||||
|
finished = {}
|
||||||
|
for city in list(unfinished):
|
||||||
|
margin_left = lboxes[city].with_margin(ns.dotsize_erfa)
|
||||||
|
i_left = sum([1 for c, b in lboxes.items() if c != city and b in margin_left])
|
||||||
|
i_left += sum([1 for c, b in rboxes.items() if c != city and b in margin_left])
|
||||||
|
i_left += sum([0.5 for c, loc in chaostreffs.items() if loc in margin_left])
|
||||||
|
margin_right = rboxes[city].with_margin(ns.dotsize_erfa)
|
||||||
|
i_right = sum([1 for c, b in lboxes.items() if c != city and b in margin_right])
|
||||||
|
i_right += sum([1 for c, b in rboxes.items() if c != city and b in margin_right])
|
||||||
|
i_right += sum([0.5 for c, loc in chaostreffs.items() if loc in margin_right])
|
||||||
|
|
||||||
|
if i_right == 0 and i_left > 0:
|
||||||
|
finished[city] = rboxes[city]
|
||||||
|
unfinished.discard(city)
|
||||||
|
elif i_left == 0:
|
||||||
|
if lboxes[city].left > size[0] * 0.8:
|
||||||
|
finished[city] = rboxes[city]
|
||||||
|
else:
|
||||||
|
finished[city] = lboxes[city]
|
||||||
|
unfinished.discard(city)
|
||||||
|
|
||||||
|
for a in list(unfinished):
|
||||||
|
if a not in unfinished:
|
||||||
|
continue
|
||||||
|
mla = lboxes[a].with_margin(ns.dotsize_erfa)
|
||||||
|
mra = rboxes[a].with_margin(ns.dotsize_erfa)
|
||||||
|
for b in list(unfinished.difference({a})):
|
||||||
|
if b not in unfinished:
|
||||||
|
continue
|
||||||
|
mlb = lboxes[b]
|
||||||
|
mrb = rboxes[b]
|
||||||
|
if mla not in mlb and mla not in mlb and mra not in mlb and mra not in mrb:
|
||||||
|
continue
|
||||||
|
if mra in mlb:
|
||||||
|
finished[a] = lboxes[a]
|
||||||
|
finished[b] = rboxes[b]
|
||||||
|
unfinished.discard(a)
|
||||||
|
unfinished.discard(b)
|
||||||
|
elif mla in mrb:
|
||||||
|
finished[a] = rboxes[a]
|
||||||
|
finished[b] = lboxes[b]
|
||||||
|
unfinished.discard(a)
|
||||||
|
unfinished.discard(b)
|
||||||
|
|
||||||
|
for city in list(unfinished):
|
||||||
|
margin_left = lboxes[city].with_margin(ns.dotsize_erfa)
|
||||||
|
margin_right = rboxes[city].with_margin(ns.dotsize_erfa)
|
||||||
|
i_left = sum([1 for c, b in finished.items() if c != city and b in margin_left])
|
||||||
|
i_left += sum([0.5 for c, loc in chaostreffs.items() if loc in margin_left])
|
||||||
|
i_right = sum([1 for c, b in finished.items() if c != city and b in margin_right])
|
||||||
|
i_right += sum([0.5 for c, loc in chaostreffs.items() if loc in margin_right])
|
||||||
|
if i_left <= i_right:
|
||||||
|
finished[city] = lboxes[city]
|
||||||
|
else:
|
||||||
|
finished[city] = rboxes[city]
|
||||||
|
unfinished.discard(city)
|
||||||
|
|
||||||
|
return finished
|
||||||
|
|
||||||
|
|
||||||
|
def create_svg(ns, bbox):
|
||||||
|
print('Creating SVG image')
|
||||||
|
|
||||||
|
# Convert from WGS84 lon, lat to chosen projection
|
||||||
|
transformer = pyproj.Transformer.from_crs('epsg:4326', ns.projection)
|
||||||
|
scalex = ns.scale_x
|
||||||
|
scaley = ns.scale_y
|
||||||
|
blt = transformer.transform(*bbox[0])
|
||||||
|
trt = transformer.transform(*bbox[1])
|
||||||
|
trans_bounding_box = [
|
||||||
(scalex*blt[0], scaley*trt[1]),
|
(scalex*blt[0], scaley*trt[1]),
|
||||||
(scalex*trt[0], scaley*blt[1])
|
(scalex*trt[0], scaley*blt[1])
|
||||||
]
|
]
|
||||||
origin = jtm_bounding_box[0]
|
origin = trans_bounding_box[0]
|
||||||
svg_box = (jtm_bounding_box[1][0] - origin[0], origin[1] - jtm_bounding_box[1][1])
|
svg_box = (trans_bounding_box[1][0] - origin[0], origin[1] - trans_bounding_box[1][1])
|
||||||
|
|
||||||
shapes_states = []
|
shapes_states = []
|
||||||
files = os.listdir(source_states)
|
files = os.listdir(ns.cache_directory.shapes_states)
|
||||||
for f in files:
|
for f in files:
|
||||||
if not f.endswith('.json'):
|
if not f.endswith('.json'):
|
||||||
continue
|
continue
|
||||||
path = os.path.join(source_states, f)
|
path = os.path.join(ns.cache_directory.shapes_states, f)
|
||||||
with open(path, 'r') as sf:
|
with open(path, 'r') as sf:
|
||||||
shapedata = sf.read()
|
shapedata = sf.read()
|
||||||
shape = json.loads(shapedata)
|
shape = json.loads(shapedata)
|
||||||
|
@ -175,11 +381,11 @@ def create_svg(source_states='shapes_states', source_countries='shapes_filtered'
|
||||||
shapes_states.append(ts)
|
shapes_states.append(ts)
|
||||||
|
|
||||||
shapes_countries = []
|
shapes_countries = []
|
||||||
files = os.listdir(source_countries)
|
files = os.listdir(ns.cache_directory.shapes_filtered)
|
||||||
for f in files:
|
for f in files:
|
||||||
if not f.endswith('.json'):
|
if not f.endswith('.json'):
|
||||||
continue
|
continue
|
||||||
path = os.path.join(source_countries, f)
|
path = os.path.join(ns.cache_directory.shapes_filtered, f)
|
||||||
with open(path, 'r') as sf:
|
with open(path, 'r') as sf:
|
||||||
shapedata = sf.read()
|
shapedata = sf.read()
|
||||||
shape = json.loads(shapedata)
|
shape = json.loads(shapedata)
|
||||||
|
@ -194,7 +400,7 @@ def create_svg(source_states='shapes_states', source_countries='shapes_filtered'
|
||||||
shapes_countries.append(ts)
|
shapes_countries.append(ts)
|
||||||
|
|
||||||
chaostreffs = {}
|
chaostreffs = {}
|
||||||
with open(source_ct, 'r') as f:
|
with open(ns.cache_directory.chaostreff_info, 'r') as f:
|
||||||
ctdata = json.load(f)
|
ctdata = json.load(f)
|
||||||
for city, location in ctdata.items():
|
for city, location in ctdata.items():
|
||||||
if location is None:
|
if location is None:
|
||||||
|
@ -203,7 +409,7 @@ def create_svg(source_states='shapes_states', source_countries='shapes_filtered'
|
||||||
chaostreffs[city] = (xt*scalex - origin[0], origin[1] - yt*scaley)
|
chaostreffs[city] = (xt*scalex - origin[0], origin[1] - yt*scaley)
|
||||||
|
|
||||||
erfas = {}
|
erfas = {}
|
||||||
with open(source_erfa, 'r') as f:
|
with open(ns.cache_directory.erfa_info, 'r') as f:
|
||||||
ctdata = json.load(f)
|
ctdata = json.load(f)
|
||||||
for city, location in ctdata.items():
|
for city, location in ctdata.items():
|
||||||
if location is None:
|
if location is None:
|
||||||
|
@ -220,65 +426,115 @@ def create_svg(source_states='shapes_states', source_countries='shapes_filtered'
|
||||||
rectbox[3] = max(lat, rectbox[3])
|
rectbox[3] = max(lat, rectbox[3])
|
||||||
|
|
||||||
|
|
||||||
SVG = f'''
|
svg = etree.Element('svg',
|
||||||
<svg viewBox="0 0 {svg_box[0]} {svg_box[1]}" width="{svg_box[0]}" height="{svg_box[1]}"
|
xmlns='http://www.w3.org/2000/svg',
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
viewBox=f'0 0 {svg_box[0]} {svg_box[1]}',
|
||||||
|
width=str(svg_box[0]), height=str(svg_box[1]))
|
||||||
|
|
||||||
<rect x="{rectbox[0]}" y="{rectbox[1]}" width="{rectbox[3]-rectbox[1]}" height="{rectbox[2]-rectbox[0]}" stroke="none" fill="#759eb5" />
|
defs = etree.Element('defs')
|
||||||
'''
|
style = etree.Element('style', type='text/css')
|
||||||
|
style.text = f'@import url({ns.stylesheet})'
|
||||||
|
defs.append(style)
|
||||||
|
svg.append(defs)
|
||||||
|
|
||||||
|
bg = etree.Element('rect',
|
||||||
|
x=str(rectbox[0]),
|
||||||
|
y=str(rectbox[1]),
|
||||||
|
width=str(rectbox[3]-rectbox[1]),
|
||||||
|
height=str(rectbox[2]-rectbox[0]))
|
||||||
|
bg.set('class', 'background')
|
||||||
|
svg.append(bg)
|
||||||
|
|
||||||
|
for shape in shapes_countries:
|
||||||
|
points = ' '.join([f'{lon},{lat}' for lon, lat in shape])
|
||||||
|
poly = etree.Element('polygon', points=points)
|
||||||
|
poly.set('class', 'country')
|
||||||
|
svg.append(poly)
|
||||||
|
|
||||||
# Render shortest shapes last s.t. Berlin, Hamburg and Bremen are rendered on top of their surrounding states
|
# Render shortest shapes last s.t. Berlin, Hamburg and Bremen are rendered on top of their surrounding states
|
||||||
for shape in sorted(shapes_states, key=lambda x: -sum(len(s) for s in x)):
|
for shape in sorted(shapes_states, key=lambda x: -sum(len(s) for s in x)):
|
||||||
points = ' '.join([f'{lon},{lat}' for lon, lat in shape])
|
points = ' '.join([f'{lon},{lat}' for lon, lat in shape])
|
||||||
SVG += f'''
|
poly = etree.Element('polygon', points=points)
|
||||||
<polygon points="{points}" fill="#ffffff" stroke="#c3c3c3" stroke-width="3" />
|
poly.set('class', 'state')
|
||||||
'''
|
svg.append(poly)
|
||||||
|
|
||||||
for shape in shapes_countries:
|
|
||||||
points = ' '.join([f'{lon},{lat}' for lon, lat in shape])
|
|
||||||
SVG += f'''
|
|
||||||
<polygon points="{points}" fill="#c3c3c3" stroke="#ffffff" stroke-width="3" />
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
for city, location in erfas.items():
|
for city, location in erfas.items():
|
||||||
SVG += f'''
|
circle = etree.Element('circle', cx=str(location[0]), cy=str(location[1]), r=str(ns.dotsize_erfa))
|
||||||
<circle cx="{location[0]}" cy="{location[1]}" r="15" fill="#f47e1e" stroke="#ffffff" stroke-width="3" />
|
circle.set('class', 'erfa')
|
||||||
<!--<rect x="{location[0]+25}" y="{location[1]-15}" width="{len(city)*15}" height="30" stroke="green" stroke-width="1" fill="none" />
|
svg.append(circle)
|
||||||
<rect x="{location[0]-25-len(city)*15}" y="{location[1]-15}" width="{len(city)*15}" height="30" stroke="red" stroke-width="1" fill="none" />-->
|
|
||||||
'''
|
|
||||||
|
|
||||||
for city, location in chaostreffs.items():
|
for city, location in chaostreffs.items():
|
||||||
SVG += f'''
|
circle = etree.Element('circle', cx=str(location[0]), cy=str(location[1]), r=str(ns.dotsize_treff))
|
||||||
<circle cx="{location[0]}" cy="{location[1]}" r="8" fill="#f47e1e" stroke="#ffffff" stroke-width="3" />
|
circle.set('class', 'chaostreff')
|
||||||
'''
|
svg.append(circle)
|
||||||
|
|
||||||
for city, location in erfas.items():
|
|
||||||
weight_right = sum([1 for x, y in erfas.values() if x > location[0] + 25 and x < location[0] + 25 + len(city)*15 and y > location[1] - 15 and y < location[1] + 25])
|
|
||||||
weight_left = sum([1 for x, y in erfas.values() if x < location[0] - 25 and x > location[0] - 25 - len(city)*15 and y > location[1] - 15 and y < location[1] + 25])
|
|
||||||
if weight_right > weight_left:
|
|
||||||
SVG += f'''
|
|
||||||
<text x="{location[0]-25}" y="{location[1]+7.5}" text-anchor="end" style="font-family: Liberation Sans; font-size: 25; font-weight: bold;">{city}</text>
|
|
||||||
'''
|
|
||||||
else:
|
|
||||||
SVG += f'''
|
|
||||||
<text x="{location[0]+25}" y="{location[1]+7.5}" style="font-family: Liberation Sans; font-size: 25; font-weight: bold;">{city}</text>
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
SVG += '</svg>'
|
print('Layouting labels')
|
||||||
|
texts = optimize_text_layout(ns, erfas, chaostreffs, (int(svg_box[0]), int(svg_box[1])), svg)
|
||||||
|
for city, box in texts.items():
|
||||||
|
text = etree.Element('text', x=str(box.left), y=str(box.top))
|
||||||
|
text.set('alignment-baseline', 'hanging')
|
||||||
|
text.set('class', 'erfalabel')
|
||||||
|
text.text = city
|
||||||
|
svg.append(text)
|
||||||
|
|
||||||
with open('map.svg', 'w') as mapfile:
|
print('Done, writing SVG')
|
||||||
mapfile.write(SVG)
|
with open('map.svg', 'wb') as mapfile:
|
||||||
|
root = etree.ElementTree(svg)
|
||||||
|
root.write(mapfile)
|
||||||
|
|
||||||
|
print('Done, writing PNG')
|
||||||
|
cairosvg.svg2png(url='map.svg', write_to='map.png')
|
||||||
|
print('Done')
|
||||||
|
|
||||||
|
|
||||||
bbox = []
|
|
||||||
fetch_erfas(bbox=bbox)
|
|
||||||
#fetch_chaostreffs(bbox=bbox)
|
|
||||||
#print(bbox)
|
|
||||||
#fetch_wikidata_states()
|
|
||||||
#fetch_wikidata_countries()
|
|
||||||
filter_boundingbox()
|
|
||||||
create_svg()
|
|
||||||
|
|
||||||
# Q347 P361 Q46
|
def main():
|
||||||
|
ap = argparse.ArgumentParser(sys.argv[0])
|
||||||
|
ap.add_argument('--cache-directory', type=CachePaths, default='cache', help='Path to the cache directory')
|
||||||
|
ap.add_argument('--update-borders', action='store_true', default=False, help='Update country borders from Wikidata')
|
||||||
|
ap.add_argument('--update-erfalist', action='store_true', default=False, help='Update Erfa/Chaostreff list from doku.ccc.de')
|
||||||
|
ap.add_argument('--bbox', type=float, nargs=4, default=None, help='Override map bounding box with <lon> <lat> <lon> <lat>')
|
||||||
|
ap.add_argument('--bbox-margin', type=float, default=0.3, help='Margin around the inferred bounding box. Ignored with --bbox')
|
||||||
|
ap.add_argument('--stylesheet', type=str, default='style/erfamap.css', help='Stylesheet for the generated SVG')
|
||||||
|
ap.add_argument('--font', type=str, default='style/concertone-regular.ttf', help='Name of the font used in the stylesheet.')
|
||||||
|
ap.add_argument('--font-size', type=int, default=30, help='Size of the font used in the stylesheet.')
|
||||||
|
ap.add_argument('--font-distance', type=int, default=25, help='Distance of labels from their dots center')
|
||||||
|
ap.add_argument('--dotsize-erfa', type=float, default=13, help='Radius of Erfa dots')
|
||||||
|
ap.add_argument('--dotsize-treff', type=float, default=8, help='Radius of Chaostreff dots')
|
||||||
|
ap.add_argument('--projection', type=str, default='epsg:4258', help='Map projection to convert the WGS84 coordinates to')
|
||||||
|
ap.add_argument('--scale-x', type=float, default=130, help='X axis scale to apply after projecting')
|
||||||
|
ap.add_argument('--scale-y', type=float, default=200, help='Y axis scale to apply after projecting')
|
||||||
|
ap.add_argument('--debug', action='store_true', default=False, help='Add debug information to the produced SVG')
|
||||||
|
|
||||||
|
ns = ap.parse_args(sys.argv[1:])
|
||||||
|
|
||||||
|
if ns.update_borders or not os.path.isdir(ns.cache_directory.shapes_countries):
|
||||||
|
if os.path.isdir(ns.cache_directory.shapes_countries):
|
||||||
|
shutil.rmtree(ns.cache_directory.shapes_countries)
|
||||||
|
fetch_wikidata_countries(target=ns.cache_directory.shapes_countries)
|
||||||
|
|
||||||
|
if ns.update_borders or not os.path.isdir(ns.cache_directory.shapes_states):
|
||||||
|
if os.path.isdir(ns.cache_directory.shapes_states):
|
||||||
|
shutil.rmtree(ns.cache_directory.shapes_states)
|
||||||
|
fetch_wikidata_states(target=ns.cache_directory.shapes_states)
|
||||||
|
|
||||||
|
if ns.update_erfalist or not os.path.isfile(ns.cache_directory.erfa_info):
|
||||||
|
if os.path.exists(ns.cache_directory.erfa_info):
|
||||||
|
os.unlink(ns.cache_directory.erfa_info)
|
||||||
|
fetch_erfas(target=ns.cache_directory.erfa_info, url=ERFA_URL)
|
||||||
|
|
||||||
|
if ns.update_erfalist or not os.path.isfile(ns.cache_directory.chaostreff_info):
|
||||||
|
if os.path.exists(ns.cache_directory.chaostreff_info):
|
||||||
|
os.unlink(ns.cache_directory.chaostreff_info)
|
||||||
|
fetch_erfas(target=ns.cache_directory.chaostreff_info, url=CHAOSTREFF_URL)
|
||||||
|
|
||||||
|
bbox = compute_bbox(ns)
|
||||||
|
|
||||||
|
filter_boundingbox(ns.cache_directory.shapes_countries, ns.cache_directory.shapes_filtered, bbox)
|
||||||
|
|
||||||
|
create_svg(ns, bbox)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
BIN
map.png
Normal file
BIN
map.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 396 KiB |
603
map.svg
603
map.svg
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
6
requirements.txt
Normal file
6
requirements.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
lxml
|
||||||
|
pyproj
|
||||||
|
geopy
|
||||||
|
cairosvg
|
||||||
|
tqdm
|
||||||
|
Pillow
|
BIN
style/concertone-regular.ttf
Normal file
BIN
style/concertone-regular.ttf
Normal file
Binary file not shown.
45
style/erfamap.css
Normal file
45
style/erfamap.css
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
|
||||||
|
rect.background {
|
||||||
|
fill: #759eb5;
|
||||||
|
stroke: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
polygon.country {
|
||||||
|
fill: #c3c3c3;
|
||||||
|
stroke: #ffffff;
|
||||||
|
stroke-width: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
polygon.state {
|
||||||
|
fill: #ffffff;
|
||||||
|
stroke: #c3c3c3;
|
||||||
|
stroke-width: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
circle.erfa, circle.chaostreff {
|
||||||
|
fill: #f47e1e;
|
||||||
|
stroke: #ffffff;
|
||||||
|
stroke-width: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'concertone';
|
||||||
|
src: url('./concertone-regular.ttf');
|
||||||
|
}
|
||||||
|
|
||||||
|
text.erfalabel {
|
||||||
|
font-family: concertone;
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect.debugleft {
|
||||||
|
stroke: red;
|
||||||
|
stroke-width: 1;
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect.debugright {
|
||||||
|
stroke: green;
|
||||||
|
stroke-width: 1;
|
||||||
|
fill: none;
|
||||||
|
}
|
Loading…
Reference in a new issue