Search code examples
python-3.xpandascartopy

colour map grids based on value in pandas dataframe


I want to fill the gridded map with colors based on the value of interest. A sample data is here:

import pandas as pd

df = pd.DataFrame()
df['lon'] = [100,105,110,115,120,125,130]
df['lat'] = [38,40,42,44,46,48,50]
df['value'] = [1,2,3,4,5,6,7]

Specifically, is it possible to do this with Cartopy? I found a similar question here:https://stackoverflow.com/questions/53412785/plotting-pandas-csv-data-onto-cartopy-map. But that post was to plot scattered points, I need to fill the grids with colors.

I myself tried:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import cartopy.crs as ccrs

lon, lat = np.meshgrid(df['lon'], df['lat'])

fig = plt.figure(figsize=[15,15])
ax = plt.axes(projection=ccrs.PlateCarree())
ax.pcolormesh(lon,lat,df['variable'],latlon=True,cmap='jet')

plt.show()

The error is at ax.pcolormesh(...), it says "not enough values to unpack (expected 2, got 1)"

Many thanks for your help.


Solution

  • For discrete data you can create rectangular patches for each point. Here is a possible solution for your sample data set. Each row of data (lat, long, value) is used to create a rectangular patch. The value is normalized by dividing with max(value) to enable using colormap for coloring the patches.

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import cartopy.crs as ccrs
    import matplotlib.patches as mpatches
    
    def make_rect(clon, clat, dlon, dlat):
        lon_min = clon - dlon/2.
        lat_min = clat - dlat/2.
        lon_max = clon + dlon/2.
        lat_max = clat + dlat/2.
        # clockwise from LL
        #lons = [lon_min, lon_min, lon_max, lon_max, lon_min]
        #lats = [lat_min, lat_max, lat_max, lat_min, lat_min]
        ll = [lon_min,lat_min]
        ul = [lon_min,lat_max]
        ur = [lon_max,lat_max]
        lr = [lon_max,lat_min]
        return [ll, ul, ur, lr, ll]
    
    df = pd.DataFrame()
    df['lon'] = [100,105,110,115,120,125,130]
    df['lat'] = [38,40,42,44,46,48,50]
    df['value'] = [1,2,3,4,5,6,7]   # not suffice for meshgrid plot
    
    # The colormap to use.
    cm = plt.cm.get_cmap('jet')
    
    fig = plt.figure(figsize=[8,6])
    ax = plt.axes(projection=ccrs.PlateCarree(), extent=[95, 134, 35, 52])
    
    # plot the red dots using the available data
    # comment out if not needed
    ax.plot(df['lon'], df['lat'], 'ro')
    
    # plot rectangular patches at the data points
    dlon, dlat = 5, 2  #spacings between data points
    for lon1, lat1, val1 in zip(df['lon'], df['lat'], df['value']):
        pcorners = make_rect(lon1, lat1, dlon, dlat)
        poly = mpatches.Polygon(pcorners, ec='gray', fill=True, lw=0.25, \
               fc=cm(val1 / max(df['value'])), transform=ccrs.PlateCarree())
        ax.add_patch(poly)       
    
    ax.gridlines(draw_labels=True)
    plt.show()
    

    The output plot:

    enter image description here