[SciPy-user] shape problem after flipud

Robert Kern robert.kern at gmail.com
Thu Jun 14 17:52:50 EDT 2007


Dominik Szczerba wrote:
> Thank you for a very helpful explanation. Please see below:
> 
> Robert Kern wrote:
>> Dominik Szczerba wrote:
>>> Hi,
>>>
>>> The following trivial codelet does not work as expected:
>>>
>>> -------------------------------
>>> from scipy import *
>>> import copy
>>>
>>> shape = (256,256)
>>> data = zeros(256*256)
>>> data.shape = shape
>>> print 'old shape', data.shape
>>> print data
>>>
>>> data=flipud(data)
>>> data.shape=(256*256,)
>>> print 'new shape', data.shape
>>> -------------------------------
>>>
>>> exiting with an uncomprehensive error:
>>>      data.shape=(256*256,)
>>> AttributeError: incompatible shape for a non-contiguous array
>>>
>>> If 'flipud' is ommited, it works as expected. I tried via a deepcopy, 
>>> the problem persists. Why should flipud invalidate 'reshapeability'?
>> Assigning to .shape only adjusts the strides. It does not change any of the
>> memory. It will only let you do that when the memory layout is consistent with
>> the desired shape. flipud() just gets a view on the original memory by using
>> different strides; the result is non-contiguous. The memory layout is no longer
>> consistent with the flattened view that you are requesting. Here is an example:
>>
>>   In [25]: data = arange(4)
>>
>> This is the layout in memory for 'data' and (later) 'd2':
>>
>>   In [26]: data
>>   Out[26]: array([0, 1, 2, 3])
>>
>>   In [29]: data.shape = (2, 2)
>>
>>   In [30]: data
>>   Out[30]:
>>   array([[0, 1],
>>          [2, 3]])
>>
>>   In [31]: d2 = flipud(data)
>>
>>   In [32]: d2
>>   Out[32]:
>>   array([[2, 3],
>>          [0, 1]])
>>
>> Calling .ravel() will copy the array if it is non-contiguous and will show you
>> the memory layout that 'd2' is mimicking with its strides.
> 
> quite a bit of a gotcha for a post-matlab user. deepcopy thing was 
> already not pleasant to swallow.

I don't recommend using deepcopy. Use reshape().

>>> What am I doing wrong?
>> You will want to use numpy.reshape() if you want the most foolproof and
>> idiomatic way to get a reshaped array. It will copy the array if necessary.
>>
>>   In [57]: reshape(d2, (4,))
>>   Out[57]: array([2, 3, 0, 1])
>>
> 
> This actually did not work:
> 
> shape = (256,256)
> data = zeros(256*256)
> data.shape = shape
> print 'old shape', data.shape
> print data
> data2 = flipud(data)
> data2.ravel()
> reshape(data2,(256*256,))
> print 'new shape', data2.shape
> 
> The shape is preserved! Even though I am fine with the previously given 
> solution, I am still curious what is wrong here.

It returns a (possibly new) object with the requested shape. It does not affect
the shape of the original array since it is not always possible to do that
safely. Assigning to .shape is the appropriate way to change the shape of an
existing array in-place if it is safe to do so. Two different ways to do two
different things.

> BTW> Why (size,) and not (size,1)?

Because they are different things. Not everything is a 2D array.

-- 
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
 that is made terrible by our own mad attempt to interpret it as though it had
 an underlying truth."
  -- Umberto Eco



More information about the SciPy-User mailing list