Name:Reform/Rebin magic
Category:IDL
Author:Conor
Tip:

Using the rebin/reform combination, you can perform all sorts of fun dimensional translations and neat tricks. For instance, let's say you have a simple row array and you want to repeat every element in it three times:

IDL> res = findgen(3)
IDL> print,res 0.00000 1.00000 2.00000
IDL> print,reform(rebin(transpose(res),3,3),9)
0.00000 0.00000 0.00000 1.00000 1.00000 1.00000 2.00000 2.00000 2.00000

Looking at each step individually helps explain what just happened:

IDL> print,transpose(res) 0.00000 1.00000 2.00000
IDL> print,rebin(transpose(res),3,3)
0.00000 0.00000 0.00000
1.00000 1.00000 1.00000
2.00000 2.00000 2.00000

transpose turns res into a column vector. Rebin then expands that column out right, and since there is only one element to expand extrapolation can't be done and the element is simply repeated. Reform is then used to turn it back into a row vector. If you wanted to alternate values, then you would simply get rid of the transpose:

IDL> print,rebin(res,3,3)
0.00000 1.00000 2.00000
0.00000 1.00000 2.00000
0.00000 1.00000 2.00000
IDL> print,reform(rebin(res,3,3),9)
0.00000 1.00000 2.00000 0.00000 1.00000 2.00000 0.00000 1.00000 2.00000

Here's a practical example. Imagine you have two lists of stars, one with 20 stars and one with 10 stars, each with x and y positions (relative to the center of a cluster, perhaps). You want to know how far all the stars in list one are from all the stars in list two. You can easily do that with reform/rebin:

; load random star positions
xpos1 = randomu(seed,10)
ypos1 = randomu(seed,10)
xpos2 = randomu(seed,20)
ypos2 = randomu(seed,20)

xpositions1 = rebin(xpos1,10,20)
ypositions1 = rebin(ypos1,10,20)
xpositions2 = rebin(reform(xpos2,1,20),10,20)
ypositions2 = rebin(reform(ypos2,1,20),10,20)

distances = sqrt( (xpositions1-xpositions2)^2 + (ypositions1-ypositions2)^2 )

mindistance = min(distances,wheremin,dim=2)
print,distances[wheremin]

You can then retrieve which stars are closest together

res = array_indices( distances,wheremin )

res will be a 2x10 array. The first column will be the index of a star in the first list, and the second column will be the index of the matching star in the second list.

Essentially, I've used some simple array operations to accomplish this. The first thing I did was take my first list of stars and expand it into a 10x20 array, so that each column is the same thing (or, to put it another way, each column corresponds to one star from the first list). Then, I use reform to turn the second star list into a column array, and then expand that into a 10x20 array. This causes each row to be filled with the same values (in other words, each row corresponds to one star from list 2). Finally, I calculate the distance between each element in the two resulting arrays, thereby calculating the distance from each point to every other point, all in one go. If I then wanted to know the distance between star 5 in the first list and star 6 in the second list, then I would simply check the value of distances[4,5]. In the second part, I use the second position argument to min() which returns the index where the minimum is found, similar to what you would get from the where() function. This can be combined with 'dim=2' which causes min to search along a column (i.e. search for the closest star to each star in list 1).