Reputation: 652
I have an image where every column has an associated attribute. I would like to plot the image and label each column with its attribute value. Here is a simple code showing what I mean:
import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage.filters import gaussian_filter
np.random.seed(200)
cols = 600
attr = list('abcdefghijklmnopqrstuvwxyz') * cols
attr = labels[:cols]
img = gaussian_filter(np.random.rand(400, cols), 100)
plt.imshow(img, cmap='inferno')
plt.xticks(np.arange(cols), attr)
plt.show()
The resulting image below shows how messy the X-labels get. What I would like is to show some labels, which get updated when interacting with the plot, like zooming and panning.
The reason I think this is possible is because the default behavior of maplotlib is correct (when not setting the xticks). It shows the column number in intervals so labels do not overlap, and get updated when zooming & panning.
So, my question is: is it possible to get the default matplotlib's label behavior with custom labels?
Upvotes: 1
Views: 2270
Reputation: 12618
What you want is called tick formatting. In this case you can create an instance of FuncFormatter
and assign it to the major ticks.
First you need to add FuncFormatter
to your imports:
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
import numpy as np
from scipy.ndimage.filters import gaussian_filter
You need a function that takes the tick value and its position and return the tick label. You won't need the position here but it will be passed to the function anyway. Make sure the function can handle unexpected tick values (I used matplotlib 2.0.0b4 and it put a tick at 600).
cols = 600
letters = list('abcdefghijklmnopqrstuvwxyz')
attr = (letters * (1 + cols // len(letters)))[:cols]
def format_tick(labels):
def get_label(x, pos):
try:
return labels[int(round(x))]
except IndexError:
return ''
return get_label
Create a FuncFormatter
instance using your format function:
formatter = FuncFormatter(format_tick(attr))
Set formatter
as the major formatter for your plot:
rs = np.random.RandomState(seed=200)
img = gaussian_filter(rs.rand(400, cols), 100)
plt.imshow(img, cmap='inferno')
plt.gca().xaxis.set_major_formatter(formatter)
Of course this labelling does not make any sense with your sample data. I'm sure there's a better way for your actual use case, whatever it is.
Upvotes: 3