Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Level sets of a function using "min"

UPDATE

To summarize my initial post below, I have difficulties plotting level sets of functions involving 'min' such as the following function :

def f(x,y):
   return min(x,x-y,x**2,y+1)

Code I'm using to plot level sets is :

import matplotlib.pyplot as plt
import numpy as np

plt.ion()
x_ = np.linspace(-180,180,num=40)
y_ = np.linspace(-180,180,num=40)
x,y = np.meshgrid(x_,y_)
levels = f(x,y)
c = plt.contour(x,y,levels,50)
plt.colorbar()
plt.show()

which works fine for a function involving regular arithmetic operations (+,-,**,*,/). Using function f, I have this error :

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

pointing at the return line of f. How can I plot the level sets of my function f ?


INITIAL POST

I'm trying to plot level sets of two functions f1 and f2 defined as follows :

A = -73.95, 48.73
L=180


######## f1
def distance(a,b):
      """ a and b tuples """
      return np.sqrt((a[0]-b[0])**2+(a[1]-b[1])**2)

def f1(x,y):
       """ simple distance """
       p = x,y
       #print p
       return distance(p,A)

######## f2
def images(p):
        """ p tuple """
        #print "len(p) in images : "+str(len(p))+"\n"
        #print p
        pHC = (p[0],p[1]+L)
        pHR = (p[0]+L,p[1]+L)
        pHL = (p[0]-L,p[1]+L)
        pCR = (p[0]+L,p[1])
        pCL = (p[0]-L,p[1])
        pDC = (p[0],p[1]-L)
        pDR = (p[0]+L,p[1]-L)
        pDL = (p[0]-L,p[1]-L)
        return pHC,pHR,pHL,pCR,pCL,pDC,pDR,pDL
def minD(p,focal):
        """
        distance with images (p and focal are tuples)
        """
        #print p
        pHC,pHR,pHL,pCR,pCL,pDC,pDR,pDL = images(p)
        dHC = distance(focal,pHC)
        dHR = distance(focal,pHR)
        dHL = distance(focal,pHL)
        dCR = distance(focal,pCR)
        dCL = distance(focal,pCL)
        dDC = distance(focal,pDC)
        dDR = distance(focal,pDR)
        #print "len(dHC) : "+str(len(dHC))
        #print "len(dHC[0]) : "+str(len(dHC[0]))
        #print dHC
        d = min([dHC,dHR,dHL,dCR,dCL,dDC,dDR,dDL,distance(p,focal)])
        return d

def f2(phi,psi):
       p = phi,psi
       return minD(p,A)

Here's my code for plotting level sets :

import matplotlib.pyplot as plt
import numpy as np

plt.ion()
x_ = np.linspace(-180,180,num=40)
y_ = np.linspace(-180,180,num=40)
x,y = np.meshgrid(x_,y_)
levels1 = f1(x,y)
#levels2 = f2(x,y)
c = plt.contour(x,y,levels,50)
#c = plt.contour(x,y,levels2,50)
plt.colorbar()
plt.show()

My plot seems to be correct with the function f1 (at least there's no code errors). However, with function f2, I have an error at the line before the last of minD :

    d = min([dHC,dHR,dHL,dCR,dCL,dDC,dDR,dDL,distance(p,focal)])
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

With some prints, I could find that the elements of the list on which I perform the min (in minD function) are arrays in the case of f2 and not single elements as for f1. How can I plot level sets of function f2 ?

like image 709
dada Avatar asked Dec 20 '25 21:12

dada


1 Answers

You want to call the numpy version of min, not python's version which is expecting numbers as an input and gives you the minimum of them--this is where the ValueError comes from. There are two version in numpy; np.min and np.minimum. np.min will give you the minimum value of an array (so a number) and np.minimum will do a point-wise minimum of the array (so another array). You want the latter.

Unfortunately, I don't think you can simply do np.minimum(array1, array2, array3) like to have above, so I think you need to nest the np.minimum calls. Though if will do this often, I think you can create a function that will nest these calls for you to make it easier to read. This is what I got and it seems to work:

def f(x,y):
    return np.minimum(np.minimum(np.minimum(x,x-y),x**2),y+1)

plt.figure()

x_ = np.linspace(-180, 180, num=200)
y_ = np.linspace(-180, 180, num=200)
x,y = np.meshgrid(x_, y_)

levels = f(x, y)

c = plt.contour(x, y, levels, 50)
plt.colorbar()

This yields:

enter image description here

(note, I increased num from 40 to 200 to help matplotlib with the non-smooth parts)

like image 112
breeden Avatar answered Dec 23 '25 13:12

breeden