How to draw a line with an arrow in Plot.jl?

I wonder how to draw a line with an arrow in Plot.jl. The backend I use is GR, but any backend is OK to me. In the case of GnuPlot, it looks like set arrow 1 from 0,9 to 0,-9. Note, I do not mean I want to extend arrows from datapoints.

1 Like

Of course you can draw the arrows where you want just providing a different set of vectors than those of the data (as opposed to the example given).

There is also this:

plot!([0,0],[0,1.1],arrow=true,color=:black,linewidth=2,label="")

Actually that is what I used in this example:

Which produces:

2 Likes

thank you very much!

Hi @lmiq, I have a problem with arrows, which I know how to deal with in LaTeX but not in Julia.

The problem is this: usually if we want a connection between two points (both of which display a marker), the arrow overlaps a bit with the markers. In LaTeX we can say how much distance we want to be kept between the arrow and the marker by typing, e.g., shorten> = 0.09cm. Do you know how we can do this in Plots.jl? I have looked at the documentation, but there is no information about this issue.

An MWE that shows what I have in mind:

x = [1, 3 , NaN, 0.5, 1.0]
y = [1, 0.4,  NaN, 1.5, 0.8]
GR.setarrowsize(1)
plot(x,y, marker =:circle, arrow=(:closed, 2.0))

The output is

The overlapping between arrows and markers can be easily avoided in LaTeX, like this

In simple cases, the overlapping is not a big deal; but the overlapping is quite annoying in more elaborate plotting.

Thanks a lot.

2 Likes

I don’t know.

But if you are familiar with plotting in latex (I’m not), why not using pgfplots?

1 Like

Besides Plots.jl I also use PGFPlots.jl and PGFPlotsX.jl. The last two packages are wrappers for the pgfplots.sty package, and they quite good. However, the introduction of LaTeX raw code into these wrappers is not always that simple. PGFPlots is a larger wrapper but only allows for raw LaTeX code in the preamble (as far as I know), while PGFPlotsX is more flexible but has quite a smaller amount of plotting examples available in Julia. Using pgfplots.sty is not the best option if we are dealing with data or numerical analysis (optimization, dynamic processes, …), for example.

Thanks a lot.

1 Like

Would a display like here below be of your liking?

(i) with variable arrow head sizes:
arrows_bounded_by_circles_rg
or
(ii) with fixed arrow head sizes?
fixed_size_arrows_bounded_by_circles_rg

1 Like

@rafael.guerra that looks good. How do you do it? I tried this (overlapping still in):

x = [1, 3 , NaN, 0.5, 1.0]
y = [1, 0.4,  NaN, 1.5, 0.8]
#GR.setarrowsize(1)
plot(x,y, marker =:circle, arrow=true, arrowsize=0.5)
#arrow=(:closed, 2.0))

@VivMendes, please see code below which connects a sequence of dots by arrows without overlap, more in line with the Latex example you provided. The comments explain the different parameters.

If you have disconnected sequences, then need to run the code for each of them. One could write a function to handle that case if needed.

# Draw sequence of dots as circles connected by arrows without overlap

using LinearAlgebra, Plots; gr(legend=false)

# as: arrow head size 0-1 (fraction of arrow length; if <0 : use quiver with default constant size
# la: arrow alpha transparency 0-1
function arrow0!(x, y, u, v; as=0.07, lc=:black, la=1)  # by @rafael.guerra
    if as < 0
        quiver!([x],[y],quiver=([u],[v]), lc=lc, la=la)  # NB: better use quiver directly in vectorial mode
    else
        nuv = sqrt(u^2 + v^2)
        v1, v2 = [u;v] / nuv,  [-v;u] / nuv
        v4 = (3*v1 + v2)/3.1623  # sqrt(10) to get unit vector
        v5 = v4 - 2*(v4'*v2)*v2
        v4, v5 = as*nuv*v4, as*nuv*v5
        plot!([x,x+u], [y,y+v], lc=lc,la=la)
        plot!([x+u,x+u-v5[1]], [y+v,y+v-v5[2]], lc=lc, la=la)
        plot!([x+u,x+u-v4[1]], [y+v,y+v-v4[2]], lc=lc, la=la)
    end
end

function circleShape(x,y,r)   # by @lazarusA
    θ = LinRange(0,2π,72)
    x .+ r*sin.(θ), y .+ r*cos.(θ)
end

# support points (x,y) sorted in desired plotting order
x, y = [0.5, 1., 3.],  [1.5, 1.0, 0.4]
# compute full-length connecting vectors
u, v = diff(x), diff(y)

# define circle radius in plot units
cr = 0.025

# recompute vector lengths to not overlap the circles
lv = [norm([u,v]) for (u,v) in zip(u,v)]
lv0 = lv .- 2*cr
u0, v0 = u .* lv0./lv,  v .* lv0./lv

# recompute support points to start after circle
x0, y0 = x[1:end-1] .+ cr*u./lv,  y[1:end-1] .+ cr*v./lv

# plot data
plot()
for (x,y) in zip(x,y)
   display(plot!(circleShape(x,y,cr),seriestype=:shape,c=:blue,lw=0.1,lc=:blue,ratio=1,fill_alpha=0.5))
end
for (x,y,u,v) in zip(x0,y0,u0,v0)
    display(arrow0!(x, y, u, v; as=-0.07, lc=:blue, la=1)) # if as > 0, variable arrow head sizes
end

@rafael.guerra Thanks a lot. That will be very useful.

1 Like

@rafael.guerra It works, but your code seems to have been developed for version 0.6. In Julia 1.5 we need to add using LinearAlgebra; otherwise norm will not be defined.

1 Like

@VivMendes, sorry this and other key packages are defined in my Julia startup.jl, and so, they are pre-loaded when coding and overlooked (I am using Julia 1.6.0 on Win10). Edited code above. Thanks.

1 Like