# Plot doesn't seem to evaluate my function

I've got a custom function I wrote and I'm trying to plot it. Actually, I'm trying to do an xy density plot but the density plot function was flat (all blue). So I'm trying to plot in a single variable to see what's going on, and the result is all zeroes.

However, when I evaluate my function at several points, none of them are zero. Here's some code showing my function being evaluated at several points vs what plot gives me. Any idea what's going on?

tags = []
for i in range(12):
for j in range(12):
tags.append((i*8, j*8, 3))

def getdist((x0,y0,z0),(x1,y1,z1)):
return sqrt((x1-x0)^2+(y1-y0)^2+(z1-z0)^2.)

def sum_of_distances((x,y,z), tags, maxdist):
cumdist = 0
for tag in tags:
dist = getdist((x,y,z), tag)
if dist <= maxdist:
cumdist = cumdist + dist
return cumdist

#this shows we have real numbers
for i in range(10):
print sum_of_distances((i,1,1), tags, 30)

#this just shows a y value of 0 (x is 0 to 10)
plot(sum_of_distances((x,1,1), tags, 30),(x,0,10))

edit retag close merge delete

Sort by » oldest newest most voted The problem is how binding works in Python. sum_of_distances is a Python function, so it's evaluated immediately. So your plot command is really equivalent to

onepoint = sum_of_distances((x,1,1), tags, 30)
plot(onepoint, (x, 0, 10))


And it so happens that:

sage: sum_of_distances((x,1,1), tags, 30)
0


because this requires testing whether (e.g.) sqrt(x^2+9) < 30, which returns false because Sage doesn't know how to prove it's true (and it's not in general, as x is a symbolic variable which could be anything), so cumdist stays at 0.

One way to get what you want is to use a lambda function to delay evaluation:

plot(lambda x: sum_of_distances((x,1,1), tags, 30),(0,10)) (BTW, you might be interested in CartesianProduct and in generator expressions-- they can simplify some code like this.)

more

Great! How do I properly create a 'sage.functions' class instead of a 'function'? Also, perhaps there should be a warning displayed when the plot function is used with a python function as an argument...this is a tricky nuance.

There's no way for us to tell the difference between sum_of_distances((x,1,1), tags, 30) and the return value (at least, without using the preparser), so a warning is probably not possible, or at least, very easy.

Wouldn't it be possible to have an overloaded plot function that behaved differently depending on the input type? When it received a sage class input type it would behave one way, when it received a function input type it would behave another way.

The problem is that the plot function _doesn't_ receive a function input type. It receives the value 0. It's an order-of-evaluation issue.

If I say f(x) = sum(k,k,0,x) and then f(2) y get 3, of course, but if I say g(x) = sum(binomial(10,k), k, 0,x) and then g(2), sage doesn't evaluate, just returns the definition with x replaced with 2. Why? Thanks

more