Colorbar for the subplots in PyGMT

Hey everyone,
I am new to PyGMT and I am trying to create subplots in PyGMT. I’ve set the colorbar position to be in the bottom center, however, it doesn’t run like that.

I have the following code so far:

import pygmt

path = r'E:\day'

fig = pygmt.Figure()

lowest = 255
highest = 325
interval = (highest - lowest) / 64

pygmt.makecpt(cmap="jet", series=[lowest, highest, interval])

with pygmt.config(FONT_TITLE="18p,5", MAP_TITLE_OFFSET="-12p", MAP_FRAME_TYPE="plain"):

    with fig.subplot(
        nrows=4,
        ncols=6,
        figsize=("42c", "28c"),
        margins=["0.2c", "0.2c"],
    ):
        for i in range(0, 24):
            fig.grdimage(
                grid=fr'{path}\2013276_{str(i).zfill(2)}.tif',
                frame=[f"lbtr+t{str(i).zfill(2)}:00"],
                cmap=True,
                panel=True,
                #dpi=300,
            )

with pygmt.config(FONT="18p,4"):
    fig.colorbar(position="JBC+w10c/0.5c+h", frame=["a10f10", "y+lLST (K)"])

fig.show()

One more question, how to set the colorbar annotation to show only the minimum and maximum values? The final result I would like to get is shown below.

Hello @wensentry,

Welcome to the GMT forum :slight_smile:!

Your issue was recognized and reported in this GitHub comment https://github.com/GenericMappingTools/pygmt/pull/2354#discussion_r1136518891
and is fixed via PR https://github.com/GenericMappingTools/pygmt/pull/2427.

So, upon PyGMT v0.10.0 placing a colorbar after an existing subplot will work correctly.

For now, you have to use +ooffset_x/offset_y to move your colorbar to the desired position:

with pygmt.config(FONT="18p,4"):
    fig.colorbar(position="JBC+o13.5c/0.5c+w10c/0.5c+h", frame=["a10f10", "y+lLST (K)"])
1 Like

Actually, the PR was merged into PyGMT v0.9.0. So if you upgrade your PyGMT to v0.9.0, you should get the expected results.

Hello @seisman it works!!!, thank you!!, stay safe and best regards.

Hello @yvonnefroehlich Thank you so much for your help. I have one more question. How to set the colorbar annotation to show only the minimum and maximum values? The final result I would like to get is shown below.

1 Like

@seisman, you are completely right! I am sorry for mixing this up :slightly_frowning_face:.

So far, I know unfortunately no direct way to add only the minimum and maximum values as colorbar annotations.

One (inelegant) idea or workaround here is to plot the same colorbar twice:

import pygmt


size = 5

fig = pygmt.Figure()

lowest = 255
highest = 325
interval = (highest - lowest) / 64
pygmt.makecpt(cmap="jet", series=[lowest, highest, interval])

with fig.subplot(
    nrows=4,
    ncols=6,
    figsize=("42c", "28c"),
    margins=["0.2c", "0.2c"],
):
    for i in range(0, 24):
        fig.basemap(
            region=[-size, size, -size, size],
            projection="X?",
            frame="lbtr",
            panel=True,
        )
    
# Add annotation for lowest value
fig.colorbar(
    cmap=True,
    position="JBC+w10c/0.5c+h", 
    frame=["a" + str(lowest), "y+lLST (K)"],
)
# Add annotation for highest value
fig.colorbar(
    cmap=True,
    position="JBC+w10c/0.5c+h", 
    frame=["a" + str(highest), "y+lLST (K)"],
)

fig.show()
# fig.savefig(fname="colorbar_anno_min_max.png")

Output figure:

1 Like

@yvonnefroehlich, Thank you so much. I learned a lot from you. Appreciate your time and help.

If interested, build GMT from this branch and try -S+r to limit annotations to the lower and upper boundaries.

Now merged into master.

@pwessel, thank you so much.

Hi @seisman @yvonnefroehlich ,

I encountered a similar problem with subplot:subsize in current pygmt version:

fig = pygmt.Figure()
pygmt.config(FONT="10p", FONT_TAG="10p,Helvetica-Bold,black")
with fig.subplot(
    nrows=1, ncols=2, subsize=("10c", "8c"),
    margins=["0.3c","0.5c"], sharey='l', frame=['WSne', 'xaf', 'yaf']
):
    
    max_abs_stress = 100
    pygmt.makecpt(cmap="../cpt/stress_bam.cpt", series=[-max_abs_stress, max_abs_stress, 0.1], 
                  continuous=True, output='../cpt/stress_bam-k2.cpt')
    stress_cpt='../cpt/stress_bam-k2.cpt'
    
    #-----------------------------------------------------------------------#
    with fig.set_panel(panel=0):
        fig.basemap(region=region, projection="Q?")

    #-----------------------------------------------------------------------#
    with fig.set_panel(panel=1):
        fig.basemap(region=region, projection="Q?")

colorbar_label = r'stress [MPa]'
fig.colorbar(cmap=stress_cpt,frame=[f"xaf+l{colorbar_label}", "y"], position="JBC+w10c/0.4c+o0c/0.7c+h+e")

if show_me:
    fig.show(dpi=300)

PyGMT information:
  version: v0.16.0
System information:
  python: 3.13.3 | packaged by conda-forge | (main, Apr 14 2025, 20:44:03) [GCC 13.3.0]
  executable: /share/anaconda3/envs/pygmt/bin/python
  machine: Linux-6.8.0-60-generic-x86_64-with-glibc2.35
Dependency information:
  numpy: 2.2.6
  pandas: 2.3.0
  xarray: 2025.4.0
  packaging: 25.0
  contextily: None
  geopandas: None
  IPython: 9.3.0
  pyarrow: None
  rioxarray: None
  gdal: None
  ghostscript: 10.04.0
GMT library information:
  version: 6.5.0
  padding: 2
  share dir: /share/anaconda3/envs/pygmt/share/gmt
  plugin dir: /share/anaconda3/envs/pygmt/lib/gmt/plugins
  library path: /share/anaconda3/envs/pygmt/lib/libgmt.so
  cores: 256
  grid layout: rows
  image layout: 
  binary version: 6.5.0

Best,
Ninghui

Hi @tiannh7,

Your code is incomplete and not working, and thus it is not possible to reproduce your issue.
Please provide a code example that directly demonstrates your issue.

Hi @yvonnefroehlich @seisman,

Thank you very much for your help and suggestions. I created a new Jupyter Notebook file to test the issue, and strangely, the results showed the colorbar position as normal. However, the complete example requires a large amount of data, which makes it difficult to reproduce the issue directly.

That said, I have encountered similar problems before: sometimes no manual adjustment is needed, while other times it is required. I work on both a Mac and multiple different Ubuntu systems, and I’m not sure if this might have some impact. I am actively working on finding a simpler example to reproduce this error. As soon as I identify one, I will let you know immediately.

I sincerely apologize for any inconvenience caused and appreciate your understanding.