Anna
Anna

Reputation: 229

Matplotlib colorbar: some ticks appear without labels

I'm using plr.scatter and logariphmic scale, and i'm trying to add some specific tick values to the colorbar, but it seems to work really arbitrary. See the example:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
import matplotlib
from matplotlib.ticker import LogFormatter

x, y = np.meshgrid(np.linspace(0, 1, 30), np.linspace(0, 1, 30))
z = x**2 + 15*y**3 + 1.5
plt.figure(figsize=(9, 4.5))
plt.scatter(x, y, c=z, cmap=cm.jet, norm=matplotlib.colors.LogNorm(), vmin=1, vmax=20)
formatter = LogFormatter(10, labelOnlyBase=False) 
cbar = plt.colorbar(ticks=[1, 2, 5, 10, 15, 20], format=formatter)

This code produced all the required major ticks, plus some minor ticks, but only labeled 1 and 10, while I need all numbers to be seen in colorbar. At first I though it was due to the fact that 1 and 10 are integer powers of 10, and other number are not, but...

enter image description here

...if I change the log base to 2, we can see tick labels at 1 and 2, which are powers of 2, but we also see labels at 5, 10 and 20, which are not. 15 did not appear this time too, but if I try adding 17 it works (not shown on the picture, but it does)

formatter = LogFormatter(2, labelOnlyBase=False)

enter image description here

What is this sorcery and how do I make matplotlib add exactly the labels I want to the ticks? I can do it manually by using

cbar.ax.set_yticklabels(['1', '2', '5', '10', '15', '20'])

but it seems redundant. Is there a better way?

Upvotes: 1

Views: 1145

Answers (2)

rhazer
rhazer

Reputation: 37

LogFormatter and its subclasses use the minor_thresholds parameter to decide when to hide non-decade tick labels to prevent overcrowding. By default this will hide nearly all non-decade labels, but you can increase it to allow more labels to appear.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LogFormatter
from matplotlib.colors import LogNorm

x, y = np.meshgrid(np.linspace(0, 1, 30), np.linspace(0, 1, 30))
z = x**2 + 15*y**3 + 1.5

cnorm = LogNorm(vmin=1, vmax=20)
plt.figure(figsize=(9, 4.5))
plt.scatter(x, y, c=z, cmap=cm.jet, norm=cnorm)

# define minor_thresholds to be >= the range of the color scale
decades = np.ceil(np.log10(cnorm.vmax / cnorm.vmin))
formatter = LogFormatter(10, minor_thresholds=(decades, decades))

cbar = plt.colorbar(ticks=[1, 2, 5, 10, 15, 20], format=formatter)

scatter plot of rainbow dots, similar to original post but the colorbar is labeled at every explicitly defined tick value

Upvotes: 1

Jay Patel
Jay Patel

Reputation: 1420

You can format any axis ticks with formatter. Below is the example .

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
import matplotlib
from matplotlib.colors import LogNorm

x, y = np.meshgrid(np.linspace(0, 1, 30), np.linspace(0, 1, 30))
z = x**2 + 15*y**3 + 1.5
f, ax = plt.subplots(figsize=(9, 4.5))
p = plt.scatter(x, y, c=z, cmap=cm.jet, norm=LogNorm(vmin=1, vmax=20) )

v1 = np.linspace(z.min(), z.max(), 8, endpoint=True)

cbar=plt.colorbar(ticks=v1)              
cbar.ax.set_yticklabels(["{:4.2f}".format(i) for i in v1]) # add the labels

Output

Upvotes: 1

Related Questions