Cartopy

How to fix pip cartopy error: “geos_c.h: No such file or directory”

Problem:

When trying to install cartopy on Linux using e.g. sudo pip3 install cartopy, you see an error message like

lib/cartopy/trace.cpp:633:10: fatal error: geos_c.h: Datei oder Verzeichnis nicht gefunden                                                                                                 
  633 | #include "geos_c.h"                                                                                                                                                                
      |          ^~~~~~~~~~                                                                                                                                                                
compilation terminated.                                                                                                                                                                    
setup.py:117: UserWarning: Unable to determine GEOS version. Ensure you have 3.3.3 or later installed, or installation may fail.

Solution:

Install libgeos-dev using

sudo apt -y install libgeos-dev

 

Posted by Uli Köhler in Cartopy, Python

How to install cartopy on Ubuntu

First, you need to install libproj (which is a dependency of cartopy) using

sudo apt -y install libproj-dev libgeos-dev

After that, install cartopy using

sudo pip3 install cartopy

 

Posted by Uli Köhler in Cartopy, Geoinformatics, Python

How fix Cartopy pip install error ‘Proj 4.9.0 must be installed.’

Problem:

When trying to install cartopy using e.g. pip3 install cartopy you see this error message:

Collecting cartopy
  Downloading Cartopy-0.19.0.post1.tar.gz (12.1 MB)
     |████████████████████████████████| 12.1 MB 13.2 MB/s 
  Installing build dependencies ... done
  Getting requirements to build wheel ... error
  ERROR: Command errored out with exit status 1:
   command: /usr/bin/python3 /tmp/tmp2q7tvpo8 get_requires_for_build_wheel /tmp/tmpfwd5htse
       cwd: /tmp/pip-install-dg2i313t/cartopy
  Complete output (1 lines):
  Proj 4.9.0 must be installed.
  ----------------------------------------
ERROR: Command errored out with exit status 1: /usr/bin/python3 /tmp/tmp2q7tvpo8 get_requires_for_build_wheel /tmp/tmpfwd5htse Check the logs for full command output.

Solution:

Install proj using e.g.

sudo apt -y install libproj-dev

and then install cartopy again using e.g.

sudo pip3 install cartopy

 

Posted by Uli Köhler in Cartopy, Geoinformatics, Python

How to get bounding box of a country using Natural Earth data and Cartopy

In this example, we’ll determine the bounding box of Kenya using the public domain Natural Earth dataset and the Cartopy library.

Rendering just the bounding box of Kenya (with the actual country being highlighted in green) looks like this:

How to get the bounding box

First we use Cartopy’s cartopy.io.shapereader.natural_earth() function that will automatically download Natural Earth data (if it has already been downloaded, the cached data will be used):

shpfilename = shpreader.natural_earth(resolution='10m',
                                      category='cultural',
                                      name='admin_0_countries')
reader = shpreader.Reader(shpfilename)

Now we can filter for Kenya just like we did in our previous post on How to highlight a specific country using Cartopy:

kenya = [country for country in reader.records() if country.attributes["NAME_LONG"] == "Kenya"][0]

and get the bounding box using kenya.bounds:

lon_min, lat_min, lon_max, lat_max = kenya.bounds

Complete example code

This code will render the image shown above:

import cartopy.crs as ccrs
import cartopy.feature as cf
from cartopy.feature import ShapelyFeature
from matplotlib import pyplot as plt

proj = ccrs.PlateCarree()
ax = plt.axes(projection=proj)
# Show only Africa
#ax.set_extent([-23, 55, -35, 40])
ax.stock_img()

ax.add_feature(cf.COASTLINE, lw=2)
# Make figure larger
plt.gcf().set_size_inches(20, 10)

import cartopy.io.shapereader as shpreader
# Read shape file
shpfilename = shpreader.natural_earth(resolution='10m',
                                      category='cultural',
                                      name='admin_0_countries')
reader = shpreader.Reader(shpfilename)
# Filter for a specific country
kenya = [country for country in reader.records() if country.attributes["NAME_LONG"] == "Kenya"][0]
# Determine bounding box
lon_min, lat_min, lon_max, lat_max = kenya.bounds
ax.set_extent([lon_min, lon_max, lat_min, lat_max])

# Display Kenya's shape
shape_feature = ShapelyFeature([kenya.geometry], ccrs.PlateCarree(), facecolor="lime", edgecolor='black', lw=1)
ax.add_feature(shape_feature)

# Save figure as SVG
plt.savefig("Kenya-Bounding-Box-Tight.svg")

 

Posted by Uli Köhler in Cartopy, Geography, Python

How to plot Shapefile data in Cartopy

