pygmt : how to fill polygons with cmap color

  • Last Update :
  • Techknowledgy :

Here is my best guess at what you want:

import pygmt

fig = pygmt.Figure()
a = fig.basemap(region = [0, 6, 0, 2], projection = "X12c/4c", frame = True, )

pol = ["n0.9c", "c0.9c", "d0.9c"]
Mog = [
   pygmt.makecpt(cmap = "bilbao", series = [-5, 50, 5]),
   pygmt.makecpt(cmap = "bilbao", series = [-5, 15, 5]),
   pygmt.makecpt(cmap = "bilbao", series = [-8000, 4000])
]
longitude_polyT = [1, 3, 5]
latitude_polyT = [1, 1, 1]

for i, long in enumerate(longitude_polyT):
   fig.plot(x = long, y = latitude_polyT[i], style = pol[i], frame = a,
      pen = "black",
      color = Mog[i], cmap = True)

fig.show()

Suggestion : 2

Then, you can use fig.plot(..., cmap="mycategorical.cpt", color="+z", a="Z=Name") or something along those lines (refer to How to color polygons of a geopandas dataframe in pygmt? and https://www.pygmt.org/v0.3.1/api/generated/pygmt.Figure.plot.html).,I am attempting to plot and color the polygons from a geologic map kml file I converted to a gmt file but I don’t understand how to color the polygons. I’ve been able to plot the polygon outlines using the method here, but I want to color by name of the category or a dictionary of colors matched to the names. However, when I try to assign a category to the names and color by cmap such as in this example, I get the error: “pygmt.exceptions.GMTInvalidInput: Can’t use arrays for color if data is matrix or file.”. How can I color the polygons?,Thank you for helping me with this! I attempted coloring by categorical CPT following the method in the links you provided as best I can, but no figure is generated at the end when I try it. The gmt file is too large to upload to this site, so here is a google drive link that contains the files in addition to the source klm.,Hi @hazardgoat, thanks for trying PyGMT! You may need to convert the dictionary of {names:colors} into a categorical CPT file first (as mentioned in Coloring polygon). The mycategorical.cpt plaintext file should look something like:

The working part of my code that plots the polygon outlines:

import geopandas as gpd
import pygmt
import pandas as pd

gpd.io.file.fiona.drvsupport.supported_drivers['KML'] = 'rw'

# reads kml file
df_polygons = gpd.read_file('GMC_geo_poly.kml', driver = 'KML')

# converts kml file to gmt
df_polygons.to_file('GMC_geo_poly.gmt', driver = 'OGR_GMT', )

# reads gmt file
df_polygons = gpd.read_file('GMC_geo_poly.gmt', driver = 'OGR_GMT')

region = [-125, -122, 39, 41]

fig = pygmt.Figure()

fig.basemap(
   region = region,
   projection = 'M6i',
   frame = 'f'
)

fig.coast(
   shorelines = '0.5p,black',
   resolution = 'h',
   water = 'lightskyblue2',
   transparency = 50,
)

# plots the polygons from the gmt file
fig.plot(
   data = 'GMC_geo_poly.gmt',
)

# saves a copy of the generated figure
fig.savefig('GMC_geo_poly.png')
fig.show()

Hi @hazardgoat, thanks for trying PyGMT! You may need to convert the dictionary of {names:colors} into a categorical CPT file first (as mentioned in Coloring polygon). The mycategorical.cpt plaintext file should look something like:

Q red
grMz blue
QPc green

The full script is in the google drive, but the fig.plot command I’m using is:

fig.plot(
   data = 'GMC_geo_poly.gmt',
   cmap = polyColor_cpt,
   color = '+z',
   a = 'Z = Name',
)

and the cpt file looks like this:

C 255 / 222 / 153
Ca 153 / 128 / 235
D 255 / 179 / 153
E 77 / 179 / 235
E - Ep 77 / 179 / 236
Ec 77 / 153 / 222
Ep 77 / 153 / 204
gb 255 / 153 / 179
gr 204 / 153 / 255
gr - m 204 / 128 / 235
grCz 255 / 204 / 255
grCz ? 255 / 204 / 256
grMz 204 / 179 / 255
grMz ? 204 / 179 / 256
grpC 235 / 77 / 255
grpC ? 235 / 77 / 256
grPz 179 / 102 / 255
J 128 / 255 / 77
J ? 128 / 255 / 78
K 0 / 255 / 179
K ? 0 / 255 / 180
KJf 77 / 222 / 128
KJfm 102 / 204 / 102
KJfs 128 / 235 / 128
Kl 0 / 255 / 128
Kl ? 0 / 255 / 129
Ku 102 / 255 / 153
Ku - Ep 102 / 255 / 154
ls 222 / 153 / 77
m 222 / 153 / 204
mv 222 / 153 / 205
M 0 / 222 / 255
M ? 0 / 222 / 256
M + KJfs 0 / 222 / 257
Mc 0 / 204 / 222
Mzv 0 / 255 / 77
O 128 / 222 / 235
Oc 128 / 204 / 204
Oc ? 128 / 204 / 205
pC 128 / 128 / 204
pCc 128 / 128 / 179
P 179 / 235 / 255
Pm 255 / 255 / 102
Pz 204 / 222 / 102
Pzv 255 / 222 / 128
Q 179 / 255 / 255
Qg 204 / 204 / 204
Qls 0 / 255 / 255
Qoa 102 / 255 / 255
QPc 77 / 222 / 235
Qrv 0 / 153 / 255
Qrvp 0 / 128 / 255
Qs 235 / 255 / 255
Qv 0 / 77 / 255
Qv ? 0 / 77 / 256
Qvp 0 / 77 / 204
Qvp ? 0 / 77 / 205
sch 222 / 204 / 128
SO 255 / 179 / 204
Tc 77 / 179 / 255
Ti 77 / 0 / 245
TK 77 / 222 / 179
Tr 204 / 255 / 102
Tv 102 / 102 / 255
Tvp 102 / 102 / 204
um 255 / 77 / 153
B black
F white
N 127.5

Suggestion : 3

It is also possible to create a custom mapping for a colormap. This is accomplished by creating dictionary that specifies how the RGB channels change from one end of the cmap to the other.,Creating a colormap from a list of colors can be done with the LinearSegmentedColormap.from_list method. You must pass a list of RGB tuples that define the mixture of colors from 0 to 1.,If there are discontinuities, then it is a little more complicated. Label the 3 elements in each row in the cdict entry for a given color as (x, y0, y1). Then for values of x between x[i] and x[i+1] the color value is interpolated between y1[i] and y0[i+1].,Second, create the map explicitly and register it. Like the first method, this method works with any kind of Colormap, not just a LinearSegmentedColormap:

cdict = {
   'red': ((0.0, 0.0, 0.0),
      (0.5, 1.0, 1.0),
      (1.0, 1.0, 1.0)),

   'green': ((0.0, 0.0, 0.0),
      (0.25, 0.0, 0.0),
      (0.75, 1.0, 1.0),
      (1.0, 1.0, 1.0)),

   'blue': ((0.0, 0.0, 0.0),
      (0.5, 0.0, 0.0),
      (1.0, 1.0, 1.0))
}
row i: x y0 y1 /
   /
row i + 1: x y0 y1
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.colors
import LinearSegmentedColormap

# Make some illustrative fake data:

   x = np.arange(0, np.pi, 0.1)
y = np.arange(0, 2 * np.pi, 0.1)
X, Y = np.meshgrid(x, y)
Z = np.cos(X) * np.sin(Y) * 10
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)] # R - > G - > B
n_bins = [3, 6, 10, 100] # Discretizes the interpolation into bins
cmap_name = 'my_list'
fig, axs = plt.subplots(2, 2, figsize = (6, 9))
fig.subplots_adjust(left = 0.02, bottom = 0.06, right = 0.95, top = 0.94, wspace = 0.05)
for n_bin, ax in zip(n_bins, axs.flat):
   # Create the colormap
