Phase portrait with vector field

I’m trying to reformat a python code that plots a phase portrait with vector field. It seems that I did everything right, but the error is in the quiver () function. What did I write wrong?

Python code (working correctly):

# Phase portrait with vector field. Check two systems are the same.
import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import odeint
import pylab as pl

# The 2-dimensional linear system.
a, b, c, d = 2, 1, 1, 2
def dx_dt(x, t):
    return [a*x[0] + b*x[1], c*x[0] + d*x[1]]

# Trajectories in forward time.
ts = np.linspace(0, 4, 100)
ic = np.linspace(-1, 1, 5)
for r in ic:
    for s in ic:
        x0 = [r, s]
        xs = odeint(dx_dt, x0, ts)
        plt.plot(xs[:,0], xs[:,1], "r-")

# Trajectories in backward time.
ts = np.linspace(0, -4, 100)
ic = np.linspace(-1, 1, 5)
for r in ic:
    for s in ic:
        x0 = [r, s]
        xs = odeint(dx_dt, x0, ts)
        plt.plot(xs[:,0], xs[:,1], "r-")
        
# Label the axes and set fontsizes.
plt.xlabel("x", fontsize=15)
plt.ylabel("y", fontsize=15)
plt.tick_params(labelsize=15)
plt.xlim(-1, 1)
plt.ylim(-1, 1);

# Plot the vectorfield.

X,Y = np.mgrid[-1:1:10j, -1:1:10j]
u = a*X + b*Y
v = c*X + d*Y
pl.quiver(X, Y, u, v, color = "b")
plt.show()

Output which I want to get:
Снимок экрана 2023-05-10 045546

My Julia code:

using Plots
using SciPy
using LinearAlgebra
using DifferentialEquations

# The 2-dimensional linear system.
a, b, c, d = 2, 1, 1, 2

function dx_dt(du, u, p, t)
    du[1] = a*u[1] + b*u[2]
    du[2] = c*u[1] + d*u[2]
end

# Trajectories in forward time.
ts = LinRange(0, 4, 100)
ic = LinRange(-1, 1, 5)
tspan = (0.0, 4.0)

for r in ic
    for s in ic
        x0 = [r, s]
        xs = solve(ODEProblem(dx_dt, x0, tspan))
        Plots.plot(xs, color="red", linestyle="-")
        
    end
end

# Trajectories in backward time.
ts = LinRange(0, -4, 100)
ic = LinRange(-1, 1, 5)
tspan = (-4.0, 0.0)  

for r in ic
    for s in ic
        x0 = [r, s]
        xs = solve(ODEProblem(dx_dt, x0, tspan))
        Plots.plot(xs, color="red", linestyle="-")
    end
end
        
# Label the axes and set fontsizes.
xlabel!("x")
ylabel!("y")
#fontfamily("sans-serif")
#fontsize!(15)
xlims!(-1, 1)
ylims!(-1, 1)

# Plot the vectorfield.
function meshgrid(x, y)
    X = repeat(x', length(y), 1)
    Y = repeat(y, 1, length(x))
    return (X, Y)
end

x = range(-1, 1, length=10)
y = range(-1, 1, length=10)

a, b, c, d = 1, 1, -1, 1

X, Y = meshgrid(x, y)

u = a .* X .+ b .* Y
v = c .* X .+ d .* Y

quiver(X, Y, u, v, color="blue", alpha=0.5, aspect_ratio=:equal, framestyle=:box)```

My error: 

Couldn’t process recipe args: (Matrix{Float64}, Matrix{Float64}, Matrix{Float64}, Matrix{Float64})

It’s usually a mistake to make a “meshgrid” in julia…

quiver takes in 4 vectors, and has signature quiver(x, y, quiver = (u, v)). x and y are vectors of x-y coordinates. It will also accept a vector of 2-Tuples (each one being a point), or an Nx2 matrix. u and v must also be vectors, representing the x and y offset of each arrow in the quiver. You have all 4 being NxN matrices.

Given how you’ve set things up (with a meshgrid), you could recover the vectors you need by calling vec on x, y, u and v. In general though, it is better not to use a meshgrid in the first place and just iterate over the product of x and y with e.g. iterators.product(x, y), or using a nested for loop, or something similar.

Using vec, I get what I assume you were looking for:
quiver(vec(X), vec(Y), quiver=(vec(u), vec(v)), color="blue", alpha=0.5, aspect_ratio=:equal, framestyle=:box)

1 Like

Thank you very much, your answer saved me. Do you know why I don’t have the red lines of my plot displayed?

Not off the top of my head, because I haven’t gone over all of your code in detail. What I did notice is this:

  • you use Plots.plot repeatedly. Each of these makes a new plot. To add things to an existing plot, you need to use the plot! form (or quiver!, etc)
  • I don’t think linestyle="-" is something thats supported… not sure where you got that (I could be wrong about this though)

I suggest splitting this up and solving this one piece at a time. Make a plot with the red lines separately from the quiver, and combine once you figure out each piece.

1 Like