Reputation: 2679
I am using python and have a plot which looks like this:
Now the problem is that, as most bins are in the range 0-500 on x-axis, so I want to make the x-axis like [0, 100, 200, 300, 400, 500, 1000, 1500, 2000, 2500] and each interval has the same length.
I don't know how to do this in python. Any idea?
Upvotes: 1
Views: 3757
Reputation: 25023
As already said, you have to map the original abscissae to a new range, and then draw the xtics accordingly... The first part is the toughest, of course, and can be done in different ways, my take uses a vectorized approach using numpy
and computes the function body at runtime using eval
.
def make_xmap(l):
from numpy import array
ll = len(l)
dy = 1.0 / (ll-1)
def f(l, i):
if i == 0 : return "0.0"
y0 = i*dy-dy
x0, x1 = l[i-1:i+1]
return '%r+%r*(x-%r)/%r'%(y0,dy,x0,x1-x0)
fmt = 'numpy.where(x<%f,%s%s'
body = ' '.join(fmt%(j,f(l,i),"," if i<(ll-1) else ", 1.0") for i, j in enumerate(l))
tail = ')'*ll
def xm(x):
x = array(x)
return eval(body+tail)
return xm
import numpy
xm = make_xmap([0.,200.,1000.])
x = (-10.,0.,100.,200.,600.,1000.,1010)
print xm(x)
# [0.0, 0.0, 0.25, 0.5, 0.75, 1.0, 1.0]
Note that you have to import numpy
in your code, because we have used numpy.where
to construct the function body... If you prefer to import numpy as np
modify the fmt
string in the factory function...
The second part is easier, if you have an x
and an y
array to plot, with the subdivision from your example, you can do
import numpy # I touched this point before...
...
intervals = [0., 100., 200., 300., 400., 500., 1000., 1500., 2000., 2500.]
xm = make_xmap(intervals)
plt.plot(xm(x),y)
plt.xticks(xm(intervals), [str(xi) for xi in intervals])
plt.show()
You may want to change
...
tail = ')'*ll
def xm(x):
x = array(x)
return eval(body+tail)
...
to
...
tail = ')'*ll
code = compile(body+tail,'','eval')
def xm(x):
x = array(x)
return eval(code)
...
This small optimization avoids the compilation of the code string every time you call the mapping function, and is of course more relevant if the mapping is used many times on short inputs.
Upvotes: 0
Reputation: 76297
Perhaps there's a simpler way to do this, but it's certainly possible to do so in pyplot using these two steps:
Plot a different function, namely one with the same y values but different x values
Manipulate the x-ticks so that it appears like you've plotted your original function (but with a different axis).
I'll start with 2. Note the existence of the xticks, which allows you to do stuff like this:
ticks = [0, 100, 200, 300, 400, 500, 1000, 1500, 2000, 2500]
xticks(range(10), ticks)
This allows you to place both the locations of the xticks, as well as the labels.
Now, for 1., you just need to translate your original x
array to a new_x
array, which is spread out in arange(10)
, but non-linearly, according to your labels. If your points are in the array x
, then using np.interp1d
:
from scipy import interpolate
new_x = interpolate.interp1d(ticks, arange(10))(x)
In conclusion, use plot(new_x, y)
with the xticks
above.
Upvotes: 2