firas
firas

Reputation: 1503

SciPy conditional functions

I am currently learning SciPy and I want to play a little bit with pylab and matplotlib so as an exercise I tried to visualize Reddit's hot function.

Of course this code is not working, and I can't really figure out how to google what I want.

from pylab import *
import numpy as np

def f(t,v):
    y = lambda a : 1 if a > 0 else (-1 if a < 0 else 0)

    z = lambda a : log10(abs(a)) if abs(a) >= 1 else log10(1)

    return map(z,v)*map(y,v) + t

n = 256
x = np.linspace(0,100,n)
y = np.linspace(-50,+50,n)
X,Y = np.meshgrid(x,y)

contourf(X, Y, f(X,Y), 15, alpha=.75, cmap='jet')
C = contour(X, Y, f(X,Y), 15, colors='black', linewidth=.5)
show()

EDIT: By not working it means that it is giving me the following error message:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-33-a1d2f439ebda> in <module>()
     13 X,Y = np.meshgrid(x,y)
     14 
---> 15 contourf(X, Y, f(X,Y), 15, alpha=.75, cmap='jet')
     16 C = contour(X, Y, f(X,Y), 15, colors='black', linewidth=.5)
     17 show()

<ipython-input-33-a1d2f439ebda> in f(t, v)
      6     z = lambda a : log10(abs(a)) if abs(a) >= 1 else log10(1)
      7 
----> 8     return map(z,v)*map(y,v) + t
      9 
     10 n = 256

<ipython-input-33-a1d2f439ebda> in <lambda>(a)
      4     y = lambda a : 1 if a > 0 else (-1 if a < 0 else 0)
      5 
----> 6     z = lambda a : log10(abs(a)) if abs(a) >= 1 else log10(1)
      7 
      8     return map(z,v)*map(y,v) + t

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Upvotes: 0

Views: 193

Answers (1)

YXD
YXD

Reputation: 32521

The error is from if a > 0, as the error says the truth value of a, which will be a NumPy array is ambiguous.

Why is a a NumPy array rather than a single entry? Python's map does not iterate over each element of the array, it will iterate over one dimension only and your input is multidimensional:

>>> a = np.arange(12).reshape(3, 4)
>>> a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>> f = lambda x : x
>>> map(f, a)
[array([0, 1, 2, 3]), array([4, 5, 6, 7]), array([ 8,  9, 10, 11])]

You could use np.vectorize instead of map, which will work as you want, but you should really be using vectorized NumPy functions on NumPy arrays, where the iteration will be handled by fast native code. Here's how to write your code in this way:

import numpy as np
from pylab import *

def f(t,v):
    # reproduce "y" with vectorized functions
    temp_a = np.sign(v)

    # reproduce "z" with vectorized functions
    temp_b = np.log10(np.maximum(np.abs(v), 1.0))

    # could also do something like
    # abs_v = np.abs(v)
    # temp_b = np.where(abs_v >= 1, np.log10(abs_v), np.log10(1))

    return temp_a * temp_b + t

n = 256
x = np.linspace(0,100,n)
y = np.linspace(-50,+50,n)
X,Y = np.meshgrid(x,y)

contourf(X, Y, f(X,Y), 15, alpha=.75, cmap='jet')
C = contour(X, Y, f(X,Y), 15, colors='black', linewidth=.5)
show()

Recommended reading:

I would also suggest not using pylab but importing the modules you need explicitly. e.g. here you would do import matplotlib.pyplot as plt and use plt.contour and plt.show(). See Pylab discussion here and here.

Upvotes: 2

Related Questions