mgab
mgab

Reputation: 3994

formatting the colorbar ticklabels with SymLogNorm normalization in matplotlib

TL;DR

How can you...

Of course, if there were a simpler way to get nicely formatted xticks and labels on a colormap with symlog scaling, that'd be great too. But honestly, looking at the colorbars that the documentation itself exhibits, I don't have much hope... :-/


Starting from the beginning...

Matplotlib offers a few normalizations that can be used with colorbar. This is nicely explained in the documentation.

Among them, the logarithmic one (mpl.colors.LogNorm) works specially well, as it

  1. places the xticks evenly distributed.
  2. formats the ticklabels with a nice looking scientific notation**.

by itself. A minimal example:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors, ticker

data = np.arange(4).reshape(-1,1)+np.arange(4).reshape(1,-1)
data = 10**(data/2.)

plt.figure(figsize=(4,3))
plt.imshow(data, interpolation="None", cmap="gray", norm=colors.LogNorm())
plt.colorbar()
plt.show()

imshow with LogNorm normalization

On the other hand, the symmetric logarithmic one (matplotlib.colors.SymLogNorm) does neither. This SO answer defines a wrapper function for imshow that goes a long way towards the desired results, but it does not quite get there yet.

A minimal example with an adaptation of that function:

def imshow_symlog(arr, vmin=None, vmax=None, logthresh=5, logstep=1,
                  linscale=1, **kwargs):
    # Adapted from https://stackoverflow.com/a/23118662

    vmin = arr.min() if vmin is None else vmin
    vmax = arr.max() if vmax is None else vmax
    img=plt.imshow(arr,
                   vmin=float(vmin), vmax=float(vmax),
                   norm=colors.SymLogNorm(10**-logthresh, linscale=linscale),
                   **kwargs)

    maxlog=int(np.ceil(np.log10(vmax)))
    minlog=int(np.ceil(np.log10(-vmin)))

    #generate logarithmic ticks
    tick_locations=([-(10**x) for x in xrange(-logthresh, minlog+1, logstep)][::-1]
                    +[0.0]
                    +[(10**x) for x in xrange(-logthresh,maxlog+1, logstep)] )

    cb=plt.colorbar(ticks=tick_locations, format=ticker.LogFormatter())
    return img,cb

data2 = data - data[::-1,::-1]
plt.figure(figsize=(4,3))  
img, cb = imshow_symlog(data2, interpolation="None", cmap="gray", logthresh=0)
plt.show()

imshow with SymLogNorm normalization

Upvotes: 2

Views: 3550

Answers (1)

Andrey Sobolev
Andrey Sobolev

Reputation: 12713

Change the formatter in the function to LogFormatterMathtext:

cb=plt.colorbar(ticks=tick_locations, format=ticker.LogFormatterMathtext())

The formatters obviously lack nice (if any) documentation, but this one seems to do what you want:

enter image description here

Upvotes: 1

Related Questions