When solving differential equations and plotting the results, how can I increase the number of data points that are plotted? I have
using DifferentialEquations
using Plots
function lorenz(du,u,p,t)
du[1] = 10.0*(u[2]-u[1])
du[2] = u[1]*(28.0-u[3]) - u[2]
du[3] = u[1]*u[2] - (8/3)*u[3]
end
u0 = [5.0;0.0;0.0]
tspan = (0.0,100000.0)
prob = ODEProblem(lorenz,u0,tspan)
sol = solve(prob)
plot(sol, vars = 1, xlims = (10,100000),xscale =:log)
Specifically, when using something like PyPlots I can use:
x = linspace(0,100000,num=10000)
where I set num = 10000 which increases the number of samples and allows for a higher resolution of data points for longer integration timespans.
The obvious answer is to use PyPlots, but I'm not sure if I can even use PyPlots with the DifferentialEquations package. It would be nice to know how this is done for Plots. (As depending on the function, some plots come out very jagged).
Plots.jl is actually a wrapper around plotting backends like PyPlot.jl and GR.jl (which are also wrappers).
You can make Plots.jl use PyPlot by calling pyplot(), provided that you have PyPlot.jl installed.
using Plots
pyplot() # switch to PyPlot
plot(sol.t[2:end], sol[1,2:end], xlim =(10,100000), xscale=:log10)
Note that I started from the second index, because at the first index t is 0, which creates problem with log-scale (even if xlim is set). This uses every data point in the solution. If you are on the terminal this will open up PyPlot GUI, so you can zoom as you wish. If you are on Juno you can use gui(plot(...)) to open the window.
You can sample the system at arbitrary time points. (with the DifferentialEquations' interpolant sol(t))
t = range(10, stop = 100000, num=10000) # to reach t=100000 you need to adjust `maxiters` accordingly in your call to `solve`
samples = sol(t) # sample using interpolator
plot(samples.t, samples.u[1,:], xscale=:log10)
You could also use the recipe without log-scale and with plotdensity option.
plot(sol, vars=1, plotdensity=1000)
See here for more examples: http://diffeq.sciml.ai/stable/basics/plot.html
Related
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.
In statistics, there is rejection method to generate a random variable.
(but it is not main problem)
I finished the sampling, and want to draw graphics in one screen.
I thought it was an 'add=TRUE' option, and I set it up.
But it showed me a new screen.
I do not know what is wrong.
I'm sorry to post a trivial question, but I have no other place to ask.
nsample=10000
fx = function(x){2*exp(-(x^2)/2)/sqrt(2*pi)}
gx = function(x){exp(-x)}
fxdivgx = function(x){(2*exp(-(x^2)/2)/sqrt(2*pi)/exp(-x))}
grid=seq(0.0,5.0, length.out =1000)
which(fxdivgx(grid)==max(fxdivgx(grid)))
grid[201] #x valuable which fx/gx has maximum value
const = fxdivgx(grid[201])
const
fn = function(x){((2*exp(-(x^2)/2)/sqrt(2*pi))/(exp(-x)*const))}
result2 = list()
result2$candi=rexp(nsample)
result2$targetDen=fn(result2$candi)
result2$keep=ifelse(runif(nsample)<result2$targetDen, TRUE, FALSE)
hist(result2$candi[result2$keep], freq=F, breaks=100)
curve(2*exp(-(x^2)/2)/sqrt(2*pi), add='TRUE', col='red')
This is my code.
When I run this code, the results are printed on different screens.
How do I print two pictures in one screen?
hist(result$candi[result$keep], breaks=100)
curve((2*exp(-(x^2)/2)/sqrt(2*pi)), add=TRUE, col='red')
after plotting these two lines, i got below graphics.
I'm trying to visualize a high-dim point set x (here of dim (6 x 42)) in a series of 2D scatter plots (x[1] vs x[2] etc.) using bokeh. [edit2] See this nice example from scikit-opt as a reference. When x[1] occurs in two plots it should interact with the same range and the plots should rescale simultaneously. I have accomplished this, but I don't get it to scale correctly. Here's a minimal example: [edit2]
import bokeh
import bokeh.io
import numpy as np
import bokeh.plotting
bokeh.io.output_notebook()
# That's my fictional dataset
x = np.random.randn(6, 42)
x[2] *= 10
# Build the pairwise scatter plots
kw = dict(plot_width=165, plot_height=165)
# `ranges` stores the range in each dimension,
# used as both, x- and y-range depending on
# where the variable is.
figs, ranges = {}, {}
for r, row in enumerate(x):
for c, col in enumerate(x):
if r is not c:
fig = bokeh.plotting.figure(
x_range=ranges.get(c, None), y_range=ranges.get(r, None),
**kw)
fig.scatter(x=col, y=row)
fig.xaxis.axis_label = f'Dim {c}'
fig.yaxis.axis_label = f'Dim {r}'
if c not in ranges:
ranges[c] = fig.x_range
if r not in ranges:
ranges[r] = fig.y_range
figs[f'{r}_{c}'] = fig
else:
break
# Setup the plotting layout
plots = [[]]
for r, row in enumerate(x):
for c, col in enumerate(x):
if r is not c:
plots[-1].append(figs[f'{r}_{c}'])
else:
plots.append([])
break
staircase = bokeh.layouts.gridplot(plots, **kw)
bokeh.plotting.show(staircase)
.. into an ipython notebook (>=py3.6), bokeh sets the scale for dim 1, and 2 correctly. Then, it starts to set the scale for the following dimensions as in dim 2. Notice that I scaled dim 2 10-fold to make this point.
Interactively, I can rescale the plot back to optimal settings. However, I'd like to do that by default. What options do I have inside bokeh to rescale? I played a bit with fig.xaxis.bounds, but unsuccessfully. Thanks for your help!
Epilogue:
Following #bigreddot's answer, I added the lines:
for i, X in enumerate(x):
ranges[i].start = X.min()
ranges[i].end = X.max()
to fix the starting ranges. I still think that the behaviour is a bug.
From your code and description I still can't quite tell what you are hoping to accomplish. [1] But I will state that the default DataRange1d ranges that plot's use automatically make space for all renderers, across all plots they are shared by. In this sense, I see exactly what I would expect when I run your code. If you want something different, there are two things you could control:
DataRange1d has a .renderers property. If you only want the "auto" ranging to be over a subset of the renderers, then you can explicitly set this property to the list you want. Renderers are returned by the glyph functions, e.g. fig.scatter
Don't use the "auto" ranges. You can also set the x_range and y_range yourself to be Range1d objects. These have start and end properties that you can set, and these will be the definite bounds of the range, e.g. x-range=Range1d(0, 10)
[1] The ranges are linked in what I would consider an odd way, and I can't tell if that is intended. But that is a result of your looping/python code and not Bokeh.
I apologize first for bringing what I imagine to be a ridiculously simple problem here, but I have been unable to glean from the help file for package 'polynom' how to solve this problem. For one out of several years, I have two vectors of x (d for day of year) and y (e for an index of egg production) data:
d=c(169,176,183,190,197,204,211,218,225,232,239,246)
e=c(0,0,0.006839425,0.027323127,0.024666883,0.005603878,0.016599262,0.002810977,0.00560387 8,0,0.002810977,0.002810977)
I want to, for each year, use the poly.calc function to create a polynomial function that I can use to interpolate the timing of maximum egg production. I want then to superimpose the function on a plot of the data. To begin, I have no problem with the poly.calc function:
egg1996<-poly.calc(d,e)
egg1996
3216904000 - 173356400*x + 4239900*x^2 - 62124.17*x^3 + 605.9178*x^4 - 4.13053*x^5 +
0.02008226*x^6 - 6.963636e-05*x^7 + 1.687736e-07*x^8
I can then simply
plot(d,e)
But when I try to use the lines function to superimpose the function on the plot, I get confused. The help file states that the output of poly.calc is an object of class polynomial, and so I assume that "egg1996" will be the "x" in:
lines(x, len = 100, xlim = NULL, ylim = NULL, ...)
But I cannot seem to, based on the example listed:
lines (poly.calc( 2:4), lty = 2)
Or based on the arguments:
x an object of class "polynomial".
len size of vector at which evaluations are to be made.
xlim, ylim the range of x and y values with sensible defaults
Come up with a command that successfully graphs the polynomial "egg1996" onto the raw data.
I understand that this question is beneath you folks, but I would be very grateful for a little help. Many thanks.
I don't work with the polynom package, but the resultant data set is on a completely different scale (both X & Y axes) than the first plot() call. If you don't mind having it in two separate panels, this provides both plots for comparison:
library(polynom)
d <- c(169,176,183,190,197,204,211,218,225,232,239,246)
e <- c(0,0,0.006839425,0.027323127,0.024666883,0.005603878,
0.016599262,0.002810977,0.005603878,0,0.002810977,0.002810977)
egg1996 <- poly.calc(d,e)
par(mfrow=c(1,2))
plot(d, e)
plot(egg1996)