Julia Plotting: delete and modify existing lines
Asked Answered
B

3

8

Two questions in one: Given a line plotted in Julia, how can I

  1. delete it from the plot and legend (without clearing the whole plot)
  2. change its properties (such as color, thickness, opacity)

As a concrete example in the code below, how can I 1. delete previous regression lines OR 2. change their opacity to 0.1?

using Plots; gr()

f = x->.3x+.2
g = x->f(x)+.2*randn()

x = rand(2)
y = g.(x)
plt = scatter(x,y,c=:orange)
plot!(0:.1:1, f, ylim=(0,1), c=:green, alpha=.3, linewidth=10)

anim = Animation()
for i=1:200
    r = rand()
    x_new, y_new = r, g(r)
    push!(plt, x_new, y_new)
    push!(x, x_new)
    push!(y, y_new)
    A = hcat(fill(1., size(x)), x)
    coefs = A\y
    plot!(0:.1:1, x->coefs[2]*x+coefs[1], c=:blue)  # plot new regression line
    # 1. delete previous line
    # 2. set alpha of previous line to .1
    frame(anim)
end
gif(anim, "regression.gif", fps=5)

I tried combinations of delete, pop! and remove but without success. A related question in Python can be found here: How to remove lines in a Matplotlib plot

regression

Balsamiferous answered 7/9, 2019 at 1:13 Comment(0)
Y
5

Here is a fun and illustrative example of how you can use pop!() to undo plotting in Julia using Makie. Note that you will see this goes back in the reverse order that everything was plotted (think, like adding and removing from a stack), so deleteat!(scene.plots, ind) will still be necessary to remove a plot at a specific index.


using Makie

x = range(0, stop = 2pi, length = 80)
f1(x) = sin.(x)
f2(x) = exp.(-x) .* cos.(2pi*x)
y1 = f1(x)
y2 = f2(x)

scene = lines(x, y1, color = :blue)
scatter!(scene, x, y1, color = :red, markersize = 0.1)

lines!(scene, x, y2, color = :black)
scatter!(scene, x, y2, color = :green, marker = :utriangle, markersize = 0.1)

display(scene)

Inital plot

sleep(10)
pop!(scene.plots)
display(scene)

2nd image

sleep(10)
pop!(scene.plots)
display(scene)

3rd picture

You can see the images above that show how the plot progressively gets undone using pop(). The key idea with respect to sleep() is that if we were not using it (and you can test this on your own by running the code with it removed), the fist and only image shown on the screen will be the final image above because of the render time.

You can see if you run this code that the window renders and then sleeps for 10 seconds (in order to give it time to render) and then uses pop!() to step back through the plot.

Docs for sleep()

York answered 18/9, 2019 at 3:38 Comment(0)
B
5

I have to say that I don't know what the formal way is to accomplish them.

There is a cheating method.

plt.series_list stores all the plots (line, scatter...).
If you have 200 lines in the plot, then length(plt.series_list) will be 200.

plt.series_list[1].plotattributes returns a dictionary containing attributes for the first line(or scatter plot, depends on the order).

One of the attributes is :linealpha, and we can use it to modify the transparency of a line or let it disappear.

# your code ...

plot!(0:.1:1, x->coefs[2]*x+coefs[1], c=:blue)  # plot new regression line

# modify the alpha value of the previous line
if i > 1
    plt.series_list[end-1][:linealpha] = 0.1
end

# make the previous line invisible
if i > 2
    plt.series_list[end-2][:linealpha] = 0.0
end

frame(anim)
# your code ...
Barnstorm answered 7/9, 2019 at 19:43 Comment(0)
Y
5

Here is a fun and illustrative example of how you can use pop!() to undo plotting in Julia using Makie. Note that you will see this goes back in the reverse order that everything was plotted (think, like adding and removing from a stack), so deleteat!(scene.plots, ind) will still be necessary to remove a plot at a specific index.


using Makie

x = range(0, stop = 2pi, length = 80)
f1(x) = sin.(x)
f2(x) = exp.(-x) .* cos.(2pi*x)
y1 = f1(x)
y2 = f2(x)

scene = lines(x, y1, color = :blue)
scatter!(scene, x, y1, color = :red, markersize = 0.1)

lines!(scene, x, y2, color = :black)
scatter!(scene, x, y2, color = :green, marker = :utriangle, markersize = 0.1)

display(scene)

Inital plot

sleep(10)
pop!(scene.plots)
display(scene)

2nd image

sleep(10)
pop!(scene.plots)
display(scene)

3rd picture

You can see the images above that show how the plot progressively gets undone using pop(). The key idea with respect to sleep() is that if we were not using it (and you can test this on your own by running the code with it removed), the fist and only image shown on the screen will be the final image above because of the render time.

You can see if you run this code that the window renders and then sleeps for 10 seconds (in order to give it time to render) and then uses pop!() to step back through the plot.

Docs for sleep()

York answered 18/9, 2019 at 3:38 Comment(0)
T
3

You cannot do that with the Plots package. Even the "cheating" method in the answer by Pei Huang will end up with the whole frame getting redrawn. You can do this with Makie, though - in fact the ability to interactively change plots was one of the reasons for creating that package (point 1 here http://makie.juliaplots.org/dev/why-makie.html) Not sure about the other popular plotting packages for Julia.

Timeless answered 9/9, 2019 at 9:23 Comment(3)
Ok, cool, that sounds like a good enough reason to give Makie a try! Thanks (I assume it would also be possible with pyplot backend)Balsamiferous
I looked into Makie and examples like this juliaplots.org/MakieReferenceImages/gallery//… are pretty close to what I need - however it only works by changing the data of a line. How can one remove a line (not just setting it to empty data)?Balsamiferous
You can pop!(scene.plots) to get rid of the line plot completely (assuming it's the last plot). Edit: Knowing the index of the plot, you could also deleteat!(scene.plots, ind).Twentyfourmo

© 2022 - 2024 — McMap. All rights reserved.