Plotting function returning complex vector

I have some functions which each return a constant n number of complex values, and would like to plot one as a series of lines on the complex plane. if I do something like
plot(real.([f.(0.1:.1:5)...;;]'),-imag.([f.(0.1:.1:5)...;;]'))
it technically does give me what I want, but then you lose the vertical axis being labeled as imaginary and the code is also kinda ugly. is there some way I can change the type of the functions or the call to get something more like plot(f, 0.1:.1:5)?

Here are some loose suggestions:

  • Add the labels manually plot(...; xlabel="Re(z)", ylabel="Im(z)")
  • Just extract the individual vectors of complex numbers and put it as single argument into individual plot! calls (that will draw the curve in the complex plane with automatic axis labels).
  • Write a custom plot function that does the above (this is probably what I would go for, since it also avoids calling the function f twice. Something like
function plot_complex_vector(f, u; kwargs...)
    results = f.(u)
    ...
    plot(...; kwargs...)
end
  • Write a plot recipe which is basically a function like the one above, but has a bit more standardized handling of extra kwargs etc. but also more overhead to write.
2 Likes

Wrangling data into larger arrays of the right dimensions in one-liners is always going to look a bit ugly and involve weird tricks like -imag...' for brevity. Sometimes a loop (that does more or less what Sevi suggests) is clearer.

What is the problem when using Plots.jl with:

t = 0.1:0.1:5
plot(f.(t))

# or if you need the conjugate:
plot(conj(f.(t)))

plot doesn’t seem to like that (roots() has same return type as my functions):

julia> using Plots, PolynomialRoots

julia> f(x) = roots([1,2,3,x])
f (generic function with 1 method)

julia> plot(f.(.1:.1:5))
ERROR: MethodError: no method matching isless(::Float64, ::ComplexF64)
The function `isless` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  isless(::Missing, ::Any)
   @ Base missing.jl:87
  isless(::Any, ::Missing)
   @ Base missing.jl:88
  isless(::AbstractFloat, ::SparseConnectivityTracer.GradientTracer)
   @ SparseConnectivityTracer ~/.julia/packages/SparseConnectivityTracer/YYCo5/src/overloads/gradient_tracer.jl:165
  ...

Stacktrace:
  [1] min(x::ComplexF64, y::Float64)
    @ Base ./operators.jl:499
  [2] expand_extrema!
    @ ~/.julia/packages/Plots/uiCPf/src/axes.jl:425 [inlined]
  [3] #113
    @ ~/.julia/packages/Plots/uiCPf/src/axes.jl:444 [inlined]
  [4] foreach
    @ ./abstractarray.jl:3187 [inlined]
  [5] expand_extrema!(axis::Plots.Axis, v::Vector{ComplexF64})
    @ Plots ~/.julia/packages/Plots/uiCPf/src/axes.jl:444
  [6] expand_extrema!(sp::Plots.Subplot{Plots.GRBackend}, plotattributes::RecipesPipeline.DefaultsDict)
    @ Plots ~/.julia/packages/Plots/uiCPf/src/axes.jl:479
  [7] _expand_subplot_extrema(sp::Plots.Subplot{Plots.GRBackend}, plotattributes::RecipesPipeline.DefaultsDict, st::Symbol)
    @ Plots ~/.julia/packages/Plots/uiCPf/src/pipeline.jl:433
  [8] add_series!(plt::Plots.Plot{Plots.GRBackend}, plotattributes::RecipesPipeline.DefaultsDict)
    @ Plots ~/.julia/packages/Plots/uiCPf/src/pipeline.jl:376
  [9] _process_seriesrecipe(plt::Any, plotattributes::Any)
    @ RecipesPipeline ~/.julia/packages/RecipesPipeline/BGM3l/src/series_recipe.jl:46
 [10] _process_seriesrecipes!(plt::Any, kw_list::Any)
    @ RecipesPipeline ~/.julia/packages/RecipesPipeline/BGM3l/src/series_recipe.jl:27
 [11] recipe_pipeline!(plt::Any, plotattributes::Any, args::Any)
    @ RecipesPipeline ~/.julia/packages/RecipesPipeline/BGM3l/src/RecipesPipeline.jl:99
 [12] _plot!(plt::Plots.Plot, plotattributes::Any, args::Any)
    @ Plots ~/.julia/packages/Plots/uiCPf/src/plot.jl:223
 [13] plot(args::Any; kw...)
    @ Plots ~/.julia/packages/Plots/uiCPf/src/plot.jl:102
 [14] plot(args::Any)
    @ Plots ~/.julia/packages/Plots/uiCPf/src/plot.jl:93
 [15] top-level scope
    @ REPL[3]:1

I’m currently stumbling my way through writing a plot recipe, so should prob mark Sevi’s answer as solution instead of just hearting it; but I’m obviously still open to other solutions if people want to throw them at me

The example doesn’t provide a vector of n-complex numbers, but a vector of vectors of complex numbers.
The following would plot all the roots:

scatter(reduce(vcat, f.(0.1:0.1:5)))

the function itself just returns a vector of complex numbers; the vector of vectorness comes from using the . to distribute through the range

Yeah, of course.