43

I am creating a plot in python. Is there a way to re-scale the axis by a factor? The yscale and xscale commands only allow me to turn log scale off.

Edit:
For example. If I have a plot where the x scales goes from 1 nm to 50 nm, the x scale will range from 1x10^(-9) to 50x10^(-9) and I want it to change from 1 to 50. Thus, I want the plot function to divide the x values placed on the plot by 10^(-9)

Yotam
  • 10,295
  • 30
  • 88
  • 128
  • 7
    Yotam, you seem to have many questions outstanding that have been answered but you have yet to accept an answer for. Please accept an answer for the older questions or add additional information so we can help you! – Hooked Apr 16 '12 at 14:08

3 Answers3

92

As you have noticed, xscale and yscale does not support a simple linear re-scaling (unfortunately). As an alternative to Hooked's answer, instead of messing with the data, you can trick the labels like so:

ticks = ticker.FuncFormatter(lambda x, pos: '{0:g}'.format(x*scale))
ax.xaxis.set_major_formatter(ticks)

A complete example showing both x and y scaling:

import numpy as np
import pylab as plt
import matplotlib.ticker as ticker

# Generate data
x = np.linspace(0, 1e-9)
y = 1e3*np.sin(2*np.pi*x/1e-9) # one period, 1k amplitude

# setup figures
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
# plot two identical plots
ax1.plot(x, y)
ax2.plot(x, y)

# Change only ax2
scale_x = 1e-9
scale_y = 1e3
ticks_x = ticker.FuncFormatter(lambda x, pos: '{0:g}'.format(x/scale_x))
ax2.xaxis.set_major_formatter(ticks_x)

ticks_y = ticker.FuncFormatter(lambda x, pos: '{0:g}'.format(x/scale_y))
ax2.yaxis.set_major_formatter(ticks_y)

ax1.set_xlabel("meters")
ax1.set_ylabel('volt')
ax2.set_xlabel("nanometers")
ax2.set_ylabel('kilovolt')

plt.show() 

And finally I have the credits for a picture:

Left: ax1 no scaling, right: ax2 y axis scaled to kilo and x axis scaled to nano

Note that, if you have text.usetex: true as I have, you may want to enclose the labels in $, like so: '${0:g}$'.

oystein
  • 1,507
  • 1
  • 11
  • 13
  • On the left you see the "x 10^-9" on the bottom right. Using the `FuncFormatter` this feature seems to be disabled. I need this feature, unfortunately. – Sven Jul 29 '20 at 17:09
  • @Sven one thing that one can do about your concern is to move the factor "10^-9" into the axis label and have the `FuncFormatter` function account for it as well. – Bastian Apr 27 '22 at 07:44
13

Instead of changing the ticks, why not change the units instead? Make a separate array X of x-values whose units are in nm. This way, when you plot the data it is already in the correct format! Just make sure you add a xlabel to indicate the units (which should always be done anyways).

from pylab import *

# Generate random test data in your range
N = 200
epsilon = 10**(-9.0)
X = epsilon*(50*random(N) + 1)
Y = random(N)

# X2 now has the "units" of nanometers by scaling X
X2 = (1/epsilon) * X

subplot(121)
scatter(X,Y)
xlim(epsilon,50*epsilon)
xlabel("meters")

subplot(122)
scatter(X2,Y)
xlim(1, 50)
xlabel("nanometers")

show()

enter image description here

Hooked
  • 84,485
  • 43
  • 192
  • 261
12

To set the range of the x-axis, you can use set_xlim(left, right), here are the docs

Update:

It looks like you want an identical plot, but only change the 'tick values', you can do that by getting the tick values and then just changing them to whatever you want. So for your need it would be like this:

ticks = your_plot.get_xticks()*10**9
your_plot.set_xticklabels(ticks)
bobrobbob
  • 1,251
  • 11
  • 21
fraxel
  • 34,470
  • 11
  • 98
  • 102
  • To my understanding, xlim change the range of the plot and does not scale it. See my example. – Yotam Apr 16 '12 at 11:39
  • @Yotam - So you want the plot to be identical, but the values on x scale labels would change? – fraxel Apr 16 '12 at 11:48
  • 2
    Amazingly simple solution. However, I find that this results in labels with decimals, even when using a ticker that should only display integers (for example MultipleLocator or MaxNLocator). I found that this can be solved by using `ticks.astype(int)` instead of `ticks`. – Mr.H Oct 07 '17 at 14:33
  • Unfortunately, `get_xticks()` doesn't work until after you plot. Terribly annoying and pointless to make it like that. – Aku Mar 12 '18 at 23:48