Search code examples
functionplotjuliasurface

Function and surface plot Julia


I want to plot a function using surface in Julia. I manage to plot te desired function:

x = 0:0.1:4
y = 0:0.1:4
f(x,y) = x^0.2 * y^0.8
surface(x, y, f, camera=(10,30),linealpha=0.3, fc=:heat)

However, I would f(*) to be a proper function over which I could also optimize (e.g. utility maximisation in economics). This is my attempt:

function Utility(x1, x2)
    u= x.^0.2 .* y.^0.8
    return u
end

But it unfortunately does not work. Can anybody help me?

Best

Daniel


Solution

  • I think Benoit's comment really should be the answer, but let me expand a little bit.

    First of all, an inline function definition is not any different from a multi-line function definiton (see the first two examples in the docs here). Therefore, doing

    utility(x, y) = x^0.2 * y^0.8
    

    will give you a function that works exactly like

    function utility(x, y)
        x^0.2 * y^0.8
    end
    

    However, your Utility function is actually different from your f function - you are defining it with the arguments x1 and x2, but in the function body you are using y rather than x2.

    This would ordinarily raise an undefined variable error, except that in the code snippet you posted, y is already defined in global scope as the range 0:0.1:4, so the function will use this:

    julia> y = 0:0.1:4
    0.0:0.1:4.0
    
    julia> u(x1, x2) = x1 .^ 0.2 * y .^ 0.8
    u (generic function with 1 method)
    
    julia> u(2.0, 0.0)
    41-element Array{Float64,1}:
     0.0
     0.18205642030260805
     0.3169786384922227
    ...
    

    this is also where your introduction of broadcasting in the Utility function (the second difference between your two examples as Benoit pointed out) comes back to haunt you: calling the function while relying on it to use the global variable y would error immediately without broadcasting (as you can't exponentiate a range):

    julia> u2(x1, x2) = x1^0.2 * y^0.8
    u2 (generic function with 1 method)
    
    julia> u2(2.0, 0.0)
    ERROR: MethodError: no method matching ^(::StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}, ::Float64)
    

    with broadcasting, however, this exponentiation works and returns the full range, with every element of the range exponentiated. Thus, your function returns an array rather than a single number (as you can see above from my call to u(2.0, 0.0). This is what Plots complains about - it doesn't know how to plot an array, when it expects to just be plotting a single data point.