Ask Your Question

Plot doesn't seem to evaluate my function

asked 2011-11-24 00:30:38 +0100

Jason gravatar image

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 flag offensive close merge delete

2 Answers

Sort by ยป oldest newest most voted

answered 2011-11-24 09:46:01 +0100

DSM gravatar image

updated 2011-11-24 09:46:51 +0100

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)

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))

image description

(BTW, you might be interested in CartesianProduct and in generator expressions-- they can simplify some code like this.)

edit flag offensive delete link 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.

Jason gravatar imageJason ( 2011-11-24 18:12:21 +0100 )edit

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.

Jason Grout gravatar imageJason Grout ( 2011-11-25 01:15:19 +0100 )edit

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.

Jason gravatar imageJason ( 2011-11-30 16:21:24 +0100 )edit

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.

DSM gravatar imageDSM ( 2011-11-30 17:11:50 +0100 )edit

answered 2015-10-14 15:45:24 +0100

mariopablo gravatar image

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

edit flag offensive delete link more


That's a bug that already has a fix which just needs to be reviewed:

rws gravatar imagerws ( 2015-10-14 15:52:53 +0100 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools


Asked: 2011-11-24 00:30:38 +0100

Seen: 728 times

Last updated: Oct 14 '15