In order to display shapefile data in Cartopy, we can first use the cartopy.io.shapereader package to read the shape data and then convert the geometry we want to display to a cartopy.feature.ShapelyFeature.

In the following example, we’ll read the Natural Earth ne_110m_admin_0_countries.shp and
Note that there’s an easier way to plot Natural Earth data using shpreader.natural_earth – see How to highlight a specific country using Cartopy and we’ll use the Natural Earth dataset just as an example!

import cartopy.io.shapereader as shpreader
# Read shape file
reader = shpreader.Reader("ne_110m_admin_0_countries.shp")
# Filter for a specific country
kenya = [country for country in reader.records() if country.attributes["NAME_LONG"] == "Kenya"][0]

# Display Kenya's shape
shape_feature = ShapelyFeature([kenya.geometry], ccrs.PlateCarree(), facecolor="lime", edgecolor='black', lw=1)
ax.add_feature(shape_feature)

Complete code example

import cartopy.crs as ccrs
import cartopy.feature as cf
from cartopy.feature import ShapelyFeature
from matplotlib import pyplot as plt

proj = ccrs.PlateCarree()
ax = plt.axes(projection=proj)
# Show only Africa
ax.set_extent([-23, 55, -35, 40])
ax.stock_img()

ax.add_feature(cf.COASTLINE, lw=2)
# Make figure larger
plt.gcf().set_size_inches(20, 10)

import cartopy.io.shapereader as shpreader
# Read shape file
reader = shpreader.Reader("ne_110m_admin_0_countries.shp")
# Filter for a specific country
kenya = [country for country in reader.records() if country.attributes["NAME_LONG"] == "Kenya"][0]

# Display Kenya's shape
shape_feature = ShapelyFeature([kenya.geometry], ccrs.PlateCarree(), facecolor="lime", edgecolor='black', lw=1)
ax.add_feature(shape_feature)

# Save figure as SVG
plt.savefig("Africa-Highlight-Kenya.svg")
Posted by Uli Köhler in Cartopy, Geography, Python

How to highlight a specific country using Cartopy

In our previous posts, e.g. How to draw Africa map using Cartopy we showed how to draw an overview map of an entire continent using Cartopy. This post provides an example of how to highlight a specific country in that map. In this example, we’ll highlight Kenya

The general approach is:

  1. Use cartopy.io.shapereader.natural_earth to download Natural Earth data that contains the shape of Kenya
  2. Convert it to a cartopy.feature.ShapelyFeature
  3. Display said feature

Displaying Kenya’s Natural Earth shape in cartopy

First, we create a Reader for the Natural Earth data. Cartopy will automatically download the data if it has not been cached.

import cartopy.io.shapereader as shpreader

shpfilename = shpreader.natural_earth(resolution='110m',
                                      category='cultural',
                                      name='admin_0_countries')
reader = shpreader.Reader(shpfilename)

Now we can select Kenya by name from the records:

kenya = [country for country in reader.records() if country.attributes["NAME_LONG"] == "Kenya"][0]

In order to display that geometry, we use

shape_feature = ShapelyFeature([kenya.geometry], ccrs.PlateCarree(), facecolor="lime", edgecolor='black', lw=1)
ax.add_feature(shape_feature)

Complete example code

import cartopy.crs as ccrs
import cartopy.feature as cf
from cartopy.feature import ShapelyFeature
from matplotlib import pyplot as plt

proj = ccrs.PlateCarree()
ax = plt.axes(projection=proj)
# Show only Africa
ax.set_extent([-23, 55, -35, 40])
ax.stock_img()

ax.add_feature(cf.COASTLINE, lw=2)
# Make figure larger
plt.gcf().set_size_inches(20, 10)

# Read Natural Earth data
import cartopy.io.shapereader as shpreader

shpfilename = shpreader.natural_earth(resolution='110m',
                                      category='cultural',
                                      name='admin_0_countries')
reader = shpreader.Reader(shpfilename)
kenya = [country for country in reader.records() if country.attributes["NAME_LONG"] == "Kenya"][0]

# Display Kenya's shape
shape_feature = ShapelyFeature([kenya.geometry], ccrs.PlateCarree(), facecolor="lime", edgecolor='black', lw=1)
ax.add_feature(shape_feature)

# Save figure as SVG
plt.savefig("Africa-Highlight-Kenya.svg")

 

Posted by Uli Köhler in Cartopy, Geography, Python

How to draw Europe map using Cartopy

We can easily draw an Africa Map using Cartopy by setting the extents to [-13, 45, 30, 70]:

ax.set_extent([-13, 45, 30, 70])

Complete code example

