Let's talk about the six methods I often use to draw maps

Today, let's talk about several map drawing methods I often use in my daily work and life. Next, I will introduce the map drawing methods of these visual libraries. Of course, there are many excellent class libraries for drawing beautiful visual maps. There is no way to list them one by one

pyecharts,plotly,folium,bokeh,basemap,geopandas,cartopy

Boken

Firstly, we introduce Boken's method of drawing map

Bokeh supports the creation of basic map visualization and map visualization based on processing geographic data

Draw a map of the world

from bokeh.plotting import figure, show
from bokeh.tile_providers import CARTODBPOSITRON, get_provider
from bokeh.io import output_notebook


output_notebook()
tile_provider = get_provider(CARTODBPOSITRON)

p = figure(x_range=(-2000000, 6000000), y_range=(-1000000, 7000000),
           x_axis_type="mercator", y_axis_type="mercator")
p.add_tile(tile_provider)

show(p)

Draw another map of China

from bokeh.plotting import curdoc, figure
from bokeh.models import GeoJSONDataSource
from bokeh.io import show

# Read the map data of China and send it to GeoJSONDataSource
with open("china.json", encoding="utf8") as f:
    geo_source = GeoJSONDataSource(geojson=f.read())
# Set a canvas
p = figure(width=500, height=500)
# Using the patches function and geo_source draw map
p.patches(xs='xs', ys='ys', source=geo_source)
show(p)

It is also very convenient for us to draw the map through GEO geographic data, but the map looks monotonous. We draw different provinces into different colors to see

with open("china.json", encoding="utf8") as f:
    data = json.loads(f.read())
# Judge whether it is Beijing data
def isBeijing(district):
    if 'beijing' in district['properties']['woe-name'].lower():
        return True
    return False
# data['features'] = list(filter(isInLondon, data['features']))
# Filter data
# Add a color attribute for each region
for i in range(len(data['features'])):
    data['features'][i]['properties']['color'] = ['red', 'blue', 'yellow', 'orange', 'gray', 'purple'][i % 6]
    data['features'][i]['properties']['number'] = random.randint(0, 20_000)
geo_source = GeoJSONDataSource(geojson=json.dumps(data))
p = figure(width=500, height=500, tooltips="@name, number: @number")
p.patches(xs='xs', ys='ys', fill_alpha=0.7,
        line_color='white',
        line_width=0.5,
        color="color",   # Add a color attribute, where "color" corresponds to the color attribute of each region
        source=geo_source)
p.axis.axis_label = None
p.axis.visible = False
p.grid.grid_line_color = None

show(p)

It can be seen that there is already an internal flavor. The only drawback is that the 13th segment of the South China Sea is not displayed

geopandas

GeoPandas is a map visualization tool based on Pandas. Its data structure is completely inherited from Pandas. It is very friendly to students familiar with master pan

Or draw a map of the world first

import pandas as pd
import geopandas
import matplotlib.pyplot as plt
%matplotlib inline

world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))
world.plot()
plt.show()

This is also a classic picture on the official website of geopandas. You can see that it is very simple. Except for the import code, the map is drawn in only three lines

Now let's continue to draw the map of China. This time, we add the information of Jiuduan line

china_nine = geopandas.read_file(r"geojson/Nine segment line GS(2019)1719 number.geojson")
china = geopandas.read_file('china-new.json')
fig, ax = plt.subplots(figsize=(12, 8),dpi=80)
ax = china.plot(ax=ax, column='number')
ax = china_nine.plot(ax=ax)
plt.show()

We reused the previously processed china.json data. The number field is randomly generated test data, and the effect is comparable to that of Bokeh

plotly

Next, let's introduce plot, which is also a very useful Python visualization tool. If we want to draw map information, we need to install the following dependencies

!pip install geopandas==0.3.0
!pip install pyshp==1.2.10
!pip install shapely==1.6.3

Next, let's draw a world map

import plotly.graph_objects as go

fig = go.Figure(go.Scattermapbox(
    mode = "markers+lines",
    lon = [10, 20, 30],
    lat = [10, 20,30],
    marker = {'size': 10}))

fig.add_trace(go.Scattermapbox(
    mode = "markers+lines",
    lon = [-50, -60,40],
    lat = [30, 10, -20],
    marker = {'size': 10}))

