# Adding nullclines to a streamplot

Hello there,

I’m still extremely new to Julia and I’m currently trying to plot both the flow of an autonomous system of linear ODEs + their corresponding nullclines. The flow itself I’m using -

using Makie
using CairoMakie; cm = CairoMakie

odeSol(x,y) = Point(y - x^2 + 2, x*y - y^2) #x(t)' = ..., y(t)' = ...
scene = cm.Scene(size =(500,500))
cm.streamplot!(scene, odeSol, -5..5, -5..5,
backgroundcolor = :black, colormap = cm.Reverse(:plasma),
gridsize= (30,30), arrow_size = 0.1)

save("odeField.png", scene)


Is there some sophisticated way to add the nullclines here that I should be using?

Thank you in advance a lot.

Something like this should do the trick:

using CairoMakie
fig = Figure()
fx(x,y) = y - x^2 + 2
fy(x,y) = x*y - y^2
odeSol(x,y) = Point2(fx(x,y), fy(x,y)) #x(t)' = ..., y(t)' = ...
ax = Makie.Axis(fig[1,1])
streamplot!(ax, odeSol, -5..5, -5..5,
backgroundcolor = :black, colormap = cm.Reverse(:plasma),
gridsize= (30,30), arrow_size = 0.1)

xs = range(-5, 5; length = 201)
ys = range(-5, 5; length = 201)

FX = [fx(x,y) for x ∈ xs, y ∈ ys]
FY = [fy(x,y) for x ∈ xs, y ∈ ys]

contour!(ax, xs, ys, FX; levels = [0.0], color = :black)
contour!(ax, xs, ys, FY; levels = [0.0], color = :gray, linestyle = :dash)
fig

save("odeField.png", fig)


1 Like

Thank you a lot! I’ve added some minor aesthetic changes as well

using CairoMakie; cm = CairoMakie
using LaTeXStrings

fig = cm.Figure()
fx(x,y) = y - x^2 + 2
fy(x,y) = x*y - y^2
odeSol(x,y) = Point2(fx(x,y), fy(x,y)) #x(t)' = ..., y(t)' = ...
ax = Makie.Axis(fig[1,1],
xlabel = "X",
ylabel = "Y",
title = "Nullclines and ODE flow field.")
cm.streamplot!(ax, odeSol, -5..5, -5..5,
colormap = :grays, alpha = 0.2,
gridsize= (30,30), arrow_size = 0.1)

xs = range(-5, 5; length = 201)
ys = range(-5, 5; length = 201)

FX = [fx(x,y) for x ∈ xs, y ∈ ys]
FY = [fy(x,y) for x ∈ xs, y ∈ ys]

cm.contour!(ax, xs, ys, FX; levels = [0.0], color = :blue, linestyle = :dash,
linewidth = 2, label = L"\frac{dx}{dt} = 0")
cm.contour!(ax, xs, ys, FY; levels = [0.0], color = :orange, linestyle = :dash,
linewidth = 2, label = L"\frac{dy}{dt} = 0")
cm.axislegend(ax)
fig

save("odeField.png", fig)


Would you know how to fix the legend so that it displays the colours assigned to the contour lines?

I think for contourlines you have to manually specify the legend entries (not, sure, but the below code does work)

using CairoMakie; cm = CairoMakie
using LaTeXStrings

fig = cm.Figure()
fx(x,y) = y - x^2 + 2
fy(x,y) = x*y - y^2
odeSol(x,y) = Point2(fx(x,y), fy(x,y)) #x(t)' = ..., y(t)' = ...
ax = Makie.Axis(fig[1,1],
xlabel = "X",
ylabel = "Y",
title = "Nullclines and ODE flow field.")
cm.streamplot!(ax, odeSol, -5..5, -5..5,
colormap = :grays, alpha = 0.2,
gridsize= (30,30), arrow_size = 0.1)

xs = range(-5, 5; length = 201)
ys = range(-5, 5; length = 201)

FX = [fx(x,y) for x ∈ xs, y ∈ ys]
FY = [fy(x,y) for x ∈ xs, y ∈ ys]

cm.contour!(ax, xs, ys, FX; levels = [0.0], color = :blue, linestyle = :dash,
linewidth = 2, label = L"\frac{dx}{dt} = 0")
cm.contour!(ax, xs, ys, FY; levels = [0.0], color = :orange, linestyle = :dash,
linewidth = 2, label = L"\frac{dy}{dt} = 0")

leg_elems = [
LineElement(color = :blue, linestyle = :dash),
LineElement(color = :orange, linestyle = :dash)
]
leg_strs = [
L"\frac{dx}{dt} = 0",
L"\frac{dy}{dt} = 0"
]

Legend(fig[1,1], leg_elems, leg_strs;
halign = :right,
valign = :top,
tellwidth = false,
tellheight = false
)
fig

1 Like

Thanks a lot, this is perfect.