# Mapping Tools¶

geopandas provides a high-level interface to the `matplotlib` library for making maps. Mapping shapes is as easy as using the `plot()` method on a `GeoSeries` or `GeoDataFrame`.

```In : world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))

```

We can now plot those GeoDataFrames:

```# Examine country GeoDataFrame
Out:
pop_est  ...                                           geometry
0     920938  ...  MULTIPOLYGON (((180.000000000 -16.067132664, 1...
1   53950935  ...  POLYGON ((33.903711197 -0.950000000, 34.072620...
2     603253  ...  POLYGON ((-8.665589565 27.656425890, -8.665124...
3   35623680  ...  MULTIPOLYGON (((-122.840000000 49.000000000, -...
4  326625791  ...  MULTIPOLYGON (((-122.840000000 49.000000000, -...

[5 rows x 6 columns]

# Basic plot, random colors
In : world.plot();
``` Note that in general, any options one can pass to pyplot in `matplotlib` (or style options that work for lines) can be passed to the `plot()` method.

## Choropleth Maps¶

geopandas makes it easy to create Choropleth maps (maps where the color of each shape is based on the value of an associated variable). Simply use the plot command with the `column` argument set to the column whose values you want used to assign colors.

```# Plot by GDP per capta
In : world = world[(world.pop_est>0) & (world.name!="Antarctica")]

In : world['gdp_per_cap'] = world.gdp_md_est / world.pop_est

In : world.plot(column='gdp_per_cap');
``` ### Creating a legend¶

When plotting a map, one can enable a legend using the `legend` argument:

```# Plot population estimates with an accurate legend
In : import matplotlib.pyplot as plt

In : fig, ax = plt.subplots(1, 1)

In : world.plot(column='pop_est', ax=ax, legend=True)
Out: <matplotlib.axes._subplots.AxesSubplot at 0x7fc85ba6c350>
``` However, the default appearance of the legend and plot axes may not be desirable. One can define the plot axes (with `ax`) and the legend axes (with `cax`) and then pass those in to the `plot` call. The following example uses `mpl_toolkits` to vertically align the plot axes and the legend axes:

```# Plot population estimates with an accurate legend
In : from mpl_toolkits.axes_grid1 import make_axes_locatable

In : fig, ax = plt.subplots(1, 1)

In : divider = make_axes_locatable(ax)

In : cax = divider.append_axes("right", size="5%", pad=0.1)

In : world.plot(column='pop_est', ax=ax, legend=True, cax=cax)
Out: <matplotlib.axes._subplots.AxesSubplot at 0x7fc85a0b6410>
``` And the following example plots the color bar below the map and adds its label using `legend_kwds`:

```# Plot population estimates with an accurate legend
In : import matplotlib.pyplot as plt

In : fig, ax = plt.subplots(1, 1)

In : world.plot(column='pop_est',
....:            ax=ax,
....:            legend=True,
....:            legend_kwds={'label': "Population by Country",
....:                         'orientation': "horizontal"})
....:
Out: <matplotlib.axes._subplots.AxesSubplot at 0x7fc85a0bb650>
``` ### Choosing colors¶

One can also modify the colors used by `plot` with the `cmap` option (for a full list of colormaps, see the matplotlib website):

```In : world.plot(column='gdp_per_cap', cmap='OrRd');
``` To make the color transparent for when you just want to show the boundary, you have two options. One option is to do `world.plot(facecolor="none", edgecolor="black")`. However, this can cause a lot of confusion because `"none"` and `None` are different in the context of using `facecolor` and they do opposite things. `None` does the “default behavior” based on matplotlib, and if you use it for `facecolor`, it actually adds a color. The second option is to use `world.boundary.plot()`. This option is more explicit and clear.:

```In : world.boundary.plot();
``` The way color maps are scaled can also be manipulated with the `scheme` option (if you have `mapclassify` installed, which can be accomplished via `conda install -c conda-forge mapclassify`). The `scheme` option can be set to any scheme provided by mapclassify (e.g. ‘box_plot’, ‘equal_interval’, ‘fisher_jenks’, ‘fisher_jenks_sampled’, ‘headtail_breaks’, ‘jenks_caspall’, ‘jenks_caspall_forced’, ‘jenks_caspall_sampled’, ‘max_p_classifier’, ‘maximum_breaks’, ‘natural_breaks’, ‘quantiles’, ‘percentiles’, ‘std_mean’ or ‘user_defined’). Arguments can be passed in classification_kwds dict. See the mapclassify documentation for further details about these map classification schemes.

```In : world.plot(column='gdp_per_cap', cmap='OrRd', scheme='quantiles');
``` ### Missing data¶

In some cases one may want to plot data which contains missing values - for some features one simply does not know the value. Geopandas (from the version 0.7) by defaults ignores such features.

```In : import numpy as np

In : world.loc[np.random.choice(world.index, 40), 'pop_est'] = np.nan

In : world.plot(column='pop_est');
``` However, passing `missing_kwds` one can specify the style and label of features containing None or NaN.

```In : world.plot(column='pop_est', missing_kwds={'color': 'lightgrey'});

In : world.plot(
....:     column="pop_est",
....:     legend=True,
....:     scheme="quantiles",
....:     figsize=(15, 10),
....:     missing_kwds={
....:         "color": "lightgrey",
....:         "edgecolor": "red",
....:         "hatch": "///",
....:         "label": "Missing values",
....:     },
....: );
....:
```  ## Maps with Layers¶

There are two strategies for making a map with multiple layers – one more succinct, and one that is a little more flexible.

Before combining maps, however, remember to always ensure they share a common CRS (so they will align).

```# Look at capitals
# Note use of standard `pyplot` line style options
In : cities.plot(marker='*', color='green', markersize=5);

# Check crs
In : cities = cities.to_crs(world.crs)

# Now we can overlay over country outlines
# And yes, there are lots of island capitals
# apparently in the middle of the ocean!
``` Method 1

```In : base = world.plot(color='white', edgecolor='black')

In : cities.plot(ax=base, marker='o', color='red', markersize=5);
``` Method 2: Using matplotlib objects

```In : import matplotlib.pyplot as plt

In : fig, ax = plt.subplots()

# set aspect to equal. This is done automatically
# when using *geopandas* plot on it's own, but not when
# working with pyplot directly.
In : ax.set_aspect('equal')

In : world.plot(ax=ax, color='white', edgecolor='black')
Out: <matplotlib.axes._subplots.AxesSubplot at 0x7fc85a067850>

In : cities.plot(ax=ax, marker='o', color='red', markersize=5)
Out: <matplotlib.axes._subplots.AxesSubplot at 0x7fc85a067850>

In : plt.show();
``` ### Control the order of multiple layers in a plot¶

When plotting multiple layers, use `zorder` to take control of the order of layers being plotted. The lower the `zorder` is, the lower the layer is on the map and vice versa.

Without specified `zorder`, cities (Points) gets plotted below world (Polygons), following the default order based on geometry types.

```In : ax = cities.plot(color='k')

In : world.plot(ax=ax);
``` We can set the `zorder` for cities higher than for world to move it of top.

```In : ax = cities.plot(color='k', zorder=2)

In : world.plot(ax=ax, zorder=1);
``` 