The code above produces the image shown above:

import cartopy.crs as ccrs
import cartopy.feature as cf
from matplotlib import pyplot as plt

proj = ccrs.Miller()
ax = plt.axes(projection=proj)
ax.set_extent([-13, 45, 30, 70])
ax.stock_img()

ax.add_feature(cf.COASTLINE, lw=2)
ax.add_feature(cf.BORDERS)
# Make figure larger
plt.gcf().set_size_inches(20, 10)

# Save figure as SVG
plt.savefig("Europe.svg")

 

Posted by Uli Köhler in Cartopy, Geography, Python

How to make Cartopy coastline or border lines thicker (line width)

By standard, Cartopy draws every feature with the same line width:

ax.add_feature(cf.COASTLINE)
ax.add_feature(cf.BORDERS)

We can easily increasing the line width by adding e.g. lw=2 to the ax.add_feature() call:

ax.add_feature(cf.COASTLINE, lw=2)
ax.add_feature(cf.BORDERS)

Complete code example

This example produces the image with a wider coast line line width as shown above

import cartopy.crs as ccrs
import cartopy.feature as cf
from matplotlib import pyplot as plt

proj = ccrs.PlateCarree()
ax = plt.axes(projection=proj)
ax.set_extent([-23, 55, -35, 40])
ax.stock_img()

ax.add_feature(cf.COASTLINE, lw=2)
ax.add_feature(cf.BORDERS)
# Make figure larger
plt.gcf().set_size_inches(20, 10)

# Save figure as SVG
plt.savefig("Africa-Standard.svg")

 

Posted by Uli Köhler in Cartopy, Geography, Python

How to draw Africa map using Cartopy

We can easily draw an Africa Map using Cartopy by setting the extents to [-23, 55, -35, 40]:

ax.set_extent([-23, 55, -35, 40])

Complete code example

The code above produces the image shown above:

import cartopy.crs as ccrs
import cartopy.feature as cf
from matplotlib import pyplot as plt

proj = ccrs.PlateCarree()
ax = plt.axes(projection=proj)
ax.set_extent([-23, 55, -35, 40])
ax.stock_img()

ax.add_feature(cf.COASTLINE, lw=2)
ax.add_feature(cf.BORDERS)
# Make figure larger
plt.gcf().set_size_inches(20, 10)

# Save figure as SVG
plt.savefig("Africa.svg")

 

Posted by Uli Köhler in Cartopy, Geography, Python

How to draw straight line between two coordinates using Cartopy

In our previous posts Minimal Geodetic example using Cartopy and How to increase Geodetic resolution / accuracy / smoothness in Cartopy we have shown how to create a geodetic line on a map. While a geodetic is defined to be the shortest line on the Earth’s surface, it is not a straight line on a map projection.

In order to plot a geodetic we use:

plt.plot([lon1, lon2], [lat1, lat2], transform=ccrs.Geodetic())

In order to plot a straight line, we need to use the same projection as we used to create the map instead of transform=ccrs.Geodetic().

For example, if we created the map using

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

we need to plot the line using transform=ccrs.PlateCarree()

plt.plot([lon1, lon2], [lat1, lat2], transform=ccrs.PlateCarree())

In order to avoid errors, I strongly recommend using just one instance of the projection and assigning it to a common variable, for example:

proj = ccrs.PlateCarree()
ax = plt.axes(projection=proj)
plt.plot([-75, 77.23], [43, 28.61], transform=proj)

Note that for reasons currently unknown to me at the moment, this only works for some projections at the moment. Using ccrs.PlateCarree() and ccrs.Miller() works, but using ccrs.Mollweide() does not work!

Complete example

This code reproduces the image shown above:

import cartopy.crs as ccrs
import cartopy.feature as cf
from matplotlib import pyplot as plt

proj = ccrs.PlateCarree()
ax = plt.axes(projection=proj)
ax.stock_img()
ax.add_feature(cf.BORDERS)
# Add straight line between two points
# Format: plot([lon1, lon2], [lat1, lat2])
plt.plot([-75, 77.23], [43, 28.61], linestyle='--',
         color='blue', linewidth=8,
         transform=proj)
# Make figure larger
plt.gcf().set_size_inches(20, 10)

# Save figure as SVG
plt.savefig("Cartopy-Straight-Line-PlateCarree.svg")

 

Posted by Uli Köhler in Cartopy, Geography, Python

How to increase Geodetic resolution / accuracy / smoothness in Cartopy

In our previous post we have detailed how to draw a geodetic in Cartopy. However, as you can see in the resulting map, the geodetic line is broken up into several clearly visible segments:

