comp.lang.idl-pvwave archive
Messages from Usenet group comp.lang.idl-pvwave, compiled by Paulo Penteado

Home » Public Forums » archive » Re: Using where() on slices of data cubes
Show: Today's Messages :: Show Polls :: Message Navigator
E-mail to friend 
Switch to threaded view of this topic Create a new topic Submit Reply
Re: Using where() on slices of data cubes [message #68324] Tue, 20 October 2009 13:32 Go to next message
David Fanning is currently offline  David Fanning
Messages: 11724
Registered: August 2001
Senior Member
JD Smith writes:

> you should easily be able to generalize the above arguments to access
> these elements

I think in this case the word "easily" might be
too subtly sarcastic to be easily appreciated by
the vast majority of this newsgroup. :-)

Cheers,

David

--
David Fanning, Ph.D.
Coyote's Guide to IDL Programming (www.dfanning.com)
Sepore ma de ni thui. ("Perhaps thou speakest truth.")
Re: Using where() on slices of data cubes [message #68325 is a reply to message #68324] Tue, 20 October 2009 13:03 Go to previous messageGo to next message
JDS is currently offline  JDS
Messages: 94
Registered: March 2009
Member
On Oct 20, 8:22 am, Conor <cmanc...@gmail.com> wrote:
> I feel like this should be an easy one, but I've never quite figured
> it out.  Let's say I got a data cube and I want to do something on
> just a slice of it, say I want to turn certain values in a column into
> something else:
>
> w = where( cube[1,*,*] lt 0 )
>
> It seems like you should be able to do something like this:
>
> cube[1,w] = 1e24
>
> But that doesn't work...  Somehow I can't quite figure out the right
> way to do this.

It's impossible for IDL to know the dimensionality of the original
array which from which you extracted a given set of elements. WHERE
simply gives you the zero-based running index into a given pile of
data, independent of its form and (much less) the form of the parent
array from which it was derived. So it's not at all surprising that
the returned set of indices doesn't "plug right in" in some convenient
way. The (likely) quickest solution in this case is the REFORM,/
OVERWRITE method given by Greg, since it doesn't actually copy any
data. But unfortunately, it's not at all general. For example,
suppose you had been interested in longitudinal slices instead, ala:

w=where(cube[*,1,*] lt 0)

A solution similar to Greg's would require first TRANSPOSE'ing the
cube such that the elements of the slice of interest could be put in
order along some dimension, e.g.:

w=where(cube[*,1,*] lt 0)
sz=size(cube,/dim)
cube=reform(transpose(cube,[0,2,1]),[sz[0]*sz[2],sz[1]])
cube[w,1]=1e24
cube=transpose(reform(cube,sz[0],sz[2],sz[1],/overwrite),[0, 2,1])

This obviously creates two transposed copies of the cube, which is
memory and CPU inefficient, not to mention difficult to remember. For
operating on small cubes, or a large fraction of the cube elements, it
might be reasonable. If, however, you have only a few elements to
access in a very large array (say just a sprinkling of negatives, in
your example), this would be very wasteful indeed.

In my opinion, a far better general solution to these sorts of
problems is to master the ability to recreate *yourself* any of the
index computations IDL does for you (and, by extension, any that it
doesn't). For example, when you write

slice = cube[1,*,*]

IDL doesn't just conjure the appropriate elements out of thin air. It
examines the dimensions of 'cube', and implicitly constructs a one-
dimensional index vector for all of the indices being referenced.
This happens in the background, but you can easily verify it by seeing
how much memory IDL has used for this temporary index vector. As a
side note, this can occasionally be memory inefficient, which is why
it's sometimes *preferable* to construct your own indices, even when
IDL could have done it for you (see http://www.dfanning.com/misc_tips/submemory.html).

As for the posed problem, let's skip to the end. In your example, the
answer looks like:

sz=size(cube,/DIMEN)
cube[1+sz[0]*(w mod sz[1] + w/sz[1]*sz[1])] = 1e24

Where does this come from? Your original cube "slice" has dimensions
[sz[1],sz[2]], and is at an x position of 1. Recall that

slice_col = w mod sz[1]

gives the column inside this slice, and

slice_row = w/sz[1]

gives the row. Nothing fancy there. If you forget these, you can
easily use the IDL provided convenience function ARRAY_INDICES
instead:

slice_col_row = array_indices(sz[1:2],w,/DIMENSIONS)

However, this is just doing the same pair of computations, which are
not that hard to remember.

So far so good. We need to create a one dimensional index vector
appropriate for the cube's dimensionality, ala (very generally):

ind = x + sx * (y + sy * z)

Now comes the (slightly) tricky bit. We need to do this *for the
selected slice elements*. But wait! The slice's column (x direction)
is the full cube's row (aka y direction), and the slice's row is the
full cube's plane (aka z direction). So what we need looks like:

ind = x + sx * (slice_col + sy * slice_row)

aka

ind = 1 + sz[0] * (w mod sz[1] + w/sz[1]*sz[1])

One other wrinkle. Notice I didn't write sz[1] * w/sz[1]. This is
because operator precedence would compute this as (sz[1]*w)/sz[1],
which would give you.... w -- not what you want. You can either write
sz[1]*(w/sz[1]), or just rearrange terms as I have done.

OK, you may be asking yourself, what has this really gained me? A
lot, actually. Once you become fluent in converting back and forth
between one-dimensional indices and [x,y,z,...] index sets in
arbitrary dimensions, you are able to manipulate with ease the full
range of indexing problems, and are, most importantly, no longer
reliant on IDL's convenient but limited higher-order indexing
operators. For example, suppose I had originally issued the call:

w=where(cube[1,5:*,10:1024] lt 0)

you should easily be able to generalize the above arguments to access
these elements.
Re: Using where() on slices of data cubes [message #68326 is a reply to message #68325] Tue, 20 October 2009 13:03 Go to previous messageGo to next message
David Fanning is currently offline  David Fanning
Messages: 11724
Registered: August 2001
Senior Member
Lajos writes:

>
> On Tue, 20 Oct 2009, Conor wrote:
>
>> I feel like this should be an easy one, but I've never quite figured
>> it out. Let's say I got a data cube and I want to do something on
>> just a slice of it, say I want to turn certain values in a column into
>> something else:
>>
>> w = where( cube[1,*,*] lt 0 )
>>
>> It seems like you should be able to do something like this:
>>
>> cube[1,w] = 1e24
>>
>> But that doesn't work... Somehow I can't quite figure out the right
>> way to do this.
>>
>
>
> cube[where(cube[1,*,*] lt 0)*(size(cube, /dim))[0]+1] = 1e24

Humm. Well, I suppose, for this *specific* problem. I can't
wait to see the general solution, though, for a slice in any
direction. Do you suppose it will fit on a page of paper? :-)

Cheers,

David
--
David Fanning, Ph.D.
Coyote's Guide to IDL Programming (www.dfanning.com)
Sepore ma de ni thui. ("Perhaps thou speakest truth.")
Re: Using where() on slices of data cubes [message #68327 is a reply to message #68326] Tue, 20 October 2009 07:26 Go to previous messageGo to next message
Foldy Lajos is currently offline  Foldy Lajos
Messages: 268
Registered: October 2001
Senior Member
On Tue, 20 Oct 2009, Conor wrote:

> I feel like this should be an easy one, but I've never quite figured
> it out. Let's say I got a data cube and I want to do something on
> just a slice of it, say I want to turn certain values in a column into
> something else:
>
> w = where( cube[1,*,*] lt 0 )
>
> It seems like you should be able to do something like this:
>
> cube[1,w] = 1e24
>
> But that doesn't work... Somehow I can't quite figure out the right
> way to do this.
>


cube[where(cube[1,*,*] lt 0)*(size(cube, /dim))[0]+1] = 1e24

regards,
lajos
Re: Using where() on slices of data cubes [message #68330 is a reply to message #68327] Tue, 20 October 2009 09:18 Go to previous messageGo to next message
greg.addr is currently offline  greg.addr
Messages: 160
Registered: May 2007
Senior Member
> Is'nt this more efficient ?
>   cube[1,*,*] = 1e24*(cube[1,*,*] lt 0) + cube[1,*,*]*(cube[1,*,*] ge
> 0)

I reckon you're copying out the slice twice, processing through it 5
times, and copying it back. That's compared to one scan through the
slice and one indexed substitution (possibly many fewer items than one
slice). The 'reform' with /overwrite costs nothing.

regards,
Greg
Re: Using where() on slices of data cubes [message #68331 is a reply to message #68327] Tue, 20 October 2009 08:00 Go to previous messageGo to next message
Paul Van Delst[1] is currently offline  Paul Van Delst[1]
Messages: 1157
Registered: April 2002
Senior Member
David Fanning wrote:
> Conor writes:
>
>> I feel like this should be an easy one, but I've never quite figured
>> it out. Let's say I got a data cube and I want to do something on
>> just a slice of it, say I want to turn certain values in a column into
>> something else:
>>
>> w = where( cube[1,*,*] lt 0 )
>>
>> It seems like you should be able to do something like this:
>>
>> cube[1,w] = 1e24
>>
>> But that doesn't work... Somehow I can't quite figure out the right
>> way to do this.
>
> It *seems* like there should be a simple way to do this,
> but if there is, I haven't found it. What would make
> sense to me is this:
>
> (cube[1,*,*])[w] = 1e24
>
> But this gives the error message that you can't store into
> a temporary variable. (The ol' pass by reference/pass by value
> thing, I suppose.)

Is it possible at all to use IDL pointer for aliasing? E.g. in Fortran I would do
something like the following

real, target :: cube(:,:,:)
real, pointer :: alias(:,:) => null()

alias => cube(1,:,:)

where ( alias < 0.0 )
alias = 1e24
end where

nullify(alias)


Is there an IDL equivalent to the "alias => cube(1,:,:)" statement in Fortran?

If there is, then that might get around the tired old "can't store into a temporary
variable" issue that plagues IDL due to it sticking to pass by reference only. (Man, I
wish they would fix that.)

The only way I can figure out to do the aliasing ends up copying the data.

Anyway...

cheers,

paulv
Re: Using where() on slices of data cubes [message #68333 is a reply to message #68327] Tue, 20 October 2009 07:39 Go to previous messageGo to next message
penteado is currently offline  penteado
Messages: 866
Registered: February 2018
Senior Member
Administrator
On Oct 20, 10:22 am, Conor <cmanc...@gmail.com> wrote:
> I feel like this should be an easy one, but I've never quite figured
> it out.  Let's say I got a data cube and I want to do something on
> just a slice of it, say I want to turn certain values in a column into
> something else:
>
> w = where( cube[1,*,*] lt 0 )
>
> It seems like you should be able to do something like this:
>
> cube[1,w] = 1e24
>
> But that doesn't work...  Somehow I can't quite figure out the right
> way to do this.

It does not apply to this case, but for future reference, it may be
useful to know that it could be done directly if the slice was the
other way around (a subset of indices on the left):

w=where(cube[*,*,i] lt 0)
nel=n_elements(cube[*,*,i])
cube[i*nel+w]=1e24
Re: Using where() on slices of data cubes [message #68334 is a reply to message #68327] Tue, 20 October 2009 07:34 Go to previous messageGo to next message
lecacheux.alain is currently offline  lecacheux.alain
Messages: 325
Registered: January 2008
Senior Member
> This method avoids the need for any duplication:
>
>   w=where(cube[1,*,*] lt 0)
>   sz=size(cube,/dim)
>   cube=reform(cube,[sz[0],sz[1]*sz[2]],/overwrite)
>   cube[1,w]=1e24
>   cube=reform(cube,sz,/overwrite)
>
> regards,
> Greg

Is'nt this more efficient ?
cube[1,*,*] = 1e24*(cube[1,*,*] lt 0) + cube[1,*,*]*(cube[1,*,*] ge
0)

alx.
Re: Using where() on slices of data cubes [message #68335 is a reply to message #68327] Tue, 20 October 2009 07:20 Go to previous messageGo to next message
greg.addr is currently offline  greg.addr
Messages: 160
Registered: May 2007
Senior Member
On 20 Okt., 14:22, Conor <cmanc...@gmail.com> wrote:
> I feel like this should be an easy one, but I've never quite figured
> it out.  Let's say I got a data cube and I want to do something on
> just a slice of it, say I want to turn certain values in a column into
> something else:
>
> w = where( cube[1,*,*] lt 0 )
>
> It seems like you should be able to do something like this:
>
> cube[1,w] = 1e24
>
> But that doesn't work...  Somehow I can't quite figure out the right
> way to do this.

This method avoids the need for any duplication:

w=where(cube[1,*,*] lt 0)
sz=size(cube,/dim)
cube=reform(cube,[sz[0],sz[1]*sz[2]],/overwrite)
cube[1,w]=1e24
cube=reform(cube,sz,/overwrite)

regards,
Greg
Re: Using where() on slices of data cubes [message #68342 is a reply to message #68335] Tue, 20 October 2009 06:20 Go to previous messageGo to next message
Conor is currently offline  Conor
Messages: 138
Registered: February 2007
Senior Member
Well it works, so I can't knock it that much :) I had resorted to
using a for loop :(

On Oct 20, 9:03 am, David Fanning <n...@dfanning.com> wrote:
> Conor writes:
>> I feel like this should be an easy one, but I've never quite figured
>> it out. Let's say I got a data cube and I want to do something on
>> just a slice of it, say I want to turn certain values in a column into
>> something else:
>
>> w = where( cube[1,*,*] lt 0 )
>
>> It seems like you should be able to do something like this:
>
>> cube[1,w] = 1e24
>
>> But that doesn't work... Somehow I can't quite figure out the right
>> way to do this.
>
> It *seems* like there should be a simple way to do this,
> but if there is, I haven't found it. What would make
> sense to me is this:
>
> (cube[1,*,*])[w] = 1e24
>
> But this gives the error message that you can't store into
> a temporary variable. (The ol' pass by reference/pass by value
> thing, I suppose.)
>
> I have always resorted to making a subset of the data, like
> this:
>
> sub = cube[1,*,*]
> w = where(sub lt 0)
> sub[w] = 1e24
> cube[1,*,*] = sub
>
> Not at all elegant, I admit. :-(
>
> Cheers,
>
> David
>
> --
> David Fanning, Ph.D.
> Fanning Software Consulting, Inc.
> Coyote's Guide to IDL Programming:http://www.dfanning.com/
> Sepore ma de ni thui. ("Perhaps thou speakest truth.")
Re: Using where() on slices of data cubes [message #68343 is a reply to message #68342] Tue, 20 October 2009 06:03 Go to previous messageGo to next message
David Fanning is currently offline  David Fanning
Messages: 11724
Registered: August 2001
Senior Member
Conor writes:

> I feel like this should be an easy one, but I've never quite figured
> it out. Let's say I got a data cube and I want to do something on
> just a slice of it, say I want to turn certain values in a column into
> something else:
>
> w = where( cube[1,*,*] lt 0 )
>
> It seems like you should be able to do something like this:
>
> cube[1,w] = 1e24
>
> But that doesn't work... Somehow I can't quite figure out the right
> way to do this.

It *seems* like there should be a simple way to do this,
but if there is, I haven't found it. What would make
sense to me is this:

(cube[1,*,*])[w] = 1e24

But this gives the error message that you can't store into
a temporary variable. (The ol' pass by reference/pass by value
thing, I suppose.)

I have always resorted to making a subset of the data, like
this:

sub = cube[1,*,*]
w = where(sub lt 0)
sub[w] = 1e24
cube[1,*,*] = sub

Not at all elegant, I admit. :-(

Cheers,

David



--
David Fanning, Ph.D.
Fanning Software Consulting, Inc.
Coyote's Guide to IDL Programming: http://www.dfanning.com/
Sepore ma de ni thui. ("Perhaps thou speakest truth.")
Re: Using where() on slices of data cubes [message #68464 is a reply to message #68324] Wed, 21 October 2009 14:52 Go to previous message
JDS is currently offline  JDS
Messages: 94
Registered: March 2009
Member
On Oct 20, 4:32 pm, David Fanning <n...@dfanning.com> wrote:
> JD Smith writes:
>> you should easily be able to generalize the above arguments to access
>> these elements
>
> I think in this case the word "easily" might be
> too subtly sarcastic to be easily appreciated by
> the vast majority of this newsgroup. :-)

(Almost) no sarcasm was intended.

Suppose you have this:

w=where(cube[1,5:*,10:1024] lt 0)

The "slice" is no longer as large as the cube in the yz dimensions,
and is offset by [5,10] too. So

y_full_cube = slice_column + 5
z_full_cube = slice_row + 10

and since the slice is smaller than the cube by 5 columns, to convert
our WHERE index vector w into col,row in the slice, we use

slice_column = w mod (sz[1]-5)
slice_row = w/(sz[1]-5)

Putting it all together we have:

ind = 1 + sz[0] * (5 + w mod (sz[1]-5) + (10 + w/(sz[1]-5)) * sz[1])

JD
  Switch to threaded view of this topic Create a new topic Submit Reply
Previous Topic: Rrun itools at breakpoint
Next Topic: Designating values to different ROIs in a single ROI file

-=] Back to Top [=-
[ Syndicate this forum (XML) ] [ RSS ] [ PDF ]

Current Time: Wed Oct 08 13:46:52 PDT 2025

Total time taken to generate the page: 0.14844 seconds