Easy way to plot a circle given as a vector of vectors (pointwise) as line plot?

Is there an easier way to plot a shape (in geometric sense, not Plots.jl’s) given as a vector of points (i.e. 2D-vectors)?

using Plots

# approximately a circle
vector_of_points = [[0.708441362115303, 1.413585198669223],
[1.0185589103132255, 1.557842996204574],
[1.3488474334102414, 1.4690134256250358],
[1.5447662714075574, 1.188657163943744],
[1.5146337337537332, 0.8479675075866541],
[1.2725600518547597, 0.6063407865330036],
[0.9318084528866316, 0.5768437043492579],
[0.6518197911665652, 0.7732820990802726],
[0.5636046347857182, 1.1037378826491369],
[0.7084413621153031, 1.4135851986692225]]

# convert to matrix
matrix_of_point = stack(vector_of_points)

# disassemble the matrix to arguments and values
x = matrix_of_point[1, :]
y = matrix_of_point[2, :]

# almost a circle
plot(x, y)

sure, plot(x, y, seriestype = :shape) should do the trick.

Thanks! This function call creates a filled shape, which is not what I’m looking for.

Probably, I should reformulate my question:

1. given a vector of vectors,
2. how to plot a line plot
3. without the steps converting the vector of vectors into a matrix and
4. then disassembling (be it stack, comprehension, or whatever else) it into x and y arguments what plot(x, y) expects?

This kinda looks like a promise that such simple plotting should be possible:

Part of the power of Plots lies is in the many combinations of allowed input data. You shouldn’t spend your time transforming and massaging your data into a specific format.

Here is one method:

using MappedArrays

# vector_of_points defined as in OP

xvec = mappedarray(first, vector_of_points)
yvec = mappedarray(last, vector_of_points)

plot(xvec, yvec)
1 Like

Are you looking for a Plots.jl-specific answer?

If you can use other plotting packages, check Makie.jl and the linesegments function. If you are doing geometric processing work, check Meshes.jl as it can plot all sorts of geometries using Makie.jl.

2 Likes

Thanks! This definitely saves from some boilerplate.

I chose Plots.jl because it’s the most popular one. I’ll have a look on Maki-e. Thanks!

Vector{Vector} is a relatively uncommon type in Julia for geometry because it’s relatively inefficient with all the pointers, so I’m not surprised you don’t find specific dispatches for it. I’m not sure if Makie, which was mentioned above, converts this signature to points. I’m only aware of Tuples and SVectors and Points which are bits types, so store contiguously in memory.

2 Likes

The simplest way to plot a line fron vect_points:

using Plots
plot(getindex.(vect_points,1), getindex.(vect_points, 2)

or first.( and last.( if you know there are only two elements each

2 Likes

Yes, exactly. Plots tries to digest all sensible types, but the issue is that a vector of vectors is understood in Plots as multiple series (and that use is often very convenient). What kind of process or function does your vector of vectors derive from? It seems unusual, because a vector does not guarantee it will have a length of two, and pushing to any one of the vectors would break the inference as points.
Making the vectors static would give the behaviour you want.

Applying an ODE solver to a list of initial conditions, each given as a vector:

function flow(ic)
tspan = (0.0, 1.0)
prob = ODEProblem(problem!, ic, tspan)
sol = solve(prob, Euler(), dt=0.1)
last = sol.u[end]
return last
end

flow.(list_of_ics)

Unfortunately, Makie also fails in this task:

ERROR: `Makie.convert_arguments` for the plot type LineSegments{Tuple{Vector{Vector{Float64}}}} and its conversion trait PointBased() was unsuccessful.

The signature that could not be converted was:
::Vector{Vector{Float64}}

As @jules explained, you need to convert the dynamic vectors to static vectors or tuples before you plot. Try Tuple.(vectors) for example.

1 Like

Thanks!

The recipe would be

Makie.convert_arguments(P::PointBased, m::Vector{Vector{Float64}}) = convert_arguments(P, Tuple.(m))

Thanks for the explanation!