fig.update_layout(
    margin ={'l':0,'t':0,'b':0,'r':0},
    mapbox = {
        'center': {'lon': 113.65000, 'lat': 34.76667},
        'style': "stamen-terrain",
        'center': {'lon': -20, 'lat': -20},
        'zoom': 1})

fig.show()

Here we use the underlying API plot.graph_ Objects. Choroplethmapbox

Let's continue to draw a map of China using an advanced API, plot. Express. Choropleth_ mapbox

import pandas as pd
import plotly.express as px
import numpy as np
import json

with open(r"china_province.geojson", encoding='utf8') as f:
    provinces_map = json.load(f)

df = pd.read_csv(r'data.csv')
df.diagnosis = df.diagnosis.map(np.log)

fig = px.choropleth_mapbox(
    df,
    geojson=provinces_map,
    color='diagnosis',
    locations="region",
    featureidkey="properties.NL_NAME_1",
    mapbox_style="carto-darkmatter",
    color_continuous_scale='viridis',
    center={"lat": 37.110573, "lon": 106.493924},
    zoom=3,
)
fig.show()

It can be seen that the interactive map drawn is still very beautiful, but the rendering speed is somewhat moving. It depends on your personal needs. If you have requirements for rendering speed, Ployly may not be the best choice~

Cartopy/Basemap

The reason why the two libraries are put together is that they are based on Matplotlib. With the no maintenance of Python 2, Basemap is also abandoned by Matplotlib, and Cartopy becomes a regular. Next, we mainly introduce the Cartopy tool

Cartopy makes use of the powerful PROJ.4, NumPy and Shapely libraries, and builds a programming interface on Matplotlib to create and publish high-quality maps

Let's draw a map of the world first

%matplotlib inline
import cartopy.crs as ccrs
import matplotlib.pyplot as plt

ax = plt.axes(projection=ccrs.PlateCarree())
ax.coastlines()

plt.show()

This is a very classic and common world map drawn by cartopy. The form is relatively simple. Let's enhance the map below

import datetime
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.feature.nightshade import Nightshade


fig = plt.figure(figsize=(10, 5))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())

date = datetime.datetime(2021, 12, 2, 21)

ax.set_title(f'Night time shading for {date}')
ax.stock_img()
ax.add_feature(Nightshade(date, alpha=0.2))
plt.show()

Through the above code, we have drawn the day and night map of the current time world, which is still very strong

Let's continue to draw a map of China

import cartopy.io.shapereader as shpreader
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
import cartopy.io.shapereader as shapereader
import matplotlib.ticker as mticker
#Load China region shp from file
shpfile = shapereader.Reader(r'ne_10m_admin_0_countries_chn\ne_10m_admin_0_countries_chn.shp')
# Set figure size
fig = plt.figure(figsize=[8, 5.5])
# Set the projection mode and draw the main drawing
ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180))
ax.add_geometries(
        shpfile.geometries(),
        ccrs.PlateCarree())
ax.set_extent([70, 140, 0, 55],crs=ccrs.PlateCarree())
plt.show()

The biggest feature of cartopy mapping is its high flexibility. The corresponding cost is that it will be more difficult to write code. For example, if we want to fill different colors in different provinces, we need to write a little more code

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
import shapely.geometry as sgeom

import cartopy.crs as ccrs
import cartopy.io.shapereader as shpreader

font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14) 

def sample_data():
#    lons = [110, 115, 120, 122, 124 ]
    lons = [124, 122, 120, 115, 110 ]
    lats = [33, 32, 28, 30, 28 ]
    return lons, lats

#ax = plt.axes([0, 0, 1, 1], projection=ccrs.LambertConformal())
ax = plt.axes(projection=ccrs.PlateCarree())


ax.set_extent([70, 140, 0, 55],crs=ccrs.Geodetic())

shapename = 'admin_1_states_provinces'
states_shp = shpreader.natural_earth(resolution='10m', category='cultural', name=shapename)


lons, lats = sample_data()

# to get the effect of having just the states without a map "background"
# turn off the outline and background patches
ax.background_patch.set_visible(False)
ax.outline_patch.set_visible(False)