cmap = LinearSegmentedColormap.from_list(cmap_name, colors, N = n_bin)
# Fewer bins will result in "coarser"
colomap interpolation
im = ax.imshow(Z, origin = 'lower', cmap = cmap)
ax.set_title("N bins: %s" % n_bin)
fig.colorbar(im, ax = ax)
cdict1 = {
   'red': ((0.0, 0.0, 0.0),
      (0.5, 0.0, 0.1),
      (1.0, 1.0, 1.0)),

   'green': ((0.0, 0.0, 0.0),
      (1.0, 0.0, 0.0)),

   'blue': ((0.0, 0.0, 1.0),
      (0.5, 0.1, 0.0),
      (1.0, 0.0, 0.0))
}

cdict2 = {
   'red': ((0.0, 0.0, 0.0),
      (0.5, 0.0, 1.0),
      (1.0, 0.1, 1.0)),

   'green': ((0.0, 0.0, 0.0),
      (1.0, 0.0, 0.0)),

   'blue': ((0.0, 0.0, 0.1),
      (0.5, 1.0, 0.0),
      (1.0, 0.0, 0.0))
}

cdict3 = {
   'red': ((0.0, 0.0, 0.0),
      (0.25, 0.0, 0.0),
      (0.5, 0.8, 1.0),
      (0.75, 1.0, 1.0),
      (1.0, 0.4, 1.0)),

   'green': ((0.0, 0.0, 0.0),
      (0.25, 0.0, 0.0),
      (0.5, 0.9, 0.9),
      (0.75, 0.0, 0.0),
      (1.0, 0.0, 0.0)),

   'blue': ((0.0, 0.0, 0.4),
      (0.25, 1.0, 1.0),
      (0.5, 1.0, 0.8),
      (0.75, 0.0, 0.0),
      (1.0, 0.0, 0.0))
}

# Make a modified version of cdict3 with some transparency
# in the middle of the range.
cdict4 = {
   ** cdict3,
   'alpha': ((0.0, 1.0, 1.0),
      #(0.25, 1.0, 1.0),
      (0.5, 0.3, 0.3),
      #(0.75, 1.0, 1.0),
      (1.0, 1.0, 1.0)),
}
blue_red1 = LinearSegmentedColormap('BlueRed1', cdict1)