8

I am trying to change the value of the ticks on the x-axis an imshow plot using the following code:

import matplotlib.pyplot as plt
import numpy as np

def scale_xaxis(number):
    return(number+1001)

data = np.array([range(10),range(10,20)])
fig = plt.figure(figsize=(3,5))
ax = fig.add_subplot(111)
ax.imshow(data,aspect='auto')
ax.autoscale(False)
xticks = ax.get_xticks()
ax.xaxis.set_ticklabels(scale_xaxis(xticks))
plt.savefig("test.png")

Resulting image http://ubuntuone.com/2Y5ujtlEkEnrlTcVUxvWLU

However the x-ticks overlap and have "non-round" values. Is there some way for matplotlib to automatically do this? Either by using set_ticklabels or some other way?

Pedro Romano
  • 10,973
  • 4
  • 46
  • 50
Magnus
  • 307
  • 3
  • 8

2 Answers2

8

Also look into using extent (doc) to let matplotlib do all the thinking about how to put in the tick labels and add in an arbitrary shift:

data = np.array([range(10),range(10,20)])
fig = plt.figure(figsize=(3,5))
ax = fig.add_subplot(111)
ax.imshow(data,aspect='auto',extent=[10000,10010,0,1])  

If you definitely want do to it my hand, you might be better off setting the formatter and locator of the axis to get what you want (doc).

import matplotlib.pyplot as plt
import numpy as np

def scale_xaxis(number):
    return(number+1001)

def my_form(x,pos):
    return '%d'%scale_xaxis(x)

data = np.array([range(10),range(10,20)])
fig = plt.figure(figsize=(3,5))
ax = fig.add_subplot(111)
ax.imshow(data,aspect='auto')
ax.autoscale(False)
ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(int(2)))
ax.xaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(my_form))

The locator needs to be set to make sure that ticks don't get put at non-integer locations which are then forcible cast to integers by the formatter (which would leave them in the wrong place)

related questions:

matplotlib: format axis offset-values to whole numbers or specific number

removing leading 0 from matplotlib tick label formatting

Community
  • 1
  • 1
tacaswell
  • 84,579
  • 22
  • 210
  • 199
  • This works for the specific problem, and answers the question I asked (in retrospect I see that I phrased my question poorly). But it doesn't really solve the main problem I had: I need some way to make matplotlib to select the appropriate number of ticks. For example if return(number+1001) was return(number+10001). How could I then make matplotlib automatically select the right number of ticks to avoid overlap? Should I accept the answer and make a new question, or should I edit this question? – Magnus Nov 17 '12 at 00:07
3

There are several ways to do this.

You can:

  1. Pass in an array of ints instead of an array of floats
  2. Pass in an array of formatted strings
  3. Use a custom tick formatter

The last option is overkill for something this simple.

As an example of the first option, you'd change your scale_xaxis function to be something like this:

def scale_xaxis(numbers):
    return numbers.astype(int) + 1001

Note that what you're getting out of ax.get_xticks is a numpy array instead of a single value. Thus, we need to do number.astype(int) instead of int(number).

Alternately, we could return a series of formatted strings. set_xticklabels actually expects a sequence of strings:

def scale_xaxis(numbers):
    return ['{:0.0f}'.format(item + 1001) for item in numbers]

Using a custom tick formatter is overkill here, so I'll leave it out for the moment. It's quite handy in the right situation, though.

Joe Kington
  • 275,208
  • 71
  • 604
  • 463