Big Data 9 min read

Master Chinese Map Visualization with Python‑geopandas: A Step‑by‑Step Guide

This tutorial walks you through reading Chinese GeoJSON files, converting projections, preparing scatter data, and creating a detailed map with an inset of the South China Sea using Python‑geopandas, Matplotlib, and custom legends, while also covering installation tips and known limitations.

Python Crawling & Data Mining
Python Crawling & Data Mining
Python Crawling & Data Mining
Master Chinese Map Visualization with Python‑geopandas: A Step‑by‑Step Guide

geopandas reads Chinese map files

geopandas provides a convenient read_file() method to load GeoJSON files. The example loads a provincial map and a nine‑dash line file, then plots them using the default WGS84 projection.

file = "中国省级地图GS(2019)1719号.geojson"
nine = "九段线GS(2019)1719号.geojson"
china_main = gpd.read_file(file)
china_nine = gpd.read_file(nine)
fig, ax = plt.subplots(figsize=(12, 8), dpi=80)
ax = china_main.plot(ax=ax)
ax = china_nine.plot(ax=ax)

The resulting map is shown below:

Projection conversion and basic settings

Switch to EPSG:2343 and adjust visual properties:

fig, ax = plt.subplots(figsize=(12, 8), dpi=80)
ax = china_main.geometry.to_crs(epsg=2343).plot(fc="white", ec="black", ax=ax)
ax = china_nine.geometry.to_crs(epsg=2343).plot(ec="black", ax=ax)

The key call is to_crs(epsg=2343) for projection transformation.

Data preparation

Scatter data is converted into a GeoDataFrame with geographic coordinates:

scattergdf = gpd.GeoDataFrame(
    scatter,
    geometry=gpd.points_from_xy(scatter.lon, scatter.lat),
    crs="EPSG:4326"
)
scattergdf.head()

After conversion, the data is re‑projected to EPSG:2343:

scattergdf_2343 = scattergdf.to_crs(epsg=2343, inplace=True)

Map visualization

The main plotting code creates the base map, adds the South China Sea inset, and customizes legends:

fig, ax = plt.subplots(figsize=(8,5), dpi=200)
plt.rcParams['font.family'] = ['Times New Roman']
ax = china_main.geometry.to_crs(epsg=2343).plot(fc="white", ec="black", linewidth=.8, ax=ax)
ax = china_nine.geometry.to_crs(epsg=2343).plot(color="gray", linewidth=.9, ax=ax)
for loc, size, class_name in zip(
        scattergdf_2343.geometry.representative_point(),
        scattergdf_2343["data"],
        scattergdf_2343["class"]):
    ax.scatter(loc.x, loc.y, s=10*size, fc=class_color[class_name], ec="black", lw=.5, zorder=2)
# hide spines
for spine in ['top', 'left', 'bottom', 'right']:
    ax.spines[spine].set_color("none")
ax.set_xlim(china_nine_2343.geometry[0].x-500000, china_nine_2343.geometry[1].x)
ax.set_ylim(china_nine_2343.geometry[0].y, china_nine_2343.geometry[1].y)
ax.set_xticks([])
ax.set_yticks([])
# custom legend points
ax.scatter([], [], c='#E21C21', s=30, label='cluster1', ec='black', lw=.5)
ax.scatter([], [], c='#3A7CB5', s=30, label='cluster2', ec='black', lw=.5)
ax.scatter([], [], c='#51AE4F', s=30, label='cluster3', ec='black', lw=.5)
# size legend
for i in range(1,6):
    ax.scatter([], [], c='white', s=i*10, label=str(i), edgecolor='black', lw=.5)
ax.legend(frameon=False, ncol=8, loc='upper center', fontsize=9, columnspacing=.2)
ax.text(.91, -0.02, '
Visualization by DataCharm', transform=ax.transAxes, ha='center', va='center', fontsize=6, color='black')
# inset map for South China Sea
ax_child = fig.add_axes([0.688, 0.125, 0.2, 0.2])
ax_child = china_main.geometry.to_crs(epsg=2343).plot(ax=ax_child, fc='white', ec='black')
ax_child = china_nine.geometry.to_crs(epsg=2343).plot(ax=ax_child, color='gray', linewidth=.9)
for loc, size, class_name in zip(
        scattergdf_2343.geometry.representative_point(),
        scattergdf_2343["data"],
        scattergdf_2343["class"]):
    ax_child.scatter(loc.x, loc.y, s=10*size, fc=class_color[class_name], ec='black', lw=.5, zorder=2)
ax_child.set_xlim(china_nine_2343.geometry[2].x, china_nine_2343.geometry[3].x)
ax_child.set_ylim(china_nine_2343.geometry[2].y, china_nine_2343.geometry[3].y)
ax_child.set_xticks([])
ax_child.set_yticks([])

Adding the inset map with add_axes() produces a focused view of the South China Sea.

The final visualization looks like this:

Summary

This issue demonstrates how to use Python‑geopandas for Chinese map drawing, covering data labeling, projection conversion, and custom legends. Note that geopandas installation can be tricky; using conda install -c conda-forge geopandas is recommended. Spatial visualizations still lack easy support for scale bars or north arrows, which are being improved.

Disclaimer: The data is for practice only and should not be used for research or publication.

PythonData AnalysisGISmap visualizationgeopandasSpatial Data
Python Crawling & Data Mining
Written by

Python Crawling & Data Mining

Life's short, I code in Python. This channel shares Python web crawling, data mining, analysis, processing, visualization, automated testing, DevOps, big data, AI, cloud computing, machine learning tools, resources, news, technical articles, tutorial videos and learning materials. Join us!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.