logical statements (in Python and Numeric)
Fernando PĂ©rez
fperez528 at yahoo.com
Thu Jun 20 13:15:13 EDT 2002
Nathan Given wrote:
> I am graphing piecewise functions, and I have a method of getting the
> proper y values in a vector that works in MATLAB... I was trying to get
> it to work in Python, but it wasn't...
>
> it has to do with a using an and statement...
>
>
> here is my code...
>
> x = arrayrange(-4.,2.+.001,.001, Float)
> y = zeros(len(x),Float)
>
> #------ Create Piecewise Function ------#
> y = y + (x < -2)*(((x + 2.)**2) + 4)
> y = y + (x >= -2. and x < 0.) * (x + 6.)
> y = y + (x >=0) * (x ** 2. + 6.)
>
I agree that the above failure is bloody counterintuitive, to the point where
I'd call it a bug. It's easy to illustrate with:
In [58]: a=arange(12)
In [59]: a > 5 and a < 8
Out[59]: array([1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0])
What you need to use is logical_and():
In [60]: logical_and(a>5,a<8)
Out[60]: array([0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0])
You may consider posting to the Numeric mailing list about this. The 'and'
operator should either not work at all or work correctly. The above is a
heinous behavior.
But at least you can use the logical_* functions to get around the problem.
Your code would then read:
In [49]: x = arrayrange(-4.,2.+.001,.001, Float)
In [50]: y = zeros(len(x),Float)
In [51]: y += (x < -2)*(((x + 2.)**2) + 4)
In [52]: y += logical_and(x>=-2,x<0) * (x+6)
In [53]: y += (x >=0) * (x ** 2. + 6.)
Note the '+=' operator, if I recall correctly it works in-place for Numeric
arrays, which has memory benefits (significant for large arrays).
For common range creation with a closed interval, I wrote the following
function which I use constantly. Feel free to use it if you like it. The npts
optional argument is especially useful, since you often care more about the
particular size of the list rather than the specific value of delta.
def frange(xini,xfin=None,delta=None,**kw):
"""frange([start,] stop[, step, keywords]) -> list of floats
Return a Numeric array() containing a progression of floats. Similar to
arange(), but defaults to a closed interval.
frange(x0, x1) returns [x0, x0+1, x0+2, ..., x1]; start defaults to 0, and
the endpoint *is included*. This behavior is different from that of
range() and arange(). This is deliberate, since frange will probably be
more useful for generating lists of points for function evaluation, and
endpoints are often desired in this use. The usual behavior of range() can
be obtained by setting the keyword 'closed=0', in this case frange()
basically becomes arange().
When step is given, it specifies the increment (or decrement). All
arguments can be floating point numbers.
frange(x0,x1,d) returns [x0,x0+d,x0+2d,...,xfin] where xfin<=x1.
frange can also be called with the keyword 'npts'. This sets the number of
points the list should contain (and overrides the value 'step' might have
been given). arange() doesn't offer this option.
Examples:
>>> frange(3)
array([ 0., 1., 2., 3.])
>>> frange(3,closed=0)
array([ 0., 1., 2.])
>>> frange(1,6,2)
array([1, 3, 5])
>>> frange(1,6.5,npts=5)
array([ 1. , 2.375, 3.75 , 5.125, 6.5 ])
"""
#defaults
kw.setdefault('closed',1)
endpoint = kw['closed'] != 0
# funny logic to allow the *first* argument to be optional (like range())
# This was modified with a simpler version from a similar frange() found
# at http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66472
if xfin == None:
xfin = xini + 0.0
xini = 0.0
if delta == None:
delta = 1.0
# compute # of points, spacing and return final list
try:
npts=kw['npts']
delta=(xfin-xini)/float(npts-endpoint)
except KeyError:
npts=int((xfin-xini)/delta+endpoint)
return arange(npts)*delta+xini
If you want to be able to plot with gnuplot a single array with g.plot(y), or
y vs x with g.plot(x,y), ask me for a modified version I have, which also
fixes the problems with hardcopy(). It's part of ipython
(http://windom.colorado.edu/~fperez/ipython/) which gives you a python shell
which feels much like that of IDL or Mathematica.
Cheers,
f.
More information about the Python-list
mailing list