Modify plot outside of function where created

I have a function below which can accept scalars or arrays. (It seemed easier to write the code to work with both input types rather than creating separate methods. I will gladly accept tips on that too.) It returns a numerical result and a plot. My issue is that I would like the user to be able to modify the plot legend, title, etc. after it returns from the function. The code below doesn’t have any errors, but the second plot call doesn’t seem to do anything. I came up with two fixes which I think will work, but I’m not really happy with either. Hoping someone here will have some tips.

  1. Pass the plot attributes as arguments to the function.
    The plot is just a byproduct of the function, and I don’t want the user to have to be concerned with the plotting attributes if they don’t want to be. For example, the user wouldn’t need a legend at all if they are just passing scalars into the function.

  2. Return the plot handle from the function along with the numerical result.
    Now the user has to deal with a tuple rather than the simple numerical value they expect.

#Computes tangent modulus from the yield point and a point in the plastic region.
using Plots

#Function Definition
function computetangentmodulus(ϵy,σy,ϵp=0.2,σp=0.05.*σy)

    #Check Inputs
    if length(ϵy)!=length(σy)
        throw(ArgumentError("input arrays must be the same size"))
    else
        arglength=length(ϵy)
    end
    
    #Compute Output
    tm=σp./ϵp

    #Create Plot
    display(plot([zeros(arglength)';vec(ϵy)';vec(ϵy.+ϵp)'],[zeros(arglength)';vec(σy)';vec(σy.+σp)']
        ,label=""
        ,title="Bilinear Hardening Allowed for FEA Stability"
        ,xlabel="Strain [in/in]"
        ,ylabel="Stress [psi]"))

    return tm
end

#User Inputs
σy=[120 115.2 112.2 110.3 108.8 106.7 105.2 103.2 100.8 97.9]
E=[2.78E+07 2.71E+07 2.67E+07 2.62E+07 2.57E+07 2.51E+07 2.49E+07 2.46E+07 2.43E+07 2.39E+07]
ϵy=σy./E

#User Function Call
tm=computetangentmodulus(ϵy,σy)

#User Plot Modification
T=[70 200 300 400 500 600 650 700 750 800]
display(plot!(label=permutedims(string.(T))))

#Display Result
clearconsole()
println("Tangent Modulus:")
println.(tm)

I’m not sure if this is the solution, but you can try using the function current() exported by Plots.jl, to query or set the “current plot” inside the function.

1 Like

I am not sure one can set the labels after the fact, even if one has the plot handle (please correct me if I’m wrong!). But you can set other attributes (e.g. title) without the plot handle. MWE:

function p1()
    p = plot(1:10, 1:10, lab = "a");
    return p
end

p = p1()
# Works
title!("Title")
# Works
plot!(1:10, 2:11, lab = "b")
# Does nothing
plot!(p, labels = ["aaa" "bbb"])
1 Like

Oh, okay! I confirmed with my code that I am able to update everything but the series labels. I previously assumed this was a scoping issue.

If the labels do need to be added at the same time as the data, then I suppose my only choice is to pass labels as a keyword argument to the function?

I think so. This might be worth an filing an issue, asking for a labels! function.

1 Like

I filed an issue with Plots.jl here.