Search code examples
pythonmatplotlibpython-xarraycolorbarcartopy

Change colorbar ticks from powers of 10 to plain numbers


I am trying to read an .nc file and display the data on a map. I want the colorbar ticks to be not in powers of 10 scale, but rather in plain numbers, so from 0.1 to 10. Moreover, it will be welcome if I can format it so it goes from 0.1 to 10 in like 7 ticks, so the result is the same as in the attached picture.

Please note that I have not added the code snippet related to the data downloading, so the script is not runnable. If you cannot spot the mistake without running the code, please let me know, I will attach it so you can download the .nc file.

Format of the colorbar I want to achieve: log scale and plain numbering

Here is the code I am using. Sorry for the redundant imports.

import xarray as xr
import cartopy
import matplotlib
from matplotlib.colors import LogNorm
from matplotlib.offsetbox import AnchoredText
from matplotlib.ticker import ScalarFormatter, FormatStrFormatter
import sys
import os

#First we open the dataset and read the varaible of interest
ds = xr.open_dataset(OUTPUT_FILENAME)
chl = ds.CHL.sel(time=min_date)

#Setting the figure size and projection
fig = plt.figure(figsize=(15,15))
ax = plt.axes(projection=ccrs.PlateCarree())

#Adding coastlines and land
ax.coastlines(resolution="10m") #Coastline resolution
ax.set_extent([-9,2,35,37.6]) #Map extent
ax.add_feature(cartopy.feature.LAND) #Adding land
#Formatting colorbar <---------------------------------------------------DOES NOT WORK
ax.ticklabel_format(style='plain',useMathText=None)

#Adding gridlines
gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
                  linewidth=0.5, color='black', alpha=0.7, linestyle='--')
gl.top_labels = False
gl.right_labels = False

#Adding lat/lon labels in the axes
ax.text(-0.07, 0.55, 'Latitude [deg]', va='bottom', ha='center',
        rotation='vertical', rotation_mode='anchor',
        transform=ax.transAxes)
ax.text(0.5, -0.2, 'Longitude [deg]', va='bottom', ha='center',
        rotation='horizontal', rotation_mode='anchor',
        transform=ax.transAxes)

#Adding (C) info to the figure
SOURCE = 'ICMAN CSIC'
text = AnchoredText('$\copyright$ {}'.format(SOURCE),
                    loc=1, prop={'size': 9}, frameon=True)
ax.add_artist(text)

#Drawing the plot
chl.plot(ax=ax, transform=ccrs.PlateCarree(),
         vmin=0.1, vmax=10, extend='both', cbar_kwargs={'shrink': 0.2, 'pad':0.01},
         cmap="jet", norm=LogNorm(vmax=10))


#Figure title
ax.set_title("Chlorophyll NN (mg/m$^{3}$) "+ min_date_h + " - " + max_date_h)

Solution

  • The colorbar should be the last axes in the figure (fig.axes[-1]). You can manually set the colorbar's ticks and tick labels:

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.colors as colors
    
    X, Y = np.mgrid[-3:3:100j, -2:2:100j]
    Z = 10*np.exp(-X**2 - Y**2)
    
    fig, ax = plt.subplots()
    pcm = ax.pcolor(X, Y, Z, norm=colors.LogNorm(vmin=.1, vmax=10), cmap='jet')
    fig.colorbar(pcm, ax=ax)
    
    cb = fig.axes[-1]
    ticks = [.1,.2,.5,1,2,5,10]
    cb.yaxis.set_ticks(ticks, labels=[f"{t:g}" for t in ticks])
    cb.minorticks_off()
    

    (prior to matplotlib 3.5.0 you must set ticks and labels separately).

    enter image description here