0

I am using Python with numpy, scipy, matplotlib.

I have two lists containing arrays of varying length, which for concreteness I will call x and y and say they look like (the actual arrays are on the order of ~1000 elements in length, and the actual lists have on the order of ~10s to ~100s of arrays):

x = [
    np.array([0, 1, 2, 3, 4]),
    np.array([0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4]),
    np.array([0, 2 ,4])
]
y = [
    np.array([0, 0, 1, 0, 0]),
    np.array([1, 0.75, 0.5, 0.25, 0.0, 0.25, 0.5, 0.75, 1]),
    np.array([0, 1, 0,])
]

Each x-array is sorted, and each y-array is sorted by the corresponding x-array, so len(x[i])==len(y[i]) is always True and x[i][j] always corresponds to y[i][j]. Each x-array ranges between the same two values (e.g., 0 and 4 in the above example).

I want to make a plot or save an image (if possible I want to know how to do both) where the i'th row is y[i] vs. x[i], with brightness corresponding to the y-value.

So e.g., in the above example:

  • For the entire plot the x-axis would go from 0 to 4 (if I save an image instead of making a plot, then I'm not worried about explicitly having the x-values on an axis anyway, but I just know that the y-values of each row correspond to x-values going from 0 to 4).
  • The 1st row would have the middle fifth of the row white, and the rest of the row black.
  • The 2nd row would be divided into eights, with the middle of the row black and the two edges white, the rest varying shades of grey.
  • The 3rd row would be divided into thirds, with the middle third of the row white and the two edge thirds of the row black.

I'm sure I could do this easily if Python or numpy has any stretch-array functions so that I could normalize the lengths of all of the arrays in x and y, or if matplotlib simply has a built-in function for exactly this type of plot. But I don't know whether either of these exist.

Does anyone know how to do this sort of thing (or for that matter, what this sort of plot would be called)?

Thanks very much for any help. Please let me know if my question is unclear.

---Further elaboration on above example--- If I go the route of stretching the arrays to all be of the same length, then the final arrays above might look something like (after stretching)

x = [
    np.array([0, 0, 1, 1, 2, 3, 3, 4, 4]),
    np.array([0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4]),
    np.array([0,0,0,2,2,2,4,4,4])
]
y = [
    np.array([0, 0, 0, 0, 1, 0, 0, 0, 0]),
    np.array([1, 0.75, 0.5, 0.25,0, 0 .25,0 .5, 0.75, 1]),
    np.array([0, 0, 0, 1, 1, 1, 0, 0, 0])
]

And the plot or image would look something like would look like an image version of y (I can't post the image without 10 reputation points).

user3558855
  • 303
  • 4
  • 17
  • `I'm sure I could do this easily if Python or numpy has any stretch-array functions`. Did you look at the documentation? The first google result I see for "pad numpy array" is this:http://docs.scipy.org/doc/numpy/reference/generated/numpy.pad.html – Paul H Jan 14 '15 at 05:40
  • Hmm I don't think that's quite what I'm looking for - I could make all of the arrays the same length, but what I need is to do this in such a way that the values in the array are "spread out" through the lengthened array, e.g., [0,1,2,3,4]->[0,0,1,2,2,3,3,4,4]. So a stretch rather than a pad. I Googled a few things like "stretch numpy array", but didn't quite find what I was looking for. – user3558855 Jan 14 '15 at 05:50
  • Why don't you include examples of your desired final arrays and an example of the kind of plot you would like to see – Paul H Jan 14 '15 at 05:51
  • Okay I'll edit the post to include that – user3558855 Jan 14 '15 at 05:53

2 Answers2

1

You could use interp1d with kind="nearest". (Using "nearest" will give steps at the boundaries and look like an expansion, but without your needing to do it explicitly, and also do a reasonable approximation to what you want if your lengths don't exactly divide as needed.) This would give something like this:

enter image description here

import numpy as np
from scipy import interpolate
import matplotlib.pyplot as plt
import matplotlib.cm as cm


x = [
    np.array([0, 1., 2, 3, 4]),
    np.array([0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4]),
    np.array([0, 2., 4])
]
y = [
    np.array([0, 0, 1., 0, 0]),
    np.array([1, 0.75, 0.5, 0.25, .25, 0, .5, 0.75, 1]),
    np.array([0, 1., 0,])
]

N = 30
xd = np.linspace(0, 4, 30)

data = np.zeros((len(x), N), dtype=np.float)
print data.shape

for i in range(len(x)):
    xi, yi = x[i], y[i]
    f = interpolate.interp1d(x[i], y[i], kind="nearest")
    data[i] = f(xd)

fig, ax = plt.subplots()
i = ax.imshow(data, cmap=cm.gray, interpolation='nearest')
#fig.colorbar(i)

plt.show()

Because the x-dimension of the output needs to be an integer, you would need to have a number that was divisible by all or your lengths. This could be large odd numbers (45 in this case, though I used 30 as an approximation in the above example). A completely generalizable approach would be to build the plot from patches, although that would be much more of a hassle.

tom10
  • 67,082
  • 10
  • 127
  • 137
  • Yeah I think this and jme's approach are the kinds of things I'm looking for. I'll play around with this and see if I can get it working, thanks! – user3558855 Jan 14 '15 at 06:12
  • @user3558855: There are a lot of ways to do this, and what I suggested is the easiest that I know. The downside is that scipy's "nearest" might not be exactly what you're going for. If you don't like this, you'll have to manipulate it more directly, but if you ask about that here, you need to be much more specific about the algorithm that you want to use. (Though, if this is what you want to use, please accept the answer so we can all know that.) – tom10 Jan 14 '15 at 18:17
  • 1
    interp1d ended up being the perfect function. Since some of my arrays were long (100s to 1000s), I skipped the least common multiple part and just set the length to that of the longest array. Thanks again! – user3558855 Jan 15 '15 at 07:37
0

One approach would be to use numpy.repeat, which repeats each element of a 1-d array a certain number of times. For instance:

>>> np.repeat([1,2,3,4], 3)
array([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4])

The idea would be to find the least common multiple of the lengths of all of your lists, then use np.repeat on each to "stretch" the arrays to a common length.

More generally, you might interpolate the values of the arrays, for example, linearly, using scipy.interpolate.interp1d:

from scipy.interpolate import interp1d
import numpy as np

x = np.array([0, 1, 2, 3, 4])
y = np.array([0, 0, 1, 0, 0])

f = interp1d(x,y)
print f(np.linspace(0,4,10))

Which prints:

[ 0.          0.          0.          0.33333333  0.77777778  0.77777778
  0.33333333  0.          0.          0.        ]
jme
  • 19,895
  • 6
  • 41
  • 39