SciMLBase.jl icon indicating copy to clipboard operation
SciMLBase.jl copied to clipboard

Incorrect x-axis limits for solution plot w/ function of states

Open fabern opened this issue 4 years ago • 3 comments

Description When plotting an ODE solution using a function f such as in vars = (f,2,3) the x-axis is set on the range of the state variable corresponding to the first function argument, i.e. u[vars[2]]. However, it should rather be set based on the range of the actually plotted values, which depend on the return value of f.

Actual Behavior

using Plots, OrdinaryDiffEq

f(x,p,t) = p*x
prob = ODEProblem(f,[1.0,2.0,3.0],(0.0,1.0),-.2)
sol = solve(prob, Tsit5())

f4(y,z) = (y,z) # f4 keeps order
f5(z,y) = (y,z) # f5 inverts order
f6(t,x,y,z) = (y,z) # f6 has unused arguments

# Working as expected with x-axis range of [1.5, 2.2]:
plot(sol, vars = (2,3))                # CORRECT: x-axis range [1.5, 2.2] equal to range of u[2]
plot(sol, vars = (f4,2,3))             # CORRECT: x-axis range [1.5, 2.2] equal to range of u[2]

# Not working as expected:
plot(sol, vars = (f5,3,2))             # WRONG: x-axis range [2.3, 3.3] equal to range of u[3]
plot(sol, vars = (f6,0,1,2,3))         # WRONG: x-axis range [0, 1]     equal to range of time and label "t"
plot(sol, vars = [(f4,2,3), (f5,3,2)]) # WRONG: x-axis range [1.5, 3.3] equal to overall range of u[2] and u[3]

Expected Behavior Following statements should yield a plot with x-axis range [1.5, 2.2] and without axis label "t"

plot(sol, vars = (f5,3,2))             
plot(sol, vars = (f6,0,1,2,3))         
plot(sol, vars = [(f4,2,3), (f5,3,2)]) 

Related issues OPEN: https://github.com/SciML/DiffEqBase.jl/issues/591 CLOSED: https://github.com/SciML/DiffEqBase.jl/issues/35

Possible solution I pinpointed the behavior to the lines: https://github.com/SciML/SciMLBase.jl/blob/e44240ff63a0eae590ba25653ad1b164714585aa/src/solutions/solution_interface.jl#L204-L212

Instead one could use plot_vecs, which acutally gets printed. Something along the lines below. However, I'm unsure whether this breaks other use cases.

mins = minimum(plot_vecs[1])
maxs = maximum(plot_vecs[1])

fabern avatar Jun 02 '21 22:06 fabern

Yeah good point, that seems like it would be the correct thing to do.

ChrisRackauckas avatar Jun 02 '21 23:06 ChrisRackauckas

Actually there might be two ways to fix:

  • either set mins and maxs based on plot_vecs as mentioned at bottom of first post
  • or refrain from setting xlims in that case. [Untested. Would this work? Or does xlims need to be set in a Plotrecipe?]

fabern avatar Jun 03 '21 17:06 fabern

or refrain from setting xlims in that case. [Untested. Would this work? Or does xlims need to be set in a Plotrecipe?]

It would work. IIRC the reason why it was changed is because it gives no padding on the ends though.

ChrisRackauckas avatar Jun 03 '21 19:06 ChrisRackauckas