I am trying to create a gif with 100 frames, which I assume shouldn't be a problem if I code it correctly. However, the following code slows to a crawl, and seems to cause a memory leak.
using Plots
using ProgressMeter
u = rand(100,100)
hmap = heatmap(zeros(size(u)), clim=(0,1))
p = Progress(1000, 1)
anim = Animation()
for i=1:1000
u = rand(100,100)
heatmap!(hmap[1],u)
if mod(i,10) == 0
frame(anim)
end
next!(p)
end
gif(anim, "/tmp/anim_fps30.gif", fps=30)
Have I made a critical error in my coding? Is there a way to get frames for the animation without holding them all in memory? Thanks.
I think the slower portion of your loop is not frame() but heatmap(). Your code runs heatmap 10 times per frame. Try:
using Plots
pyplot() # if needed
using ProgressMeter
function doit()
u = rand(100,100)
hmap = heatmap(zeros(size(u)), clim=(0,1))
prog = Progress(1000, 1)
anim = Animation()
for i=1:1000
if mod(i,10) == 0
heatmap!(hmap[1],rand(100,100))
frame(anim)
end
next!(prog)
end
anim
end
gif(doit(), "/tmp/anim_fps30.gif", fps=30)
Related
I want to plot the function
4(x)^2 = ((y)^2/(1-y));
how can I plot this?
--> 4*(x) = ((y^2)*(1-y)^-1)^0.5;
4*(x) = ((y^2)*(1-y)^-1)^0.5;
^^
Error: syntax error, unexpected =, expecting end of file
Since Scilab 6.1.0, plotimplicit() does it:
plotimplicit "4*x^2 = y^2/(1-y)"
xgrid()
Can't do more simple. Result:
Well, you have to first create a function and for that you have to express one variable in terms of the other.
function x = f(y)
x = (((y^2)*(1-y)^-1)^0.5)/4;
endfunciton
Then you need to generate the input data (i.e, the points at which you want to evaluate the function)
ydata = linspace(1, 10)
Now you push your input point through the function to get your output points
xdata = f(ydata)
Then, you can plot the pairs of x and y using:
plot(xdata, ydata)
Or even easier, without the intermediate step of generating the output data, you can simply do:
plot(f(ydata), ydata)
BTW. I find it strange that the function you are trying to plot is x in terms of y, usually, x is the input variable, but I hope you know what you are trying to accomplish.
Reference: https://www.scilab.org/tutorials/getting-started/plotting
Take care that y must be in [-inf 1[
y=linspace(-10 ,1.00001,1000);
x = sqrt(y^2./(1-y))/4;
clf; plot(y,x),plot(y,-x)
If x is a solution -x is also solution
Two questions in one: Given a line plotted in Julia, how can I
delete it from the plot and legend (without clearing the whole plot)
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
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)
sleep(10)
pop!(scene.plots)
display(scene)
sleep(10)
pop!(scene.plots)
display(scene)
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()
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 ...
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.
I would like to create a stacked area chart, similar to this for example, in Julia using Plots.
I know / suppose that you can do this if you directly use the Gadfly or PyPlot backends in Julia, but I was wondering if there was a recipe for this. If not, how can you contribute to the Plots Recipes? Would be a useful addition.
There's a recipe for something similar in
https://docs.juliaplots.org/latest/examples/pgfplots/#portfolio-composition-maps
For some reason the thumbnail looks broken now though (but the code works).
The exact plot in the matlab example can be produced by
plot(cumsum(Y, dims = 2)[:,end:-1:1], fill = 0, lc = :black)
As a recipe that would look like
#userplot AreaChart
#recipe function f(a::AreaChart)
fillto --> 0
linecolor --> :black
seriestype --> :path
cumsum(a.args[1], dims = 2)[:,end:-1:1]
end
If you want to contribute a recipe to Plots you can open a pull request on Plots, or, eg. on StatsPlots - there's a good description of contributing here: https://docs.juliaplots.org/latest/contributing/
It's a bit of reading, but very generally useful as an introduction to contributing to Julia packages.
You can read this thread in the Julia discourse forum where the question is developed in deep.
One solution posted there using Plots is :
# a simple "recipe" for Plots.jl to get stacked area plots
# usage: stackedarea(xvector, datamatrix, plotsoptions)
#recipe function f(pc::StackedArea)
x, y = pc.args
n = length(x)
y = cumsum(y, dims=2)
seriestype := :shape
# create a filled polygon for each item
for c=1:size(y,2)
sx = vcat(x, reverse(x))
sy = vcat(y[:,c], c==1 ? zeros(n) : reverse(y[:,c-1]))
#series (sx, sy)
end
end
a = [1,1,1,1.5,2,3]
b = [0.5,0.6,0.4,0.3,0.3,0.2]
c = [2,1.8,2.2,3.3,2.5,1.8]
sNames = ["a","b","c"]
x = [2001,2002,2003,2004,2005,2006]
plotly()
stackedarea(x, [a b c], labels=reshape(sNames, (1,3)))
(by user NiclasMattsson)
Other ways presented there include using the VegaLite.jl package.
With Gadfly it is possible to combine plots in a grid and save the combined plot in a file:
using Gadfly, Compose
x=1:0.1:5;
grid = Array(Compose.Context, (2, 2));
grid[1,1] = render(plot( x=x, y = x, Geom.line));
grid[1,2] = render(plot( x=x, y = x.^2, Geom.line));
grid[2,1] = render(plot( x=x, y = log(x), Geom.line));
grid[2,2] = render(plot( x=x, y = sqrt(x), Geom.line));
draw(SVG("example.svg", 100mm, 100mm), gridstack(grid));
I wrote a function that creates such a plot and this function creates a file. It is a little bit unintuitive for someone who wants to use this function why exactly this function creates a file, while the results of all the other plotting functions with single plots are displayed directly in the browser.
So, is it possible to call a function (in place of draw?) such that the combined plot defined by the grid is displayed directly in the browser like "normal" plots?
function as_temp_html(gadflyplot)
thefilepath=tempname() * ".html"
write(open(thefilepath,"w"),stringmime("text/html",gadflyplot))
return thefilepath
end
You can open this file in your browser by re-using Gadfly's crossplatform "open_file" method:
function open_file(filename)
if is_apple()
run(`open $(filename)`)
elseif is_linux() || is_bsd()
run(`xdg-open $(filename)`)
elseif is_windows()
run(`$(ENV["COMSPEC"]) /c start $(filename)`)
else
warn("Showing plots is not supported on OS $(string(Compat.KERNEL))")
end
end
EDIT: now the answer uses Gadfly-exclusive code
I need to draw lines from the data stored in a text file.
So far I am able only to draw points on a graph and i would like to have them as lines (line graph).
Here's the code:
pupil_data <- read.table("C:/a1t_left_test.dat", header=T, sep="\t")
max_y <- max(pupil_data$PupilLeft)
plot(NA,NA,xlim=c(0,length(pupil_data$PupilLeft)), ylim=c(2,max_y));
for (i in 1:(length(pupil_data$PupilLeft) - 1))
{
points(i, y = pupil_data$PupilLeft[i], type = "o", col = "red", cex = 0.5, lwd = 2.0)
}
Please help me change this line of code:
points(i, y = pupil_data$PupilLeft[i], type = "o", col = "red")
to draw lines from the data.
Here is the data in the file:
PupilLeft
3.553479
3.539469
3.527239
3.613131
3.649437
3.632779
3.614373
3.605981
3.595985
3.630766
3.590724
3.626535
3.62386
3.619688
3.595711
3.627841
3.623596
3.650569
3.64876
By default, R will plot a single vector as the y coordinates, and use a sequence for the x coordinates. So to make the plot you are after, all you need is:
plot(pupil_data$PupilLeft, type = "o")
You haven't provided any example data, but you can see this with the built-in iris data set:
plot(iris[,1], type = "o")
This does in fact plot the points as lines. If you are actually getting points without lines, you'll need to provide a working example with your data to figure out why.
EDIT:
Your original code doesn't work because of the loop. You are in effect asking R to plot a line connecting a single point to itself each time through the loop. The next time through the loop R doesn't know that there are other points that you want connected; if it did, this would break the intended use of points, which is to add points/lines to an existing plot.
Of course, the line connecting a point to itself doesn't really make sense, and so it isn't plotted (or is plotted too small to see, same result).
Your example is most easily done without a loop:
PupilLeft <- c(3.553479 ,3.539469 ,3.527239 ,3.613131 ,3.649437 ,3.632779 ,3.614373
,3.605981 ,3.595985 ,3.630766 ,3.590724 ,3.626535 ,3.62386 ,3.619688
,3.595711 ,3.627841 ,3.623596 ,3.650569 ,3.64876)
plot(PupilLeft, type = 'o')
If you really do need to use a loop, then the coding becomes more involved. One approach would be to use a closure:
makeaddpoint <- function(firstpoint){
## firstpoint is the y value of the first point in the series
lastpt <- firstpoint
lastptind <- 1
addpoint <- function(nextpt, ...){
pts <- rbind(c(lastptind, lastpt), c(lastptind + 1, nextpt))
points(pts, ... )
lastpt <<- nextpt
lastptind <<- lastptind + 1
}
return(addpoint)
}
myaddpoint <- makeaddpoint(PupilLeft[1])
plot(NA,NA,xlim=c(0,length(PupilLeft)), ylim=c(2,max(PupilLeft)))
for (i in 2:(length(PupilLeft)))
{
myaddpoint(PupilLeft[i], type = "o")
}
You can then wrap the myaddpoint call in the for loop with whatever testing you need to decide whether or not you will actually plot that point. The function returned by makeaddpoint will keep track of the plot indexing for you.
This is normal programming for Lisp-like languages. If you find it confusing you can do this without a closure, but you'll need to handle incrementing the index and storing the previous point value 'manually' in your loop.
There is a strong aversion among experienced R coders to using for-loops when not really needed. This is an example of a loop-less use of a vectorized function named segments that takes 4 vectors as arguments: x0,y0, x1,y1
npups <-length(pupil_data$PupilLeft)
segments(1:(npups-1), pupil_data$PupilLeft[-npups], # the starting points
2:npups, pupil_data$PupilLeft[-1] ) # the ending points