Draw circle with longitude, latitude and radius (km) in cartopy of python

Question:

#!/usr/bin/env python

import os, sys
import pandas as pd
import cartopy
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import shapely.geometry as sgeom
import numpy as np
from cartopy.geodesic import Geodesic


if __name__ == '__main__':

    stn = pd.read_csv('obs_station.csv')
    gd = Geodesic()

    lcc = ccrs.LambertConformal(central_longitude=126., central_latitude=38.)
    fig = plt.figure(figsize=(7,7))
    ax = fig.add_subplot(111, projection=lcc)
    ax.coastlines(resolution='50m')
    geoms = []
    for lon, lat in zip(stn['longitude'], stn['latitude']):
        cp = gd.circle(lon=lon, lat=lat, radius=250000.)
        geoms.append(sgeom.Polygon(cp))
    ax.add_geometries(geoms, crs=lcc, edgecolor='r')
    ax.set_extent([120., 133., 30., 43.])
    plt.show()

The file ‘obs_station.csv’ contain several coordinates of longitudes and latitudes.

Using code above, I try to draw circles with specific radius (250 km).
But, nothing is on the map as below. Only show the map with coastlines.

I don’t know what is the problem. Help please.

Result:
result

Asked By: Jeriko

||

Answers:

You did not get the plots of the circles because of wrong coordinate transformation you specifies in .add_geometries() statement.

To get it right, suppose I use this data file:
‘obs_station.csv’:

longitude,latitude
127.603897,36.932988
126.505337,38.555939

And the modified code:-

#import os, sys
import pandas as pd
import cartopy
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import shapely.geometry as sgeom
import numpy as np
from cartopy.geodesic import Geodesic

if __name__ == '__main__':

    stn = pd.read_csv('obs_station.csv')
    gd = Geodesic()

    # This is long-lat coordinate system for use in ..
    # .. coordinate transformation options
    src_crs = ccrs.PlateCarree()

    lcc = ccrs.LambertConformal(central_longitude=126., central_latitude=38.)
    fig = plt.figure(figsize=(7,7))
    ax = fig.add_subplot(111, projection=lcc)
    ax.coastlines(resolution='50m')
    geoms = []
    for lon, lat in zip(stn['longitude'], stn['latitude']):
        cp = gd.circle(lon=lon, lat=lat, radius=250000.)

        #x,y = lcc.transform_point(lon, lat, src_crs)
        #cp = gd.circle(lon=x, lat=y, radius=250000.)
        geoms.append(sgeom.Polygon(cp))

    # Note the specification of coordinate transformation, using the
    # .. correct parameter:  crs=src_crs
    ax.add_geometries(geoms, crs=src_crs, edgecolor='r', alpha=0.5)
    ax.set_extent([120., 133., 30., 43.])

    plt.show()

The output:

korea01

In conclusion, your line of code:

ax.add_geometries(geoms, crs=lcc, edgecolor='r')

needs correct CRS. And the correct CRS is

ccrs.PlateCarree()

Edit

Some useful notes:
1. `from cartopy.geodesic import Geodesic` imports geodesic module from `geographiclib` for our uses. It is one of cartopy's dependencies.
2. The circles that are generated and plotted on any conformal projection (i.e. `LambertConformal`, `Mercator`, etc.) will appear as circles (NOT ellipses). And appear as ellipses in general on non-conformal projections.
3. Shapely geometry object is created from the the circle by `sgeom.Polygon(cp)`. It can be used to do geometric operations with predicates like `within, touches` etc.
4. The creation of point buffers from shapely's point objects is not correct. Create geodesic circles first, then convert it to shapely polygon.
5. Under the hood, geodesic circle is used to create/plot Tissot indicatrices.
Answered By: swatchai
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.