plt.title(u'China Province Level', fontproperties=font)

# turn the lons and lats into a shapely LineString
track = sgeom.LineString(zip(lons, lats))

track_buffer = track.buffer(1)

for state in shpreader.Reader(states_shp).geometries():
    # pick a default color for the land with a black outline,
    # this will change if the storm intersects with our track
    facecolor = [0.9375, 0.9375, 0.859375]
    edgecolor = 'black'

    if state.intersects(track):
        facecolor = 'red'
    elif state.intersects(track_buffer):
        facecolor = '#FF7E00'

    ax.add_geometries([state], ccrs.PlateCarree(),
                      facecolor=facecolor, edgecolor=edgecolor)


# make two proxy artists to add to a legend
direct_hit = mpatches.Rectangle((0, 0), 1, 1, facecolor="red")
within_2_deg = mpatches.Rectangle((0, 0), 1, 1, facecolor="#FF7E00")
labels = [u'province level1',
          'province level2']
plt.legend([direct_hit, within_2_deg], labels,
           loc='lower left', bbox_to_anchor=(0.025, -0.1), fancybox=True, prop=font)
ax.figure.set_size_inches(14, 9)
plt.show()

folium

folium is an advanced map drawing tool based on the data application ability of Python ecosystem and the mapping ability of Leaflet.js library. It can flexibly customize the drawing area and show more diverse forms by manipulating data in Python and then visualizing it in Leaflet map

The first is to draw a world map in three lines of code

import folium


# define the world map
world_map = folium.Map()
# display world map
world_map

Next, draw a map of China

# Draw boundary
import json

df = pd.read_csv(r'plotly-choropleth-mapbox-demo-master/data.csv')
# read china border 
with open(r"plotly-choropleth-mapbox-demo-master/china_province.geojson", encoding='utf8') as f:
    china = json.load(f)

chn_map = folium.Map(location=[40, 100], zoom_start=4)


folium.Choropleth(
    geo_data=china,
    name="choropleth",
    data=df,
    columns=["region", "diagnosis"],
    key_on="properties.NL_NAME_1",
    fill_color="YlGn",
    fill_opacity=0.7,
    line_opacity=0.2,
    legend_name="New crown diagnosis",
).add_to(chn_map)

folium.LayerControl().add_to(chn_map)

chn_map

As a professional map tool, it not only has fast rendering speed, but also has a very high degree of customization, which is worth trying

PyEcharts

Finally, we introduce PyEcharts, a domestic excellent visualization tool

Map the world

from pyecharts import options as opts
from pyecharts.charts import Map
from pyecharts.faker import Faker


c = (
    Map()
    .add("test data", [list(z) for z in zip(Faker.country, Faker.values())], "world")
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(
        title_opts=opts.TitleOpts(title="Map-World map"),
        visualmap_opts=opts.VisualMapOpts(max_=200),
    )
)
c.render_notebook()

One advantage of drawing a map through Pyecharts is that we don't need to process GEO files. We can automatically match the country name to the map directly, which is very convenient

Then draw a map of China

c = (
    Map()
    .add("test data", [list(z) for z in zip(Faker.provinces, Faker.values())], "china")
    .set_global_opts(
        title_opts=opts.TitleOpts(title="Map-VisualMap(China)"),
        visualmap_opts=opts.VisualMapOpts(max_=200, is_piecewise=True),
    )
)
c.render_notebook()

We only need to replace the parameters into "china", which can easily draw the map of china. It is awesome. Of course, there are many ways to play Pyecharts.

Based on the above examples, we can see that Pyecharts is the simplest way to draw maps, which is very suitable for novices to learn and use; folium and cartopy are better than degrees of freedom. As professional map tools, they leave unlimited possibilities to users; Plotly and Bokeh are more advanced visualization tools, which are better than more beautiful picture quality and more API calls perfect

Today, we introduced several commonly used class libraries for drawing maps. Each tool has its advantages and disadvantages. We just need to clarify the goal and explore carefully when choosing!

reference resources: https://gitee.com/kevinqqnj/cartopy_trial/blob/master/cartopy_province.py https://zhuanlan.zhihu.com/p/112324234

Added by premracer on Thu, 09 Dec 2021 02:07:17 +0200