Package: prettymaps
prettymapsA Python package to draw maps with customizable styles fromOpenStreetMapdata. Created using theosmnx,matplotlib,shapelyandvsketchpackages.This work islicensedunder a GNU Affero General Public License v3.0 (you can make commercial use, distribute and modify this project, but mustdisclosethe source code with the license and copyright notice)InstallationInstall using withpip:pip install prettymapsGoogle Colab DemoNote about crediting and NFTs:Please keep the printed message on the figures crediting my repository and OpenStreetMap (mandatory by their license).I am personallyagainstNFTs for theirenvironmental impact, the fact that they're agiant money-laundering pyramid schemeand the structural incentives they create fortheftin the open source and generative art communities.I do not authorize in any way this project to be used for selling NFTs, although I cannot legally enforce it.Respect the creator.TheAeternaCivitasandgeoartnftprojects have used this work to sell NFTs and refused to credit it. See how they reacted after being exposed:AeternaCivitas,geoartnft.I have closed my other generative art projects on Github and won't be sharing new ones as open source to protect me from the NFT community.As seen onHacker News:prettymaps subredditTutorialPlotting with prettymaps is very simple. Run:prettymaps.plot(your_query)your_querycan be:An address (Example: "Porto Alegre"),Latitude / Longitude coordinates (Example: (-30.0324999, -51.2303767))A custom boundary in GeoDataFrame formatimportprettymapsplot=prettymaps.plot('Stad van de Zon, Heerhugowaard, Netherlands')You can also choose from different "presets" (parameter combinations saved in JSON files)See below an example using the "minimal" presetplot=prettymaps.plot('Stad van de Zon, Heerhugowaard, Netherlands',preset='minimal')Runprettymaps.presets()to list all available presets:presetparams0barcelona{'layers': {'perimeter': {'circle': False}, 's...1barcelona-plotter{'layers': {'streets': {'width': {'primary': 5...2cb-bf-f{'layers': {'streets': {'width': {'trunk': 6, ...3default{'layers': {'perimeter': {}, 'streets': {'widt...4heerhugowaard{'layers': {'perimeter': {}, 'streets': {'widt...5macao{'layers': {'perimeter': {}, 'streets': {'cust...6minimal{'layers': {'perimeter': {}, 'streets': {'widt...7tijuca{'layers': {'perimeter': {}, 'streets': {'widt...To examine a specific preset, run:prettymaps.preset('default')layersstylecircleradiusperimeter{}fill: falselw: 0zorder: 0null...500...streetswidth:cycleway: 3.5footway: 1motorway: 5pedestrian: 2primary: 4.5residential: 3secondary: 4service: 2tertiary: 3.5trunk: 5unclassified: 2alpha: 1ec: '#475657'fc: '#2F3737'lw: 0zorder: 4buildingtags:building: truelanduse: constructionec: '#2F3737'lw: 0.5palette:- '#433633'- '#FF5E5B'zorder: 5watertags:natural:- water- bayec: '#2F3737'fc: '#a8e1e6'hatch: ooo...hatch_c: '#9bc3d4'lw: 1zorder: 3foresttags:landuse: forestec: '#2F3737'fc: '#64B96A'lw: 1zorder: 2greentags:landuse:- grass- orchardleisure: parknatural:- island- woodec: '#2F3737'fc: '#8BB174'hatch: ooo...hatch_c: '#A7C497'lw: 1zorder: 1beachtags:natural: beachec: '#2F3737'fc: '#FCE19C'hatch: ooo...hatch_c: '#d4d196'lw: 1zorder: 3parkingtags:amenity: parkinghighway: pedestrianman_made: pierec: '#2F3737'fc: '#F2F4CB'lw: 1zorder: 3background.nan...fc: '#F2F4CB'zorder: -1Insted of using the default configuration you can customize several parameters. The most important are:layers: A dictionary of OpenStreetMap layers to fetch.Keys: layer names (arbitrary)Values: dicts representing OpenStreetMap queriesstyle: Matplotlib style parametersKeys: layer names (the same as before)Values: dicts representing Matplotlib style parametersplot=prettymaps.plot(# Your query. Example: "Porto Alegre" or (-30.0324999, -51.2303767) (GPS coords)your_query,# Dict of OpenStreetMap Layers to plot. Example:# {'building': {'tags': {'building': True}}, 'water': {'tags': {'natural': 'water'}}}# Check the /presets folder for more exampleslayers,# Dict of style parameters for matplotlib. Example:# {'building': {'palette': ['#f00','#0f0','#00f'], 'edge_color': '#333'}}style,# Preset to load. Options include:# ['default', 'minimal', 'macao', 'tijuca']preset,# Save current parameters to a preset file.# Example: "my-preset" will save to "presets/my-preset.json"save_preset,# Whether to update loaded preset with additional provided parameters. Booleanupdate_preset,# Plot with circular boundary. Booleancircle,# Plot area radius. Floatradius,# Dilate the boundary by this amount. Floatdilate)plotis a python dataclass containing:@dataclassclassPlot:# A dictionary of GeoDataFrames (one for each plot layer)geodataframes:Dict[str,gp.GeoDataFrame]# A matplotlib figurefig:matplotlib.figure.Figure# A matplotlib axis objectax:matplotlib.axes.AxesHere's an example of running prettymaps.plot() with customized parameters:plot=prettymaps.plot('Praça Ferreira do Amaral, Macau',circle=True,radius=1100,layers={"green":{"tags":{"landuse":"grass","natural":["island","wood"],"leisure":"park"}},"forest":{"tags":{"landuse":"forest"}},"water":{"tags":{"natural":["water","bay"]}},"parking":{"tags":{"amenity":"parking","highway":"pedestrian","man_made":"pier"}},"streets":{"width":{"motorway":5,"trunk":5,"primary":4.5,"secondary":4,"tertiary":3.5,"residential":3,}},"building":{"tags":{"building":True},},},style={"background":{"fc":"#F2F4CB","ec":"#dadbc1","hatch":"ooo...",},"perimeter":{"fc":"#F2F4CB","ec":"#dadbc1","lw":0,"hatch":"ooo...",},"green":{"fc":"#D0F1BF","ec":"#2F3737","lw":1,},"forest":{"fc":"#64B96A","ec":"#2F3737","lw":1,},"water":{"fc":"#a1e3ff","ec":"#2F3737","hatch":"ooo...","hatch_c":"#85c9e6","lw":1,},"parking":{"fc":"#F2F4CB","ec":"#2F3737","lw":1,},"streets":{"fc":"#2F3737","ec":"#475657","alpha":1,"lw":0,},"building":{"palette":["#FFC857","#E9724C","#C5283D"],"ec":"#2F3737","lw":0.5,}})In order to plot an entire region and not just a rectangular or circular area, setradius=Falseplot=prettymaps.plot('Bom Fim, Porto Alegre, Brasil',radius=False,)You can access layers's GeoDataFrames directly like this:# Run prettymaps in show = False mode (we're only interested in obtaining the GeoDataFrames)plot=prettymaps.plot('Centro Histórico, Porto Alegre',show=False)plot.geodataframes['building']addr:housenumberaddr:streetamenityoperatorwebsitegeometryaddr:postcodenameofficeopening_hours...contact:phonebuspublic_transportsource:namegovernmentwaysname:frtypebuilding:partarchitectelement_typeosmidnode2407915698820Rua Washington LuizNaNNaNNaNPOINT (-51.23212 -30.03670)90010-460NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNway126665330387Rua dos Andradasplace_of_worshipNaNNaNPOLYGON ((-51.23518 -30.03275, -51.23512 -30.0...90020-002Igreja Nossa Senhora das DoresNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN1266653311001Rua dos AndradasNaNNaNhttp://www.ruadapraiashopping.com.brPOLYGON ((-51.23167 -30.03066, -51.23160 -30.0...90020-015Rua da Praia ShoppingNaNMo-Fr 09:00-21:00; Sa 08:00-20:00...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN1291769901020Rua 7 de SetembroNaNNaNhttp://www.memorial.rs.gov.brPOLYGON ((-51.23117 -30.02891, -51.23120 -30.0...90010-191Memorial do Rio Grande do SulNaNTu-Sa 10:00-18:00...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN129176991NaNPraça da AlfândegaNaNNaNhttp://www.margs.rs.gov.brPOLYGON ((-51.23153 -30.02914, -51.23156 -30.0...90010-150Museu de Arte do Rio Grande do SulNaNTu-Su 10:00-19:00...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN.....................................................................relation6760281NaNNaNNaNNaNNaNPOLYGON ((-51.23238 -30.03337, -51.23223 -30.0...NaNNaNNaNNaN...NaNNaNNaNNaNNaN[457506887, 457506886]NaNmultipolygonNaNNaN6760282NaNNaNNaNNaNNaNPOLYGON ((-51.23203 -30.03340, -51.23203 -30.0...NaNAtheneu Espírita Cruzeiro do SulNaNNaN...NaNNaNNaNNaNNaN[457506875, 457506889, 457506888]NaNmultipolygonNaNNaN6760283NaNNaNNaNNaNNaNPOLYGON ((-51.23284 -30.03367, -51.23288 -30.0...NaNPalacete ChavesNaNNaN...NaNNaNNaNNaNNaN[457506897, 457506896]NaNmultipolygonNaNTheodor Wiederspahn6760284NaNNaNNaNNaNNaNPOLYGON ((-51.23499 -30.03412, -51.23498 -30.0...NaNNaNNaNNaN...NaNNaNNaNNaNNaN[457506910, 457506913]NaNmultipolygonNaNNaN143935261044Rua Siqueira CamposNaNNaNhttps://www.sefaz.rs.gov.brPOLYGON ((-51.23125 -30.02813, -51.23128 -30.0...NaNSecretaria Estadual da FazendaNaNNaN...NaNNaNNaNNaNNaN[236213286, 1081974882]NaNmultipolygonNaNNaN2423 rows × 105 columnsSearch a building by name and display it:plot.geodataframes['building'][plot.geodataframes['building'].name=='Catedral Metropolitana Nossa Senhora Mãe de Deus'].geometry[0]Plot mosaic of building footprintsimportnumpyasnpimportosmnxasoxfrommatplotlibimportpyplotaspltfrommatplotlib.font_managerimportFontProperties# Run prettymaps in show = False mode (we're only interested in obtaining the GeoDataFrames)plot=prettymaps.plot('Porto Alegre',show=False)# Get list of buildings from plot's geodataframes dictbuildings=plot.geodataframes['building']# Project from lat / longbuildings=ox.project_gdf(buildings)buildings=[bforbinbuildings.geometryifb.area>0]# Draw Matplotlib mosaic of n x n building footprintsn=6fig,axes=plt.subplots(n,n,figsize=(7,6))# Set background colorfig.patch.set_facecolor('#5cc0eb')# Figure titlefig.suptitle('Buildings of Porto Alegre',size=25,color='#fff',fontproperties=FontProperties(fname='../assets/PermanentMarker-Regular.ttf'))# Draw each building footprint on a separate axisforax,buildinginzip(np.concatenate(axes),buildings):ax.plot(*building.exterior.xy,c='#ffffff')ax.autoscale();ax.axis('off');ax.axis('equal')Access plot.ax or plot.fig to add new elements to the matplotlib plot:frommatplotlib.font_managerimportFontPropertiesplot=prettymaps.plot((41.39491,2.17557),preset='barcelona',)# Change background colorplot.fig.patch.set_facecolor('#F2F4CB')# Add titleplot.ax.set_title('Barcelona',fontproperties=FontProperties(fname='../assets/PermanentMarker-Regular.ttf',size=50))plt.show()Useplottermode to export a pen plotter-compatible SVG (thanks to abey79's amazingvsketchlibrary)plot=prettymaps.plot((41.39491,2.17557),mode='plotter',layers=dict(perimeter={}),preset='barcelona-plotter',scale_x=.6,scale_y=-.6,)Some other examplesplot=prettymaps.plot(# City name'Barra da Tijuca',dilate=0,figsize=(22,10),preset='tijuca',)plot=prettymaps.plot('Stad van de Zon, Heerhugowaard, Netherlands',preset='heerhugowaard',)Use prettymaps.create_preset() to create a preset:prettymaps.create_preset("my-preset",layers={"building":{"tags":{"building":True,"leisure":["track","pitch"]}},"streets":{"width":{"trunk":6,"primary":6,"secondary":5,"tertiary":4,"residential":3.5,"pedestrian":3,"footway":3,"path":3}},},style={"perimeter":{"fill":False,"lw":0,"zorder":0},"streets":{"fc":"#F1E6D0","ec":"#2F3737","lw":1.5,"zorder":3},"building":{"palette":["#fff"],"ec":"#2F3737","lw":1,"zorder":4}})prettymaps.preset('my-preset')layersstylecircleradiusdilatebuildingtags:building: trueleisure:- track- pitchec: '<span style="background-color:#2F3737; color:#fff">#2F3737'lw: 1palette:- '#fff'zorder: 4null...null...null...streetswidth:footway: 3path: 3pedestrian: 3primary: 6residential: 3.5secondary: 5tertiary: 4trunk: 6ec: '#2F3737'fc: '#F1E6D0'lw: 1.5zorder: 3perimeter.nan...fill: falselw: 0zorder: 0Use prettymaps.delete_preset() to delete presets:# Show presets before deletionprint('Before deletion:')display(prettymaps.presets())# Delete 'my-preset'prettymaps.delete_preset('my-preset')# Show presets after deletionprint('After deletion:')display(prettymaps.presets())Before deletion:presetparams0barcelona{'layers': {'perimeter': {'circle': False}, 's...1barcelona-plotter{'layers': {'streets': {'width': {'primary': 5...2cb-bf-f{'layers': {'streets': {'width': {'trunk': 6, ...3default{'layers': {'perimeter': {}, 'streets': {'widt...4heerhugowaard{'layers': {'perimeter': {}, 'streets': {'widt...5macao{'layers': {'perimeter': {}, 'streets': {'cust...6minimal{'layers': {'perimeter': {}, 'streets': {'widt...7my-preset{'layers': {'building': {'tags': {'building': ...8tijuca{'layers': {'perimeter': {}, 'streets': {'widt...After deletion:presetparams0barcelona{'layers': {'perimeter': {'circle': False}, 's...1barcelona-plotter{'layers': {'streets': {'width': {'primary': 5...2cb-bf-f{'layers': {'streets': {'width': {'trunk': 6, ...3default{'layers': {'perimeter': {}, 'streets': {'widt...4heerhugowaard{'layers': {'perimeter': {}, 'streets': {'widt...5macao{'layers': {'perimeter': {}, 'streets': {'cust...6minimal{'layers': {'perimeter': {}, 'streets': {'widt...7tijuca{'layers': {'perimeter': {}, 'streets': {'widt...Useprettymaps.multiplotandprettymaps.Subplotto draw multiple regions on the same canvas# Draw several regions on the same canvasprettymaps.multiplot(prettymaps.Subplot('Cidade Baixa, Porto Alegre',style={'building':{'palette':['#49392C','#E1F2FE','#98D2EB']}}),prettymaps.Subplot('Bom Fim, Porto Alegre',style={'building':{'palette':['#BA2D0B','#D5F2E3','#73BA9B','#F79D5C']}}),prettymaps.Subplot('Farroupilha, Porto Alegre',style={'building':{'palette':['#EEE4E1','#E7D8C9','#E6BEAE']}}),# Load a global presetpreset='cb-bf-f',# Figure sizefigsize=(12,12))