In order to fix that, we need to subclass the original projection of the plot. In this example, we’re subclassing ccrs.Mollweide():

import cartopy.crs as ccrs

class HighResMollweide(ccrs.Mollweide):
    @property
    def threshold(self): return 100.0

Note that the default threshold for the Mollweide projection is 100000.0 – you can check for yourself using print(ccrs.Mollweide().threshold)

Now we can use that projection in plt.axes():

ax = plt.axes(projection=HighResMollweide())

Complete example code

This code reproduced the high-resolution geodetic image shown above:

import cartopy.crs as ccrs
import cartopy.feature as cf
from matplotlib import pyplot as plt

class HighResMollweide(ccrs.Mollweide):
    @property
    def threshold(self): return 100.0

ax = plt.axes(projection=HighResMollweide())
ax.stock_img()
ax.add_feature(cf.BORDERS)
# Add geodetic between two points
# Format: plot([lon1, lon2], [lat1, lat2])
plt.plot([-75, 77.23], [43, 28.61],
         color='blue', linewidth=2,
         transform=ccrs.Geodetic()
         )
# Make figure larger
plt.gcf().set_size_inches(20, 10)

# Save figure as SVG
plt.savefig("Cartopy-Geodetic-HiRes.svg")

Thanks to @ajdawson on StackOverflow for the original hint on how to solve this!

Posted by Uli Köhler in Cartopy, Geography, Python

Minimal Geodetic example using Cartopy

This minimal example shows you how to plot a geodetic line between two points. It is closely based on the cartopy with matplotlib intro.

import cartopy.crs as ccrs
import cartopy.feature as cf
from matplotlib import pyplot as plt
ax = plt.axes(projection = ccrs.Mollweide())
ax.stock_img()
ax.add_feature(cf.BORDERS)
# Add geodetic between two points
# Format: plot([lon1, lon2], [lat1, lat2])
plt.plot([-75, 77.23], [43, 28.61],
         color='blue', linewidth=2,
         transform=ccrs.Geodetic()
         )

 

Complete example code

This code reproduces the image shown above:

import cartopy.crs as ccrs
import cartopy.feature as cf
ax = plt.axes(projection = ccrs.Mollweide())
ax.stock_img()
ax.add_feature(cf.BORDERS)
# Add geodetic between two points
# Format: plot([lon1, lon2], [lat1, lat2])
plt.plot([-75, 77.23], [43, 28.61],
         color='blue', linewidth=2,
         transform=ccrs.Geodetic()
         )
# Make figure larger
plt.gcf().set_size_inches(20, 10)

# Save figure as SVG
plt.savefig("Cartopy-Geodetic.svg")

 

Posted by Uli Köhler in Cartopy, Geography, Python

How to add colored background to Cartopy map

Want to get from this black and white map

to this colored map

in just one line of code? Simply use cartopy’s stock_img():

ax.stock_img()

Complete example code

import cartopy.crs as ccrs
import cartopy.feature as cf
from matplotlib import pyplot as plt
ax = plt.axes(projection = ccrs.Mollweide())
ax.stock_img()
ax.add_feature(cf.COASTLINE)
ax.add_feature(cf.BORDERS)
# Make figure larger
plt.gcf().set_size_inches(20, 10)

# Save figure as SVG
plt.savefig("Cartopy-Colored.svg")

Posted by Uli Köhler in Cartopy, Geography, Python

How to draw country borders in Cartopy

Use

import cartopy.crs as ccrs
import cartopy.feature as cf
from matplotlib import pyplot as plt
ax = plt.axes(projection = ccrs.Mercator())
# This will add borders
ax.add_feature(cf.BORDERS)

The following code shows you a minimal example of how to plot country borders (and coastlines) using cartopy:

import cartopy.crs as ccrs
import cartopy.feature as cf
ax = plt.axes(projection = ccrs.Mercator())
ax.add_feature(cf.COASTLINE)
ax.add_feature(cf.BORDERS)
# Make figure larger
plt.gcf().set_size_inches(20, 10)

# Save figure as SVG
plt.savefig("Cartopy-Borders.svg")

Posted by Uli Köhler in Cartopy, Geography, Python

Cartopy minimal example with Coastlines

This example shows you a minimal example of how to plot coastlines using cartopy:

import cartopy.crs as ccrs
import cartopy.feature as cf
from matplotlib import pyplot as plt
ax = plt.axes(projection = ccrs.Mercator())
ax.add_feature(cf.COASTLINE)
# Make figure larger
plt.gcf().set_size_inches(20, 10)

# Save figure as SVG
plt.savefig("Cartopy-Coastlines.svg")

Posted by Uli Köhler in Cartopy, Geography, Python