Related
I would like to plot a two variable function(s) (e_pos and e_neg in the code). Here, t and a are constants which I have given the value of 1.
My code to plot this function is the following:
t = 1
a = 1
kx = ky = range(3.14/a, step=0.1, 3.14/a)
# Doing a meshgrid for values of k
KX, KY = kx'.*ones(size(kx)[1]), ky'.*ones(size(ky)[1])
e_pos = +t.*sqrt.((3 .+ (4).*cos.((3)*KX*a/2).*cos.(sqrt(3).*KY.*a/2) .+ (2).*cos.(sqrt(3).*KY.*a)));
e_neg = -t.*sqrt.((3 .+ (4).*cos.((3)*KX*a/2).*cos.(sqrt(3).*KY.*a/2) .+ (2).*cos.(sqrt(3).*KY.*a)));
using Plots
plot(KX,KY,e_pos, st=:surface,cmap="inferno")
If I use Plots this way, sometimes I get an empty 3D plane without the surface. What am I doing wrong? I think it may have to do with the meshgrids I did for kx and ky, but I am unsure.
Edit: I also get the following error:
I changed some few things in my code.
First, I left the variables as ranges. Second, I simply computed the functions I needed without mapping the variables onto them. Here's the code:
t = 2.8
a = 1
kx = range(-pi/a,stop = pi/a, length=100)
ky = range(-pi/a,stop = pi/a, length=100)
#e_pos = +t*np.sqrt(3 + 4*np.cos(3*KX*a/2)*np.cos(np.sqrt(3)*KY*a/2) + 2*np.cos(np.sqrt(3)*KY*a))
e_pos(kx,ky) = t*sqrt(3+4cos(3*kx*a/2)*cos(sqrt(3)*ky*a/2) + 2*cos(sqrt(3)*ky*a))
e_neg(kx,ky) = -t*sqrt(3+4cos(3*kx*a/2)*cos(sqrt(3)*ky*a/2) + 2*cos(sqrt(3)*ky*a))
# Sort of broadcasting?
e_posfunc = e_pos.(kx,ky);
e_negfunc = e_neg.(kx,ky);
For the plotting I simply used the GR backend:
using Plots
gr()
plot(kx,ky,e_pos,st=:surface)
plot!(kx,ky,e_neg,st=:surface, xlabel="kx", ylabel="ky",zlabel="E(k)")
I got what I wanted!
I have a timerow and would like to find minima which fulfill specific criteria. Those are that the number of points within the valleys (below the red line) between 2 peaks should exceed a certain value and also the number of points above the red line should exceed a certain value for each peak neighboring the valley. Also the lower of the two peaks should be resolved at a value lower than 50% of its height (meaning that the max(intensity) of the lower of the two peaks should be at least 2 fold the intensity of the lowest intensity within the valley between the two peaks - as calculated below in the code sample). I drew the red line here at a specific height but in reality those unresolved peaks can have any height and can also be seperated by any distance. So what I am doing at the moment is to "scan" with the red line over each point of the time series which is of course very slow and inefficient.
So here is the for-loop I am using at the moment:
detect_double_peaks <- function(pot.doubleP.v, Min.PpP = 10) {
peak.dt <-
data.table(
breakP = NA,
breakH = NA,
resolved = NA
)
for (point in pot.doubleP.v[pot.doubleP.v > 0 &
pot.doubleP.v < 0.8 * max(pot.doubleP.v)]) {
doublePeak.rle <- S4Vectors::Rle(pot.doubleP.v > point)
doublePeak.rle.dt <-
data.table(
idx = as.numeric(seq.int(length(
doublePeak.rle#values
))),
values = doublePeak.rle#values,
lengths = doublePeak.rle#lengths,
start = start(doublePeak.rle),
end = end(doublePeak.rle)
)
doublePeak.rle.dt_p <-
doublePeak.rle.dt[values == TRUE & lengths > Min.PpP]
if (nrow(doublePeak.rle.dt_p) > 1) {
for(peak in 1:nrow(doublePeak.rle.dt_p)-1){
doublePeak.rle.dt_v <- doublePeak.rle.dt[idx > doublePeak.rle.dt_p[peak]$idx & idx < doublePeak.rle.dt_p[peak + 1]$idx]
if(sum(doublePeak.rle.dt_v[values == FALSE]$lengths) >= max(max(doublePeak.rle.dt_p[peak]$lengths, doublePeak.rle.dt_p[peak+1]$lengths) * 0.5, Min.PpP)){
dp.p_height_h <-
max(max(pot.doubleP.v[(doublePeak.rle.dt_p[peak]$start):(doublePeak.rle.dt_p[peak]$end)]),
max(pot.doubleP.v[(doublePeak.rle.dt_p[peak + 1]$start):(doublePeak.rle.dt_p[peak + 1]$end)]))# - baseL
dp.p_height_l <-
min(max(pot.doubleP.v[(doublePeak.rle.dt_p[peak]$start):(doublePeak.rle.dt_p[peak]$end)]),
max(pot.doubleP.v[(doublePeak.rle.dt_p[peak + 1]$start):(doublePeak.rle.dt_p[peak + 1]$end)]))# - baseL
breakH <-
min(pot.doubleP.v[min(doublePeak.rle.dt[idx > doublePeak.rle.dt_p[peak]$idx]$start):max(doublePeak.rle.dt[idx < doublePeak.rle.dt_p[peak+1]$idx]$end)])# - baseL
resolved <-
breakH / dp.p_height_l * 100
breakP <-
which.min(pot.doubleP.v[min(doublePeak.rle.dt[idx > doublePeak.rle.dt_p[peak]$idx]$start):max(doublePeak.rle.dt[idx < doublePeak.rle.dt_p[peak+1]$idx]$end)]) +
doublePeak.rle.dt_p[peak]$end
peak.dt <- rbind(peak.dt,
data.table(breakP = breakP,
breakH = breakH,
resolved = resolved))
}
}
}
}
if(nrow(peak.dt) == 1) {return(NULL)} else{
return(na.omit(unique(peak.dt, by="breakP")))
}
}
Here are some example data:
testvector <- c(13126.177734375, 12040.060546875, 10810.6171875, 10325.94140625,
13492.8359375, 33648.5703125, 14402.603515625, 29920.12890625,
24316.224609375, 36019.26171875, 34492.4609375, 53799.82421875,
45988.72265625, 47930.453125, 67438.9140625, 61231.83984375,
56710.9140625, 62301.6796875, 54844.7578125, 70913.578125, 81028.1640625,
75234.203125, 59611.05078125, 79240.4375, 52313.3828125, 78758.2734375,
87918.5859375, 80764.7421875, 108035.5390625, 76263.875, 72401.6796875,
83167.640625, 76173.96875, 66241.4296875, 68687.4375, 52107.83984375,
45672.5390625, 51907.33203125, 39967.453125, 58856.90625, 52402.53125,
36980.3125, 43365.76171875, 40480.75, 39057.96484375, 31622.58984375,
23830.455078125, 27393.30078125, 30675.208984375, 27327.48046875,
25150.08984375, 23746.212890625, 9637.625, 19065.58984375, 21367.40625,
6789.0625, 9892.7490234375, 26820.685546875, 19965.353515625,
28281.462890625, 25495.0703125, 28808.416015625, 40244.03125,
35159.421875, 35257.984375, 39971.8046875, 34710.4453125, 60987.73828125,
50620.06640625, 58757.69140625, 52998.97265625, 55601.96484375,
69057.9453125, 58486.52734375, 66115.4765625, 80801.7578125,
77444.6015625, 43545.48828125, 79545.0703125, 50352.484375, 77401.8671875,
85118.421875, 80521.9296875, 68945.8125, 93098.0234375, 83065.8046875,
95970.8203125, 74141.8828125, 90298.75, 81251.0234375, 99658.3359375,
88812.2578125, 81939.4921875, 82632.1015625, 100125.0078125,
71627.84375, 70560.1484375, 77831.765625, 68122.328125, 79049.140625,
88000.890625, 64897.4453125, 57333.3046875, 68185.3046875, 67742.3515625,
58941.85546875, 63184.8671875, 36998.67578125, 45416.58984375,
31547.3359375, 32141.58203125, 35292.9765625, 30511.861328125,
25419.716796875, 23901.431640625, 15616.8759765625, 14469.16015625,
15026.0009765625, 18321.42578125, 15820.861328125, 19532.056640625,
13230.6240234375, 14586.76953125, 14912.642578125, 8541.5224609375,
21740.98046875, 19588.986328125, 18603.662109375, 19656.5625,
10812.94921875, 18379.3359375, 31242.716796875, 25626.0390625,
42446.71875, 27782.294921875, 38450.703125, 39070.97265625, 52914.375,
56484.47265625, 47741.88671875, 52397.18359375, 79378.2109375,
77866.078125, 55902.09765625, 66988.2265625, 63571.01171875,
66192.53125, 79989.8046875, 57204.59765625, 51172.9921875, 49612.16015625,
60508.0390625, 69518.09375, 48079.5625, 48691.0390625, 33679.12890625,
30697.470703125, 31209.359375, 49656.16796875, 32041.912109375,
13851.48828125, 29316.44921875, 31586.216796875, 45422.19921875,
24208.515625, 31496.083984375, 26250.646484375, 14318.302734375
)
For this vector the minima at 56 and 125 should be returned.
Those should be returned because when scanning with the red line through the points of the vector there is at least one iteration at which there are more than Min.PpP = 10 consecutive points above the red line on each side of the valley, and with the same red line there are also more than Min.PpP = 10 points in the valley. The reason why point 4 should not be returned as minima is that no matter where we put the red line the valley will never exceed 3 points (which is lower than Min.PpP = 10) and the peak on the left side of that minima would only be 1 point (which is also lower than Min.PpP = 10).
I am aware of functions like pastecs::turnpoints. However, they do not seem to offer the implementation of criteria as I want to use them.
So it there any other more efficent way to achive that?
Ps.:
I have also put another criteria in the example code which says that there should be at least halve as many points in the vally as there are for the peak with the smaller number of points even when Min.PpP is exceeded:
if(sum(doublePeak.rle.dt_v[values == FALSE]$lengths) >= max(max(doublePeak.rle.dt_p[peak]$lengths, doublePeak.rle.dt_p[peak+1]$lengths) * 0.5, Min.PpP))
However I guess thats not really important for this problem.
I'm trying to subplot my data, but printing in PDF brings results I can't use: Title and x-axis title are cut (and the legend's box is covered by the graph, but I can handle this with other positions). I have to use gnuplot and pdfcairo because other seup isn't working with special characters, umlaut, etc.
clear;clc;close all;clf;clear all;
graphics_toolkit("gnuplot")
x = 0:.1:10;
y1 = exp(-x).*sin(x);
y2 = exp(x);
h=figure(1);
subplot(2,1,1);
plot(x,y1)
h1 = plot(x,y1);
set(h1,'LineWidth',4)
set(gca,'FontSize',32)
set(gca,'FontName','Times')
set(get(gca,'Ylabel'),'String','TTEST test \rho \rightarrow','FontWeight','Bold','FontSize',32)
set(get(gca,'Xlabel'),'String','abc / - \rightarrow','FontWeight','Bold','FontSize',32)
legend({
'h_{ref}(t)'
},"location", 'northeast');
title('TITLE')
l1 = legend;
set(l1,'FontName','Times')
subplot(2,1,2);
h2 = plot(x,y2);
set(h2,'LineWidth',4)
set(gca,'FontSize',32)
set(gca,'FontName','Times')
set(get(gca,'Ylabel'),'String','TTEST test \rho \rightarrow','FontWeight','Bold','FontSize',32)
set(get(gca,'Xlabel'),'String','agc / -\rightarrow','FontWeight','Bold','FontSize',32)
legend({
'h_{ref}(t)'
},"location", 'northeast');
l2 = legend;
set(l2,'FontName','Times')
print ('title_axis.pdf', '-dpdfcairo', '-S1000,600');
How can you get the length of the curve down below between 0 and 4*pi? The commands you should use are inttrap and diff. Here is what I have now:
t=linspace(0,4*%pi)
x=(4+sin(a*t)).*cos(3*t)
y=(4+sin(a*t)).*sin(3*t)
z=cos(3*t)
xx=diff(x)
yy=diff(y)
zz=diff(z)
aid=sqrt(xx^2+yy^2+zz^2)
length=inttrap([t],aid)
Getting error message, the last step is not right.
The reason for error message is that t and aid have different sizes. And that is because diff returns a vector with 1 entry fewer than the input. You can see how it works on an example: diff([3 1 5]) is [-2 4].
To fix this, use t(1:$-1), which omits the last entry of t. That is,
len = inttrap(t(1:$-1), aid)
(Please don't use length, which is a function name in Scilab.)
Another problem you have is that diff is just differences, not a derivative. To get the derivative, you need to divide by the step size, which in your case is t(2)-t(1).
Also, the syntax xx^2 is deprecated for elementwise power; use xx.^2 instead
t = linspace(0,4*%pi)
a = 1
x = (4+sin(a*t)).*cos(3*t)
y = (4+sin(a*t)).*sin(3*t)
z = cos(3*t)
step = t(2)-t(1)
xx = diff(x)/step
xy = diff(y)/step
xz = diff(z)/step
aid = sqrt(xx.^2+yy.^2+zz.^2)
len = inttrap(t(1:$-1), aid)
why the code below does not work?
xa = [0 0.200000000000000 0.400000000000000 1.00000000000000 1.60000000000000 1.80000000000000 2.00000000000000 2.60000000000000 2.80000000000000 3.00000000000000 3.80000000000000 4.80000000000000 5.00000000000000 5.20000000000000 6.00000000000000 6.20000000000000 7.40000000000000 7.60000000000000 7.80000000000000 8.60000000000000 8.80000000000000 9.00000000000000 9.20000000000000 9.40000000000000 10.0000000000000 10.6000000000000 10.8000000000000 11.2000000000000 11.6000000000000 11.8000000000000 12.2000000000000 12.4000000000000];
ya = [-0.183440428023042 -0.131101157495126 0.0268875670852843 0.300000000120000 0.579048247883555 0.852605831272159 0.935180993484717 1.13328608090532 1.26893326843583 1.10202945535186 1.09201137189664 1.14279083803453 0.811302535321072 0.909735376251797 0.417067545528244 0.460107770989798 -0.516307074859654 -0.333994077331822 -0.504124744955962 -0.945794320817293 -0.915934553082780 -0.975458595671737 -1.09943707404275 -1.11254211607374 -1.29739980589100 -1.23440439602665 -0.953807504156356 -1.12240274852172 -0.609284630192522 -0.592560286759450 -0.402521296049042 -0.510090363150962];
x0 = vec(xa)
y0 = vec(ya)
fun(x,a) = a[1].*sin(a[2].*x - a[3])
a0 = [1,2,3]
eps = 0.000001
maxiter=200
coefs, converged, iter = CurveFit.nonlinear_fit(x0 , fun , a0 , eps, maxiter )
y0b = fit(x0)
Winston.plot(x0, y0, "ob", x0, y0b, "r-", linewidth=3)
Error: LoadError: MethodError: convert has no method matching convert(::Type{Float64}, ::Array{Float64,1}) This may have arisen from
a call to the constructor Float64(...), since type constructors fall
back to convert methods. Closest candidates are: call{T}(::Type{T},
::Any) convert(::Type{Float64}, !Matched::Int8)
convert(::Type{Float64}, !Matched::Int16)
while loading In[269], in expression starting on line 8
in nonlinear_fit at /home/jmarcellopereira/.julia/v0.4/CurveFit/src/nonlinfit.jl:75
The fun function has to return a residual value r of type Float64, calculated at each iteration of the data, as follows:
r = y - fun(x, coefs)
so your function y=a1*sin(x*a2-a3) will be defined as:
fun(x,a) = x[2]-a[1]*sin(a[2]*x[1] - a[3])
Where:
x[2] is a value of 'y' vector
x[1] is a value of 'x' vector
a[...] is the set of parameters
The fun function has to return a single Float64, so the operators can't be 'dot version' (.*).
By calling the nonlinear_fit function, the first parameter must be an array Nx2, with the first column containing N values of x and the second, containing N values of y, so you must concatenate the two vectors x and y in a two columns array:
xy = [x y]
and finally, call the function:
coefs, converged, iter = CurveFit.nonlinear_fit(xy , fun , a0 , eps, maxiter )
Answering to your comment about the returned coefficients are not correct:
The y = 1 * sin (x * a2-a3) is a harmonic function, so the coefficients returning from the function call, depend heavily on the parameter a0 ("initial guess for each fitting parameter") you will send as the third parameter (with maxiter=200_000):
a0=[1.5, 1.5, 1.0]
coefficients: [0.2616335317043578, 1.1471991302529982,0.7048665905560775]
a0=[100.,100.,100.]
coefficients: [-0.4077952060368059, 90.52328921205392, 96.75331155303707]
a0=[1.2, 0.5, 0.5]
coefficients: [1.192007321713507, 0.49426296880933257, 0.19863645732313934]
I think the results you're getting are harmonics, as the graph:
Where:
blue line:
f1(xx)=0.2616335317043578*sin(xx*1.1471991302529982-0.7048665905560775)
yellow line:
f2(xx)=1.192007321713507*sin(xx*0.49426296880933257-0.19863645732313934)
pink line:
f3(xx)=-0.4077952060368059*sin(xx*90.52328921205392-96.75331155303707)
blue dots are your initial data.
The graph was generated with Gadfly:
plot(layer(x=x,y=y,Geom.point),layer([f1,f2,f3],0.0, 15.0,Geom.line))
tested with Julia Version 0.4.3
from Doc:
we are trying to fit the relationship fun(x, a) = 0
So, if you want to find elements of a in a way that: for each xi,yi in [x0 y0] => a[1].*sin(a[2].*xi - a[3])==yi, then the right way is:
fun(xy,a) = a[1].*sin(a[2].*xy[1] - a[3])-xy[2];
xy=hcat(x0,y0);
coefs,converged,iter = CurveFit.nonlinear_fit(xy,fun,a0,eps,maxiter);
I found the LsqFit package a bit simpler to use, just define first the model and "fit it" with your data:
using DataFrames, Plots, LsqFit
xa = [0 0.200000000000000 0.400000000000000 1.00000000000000 1.60000000000000 1.80000000000000 2.00000000000000 2.60000000000000 2.80000000000000 3.00000000000000 3.80000000000000 4.80000000000000 5.00000000000000 5.20000000000000 6.00000000000000 6.20000000000000 7.40000000000000 7.60000000000000 7.80000000000000 8.60000000000000 8.80000000000000 9.00000000000000 9.20000000000000 9.40000000000000 10.0000000000000 10.6000000000000 10.8000000000000 11.2000000000000 11.6000000000000 11.8000000000000 12.2000000000000 12.4000000000000];
ya = [-0.183440428023042 -0.131101157495126 0.0268875670852843 0.300000000120000 0.579048247883555 0.852605831272159 0.935180993484717 1.13328608090532 1.26893326843583 1.10202945535186 1.09201137189664 1.14279083803453 0.811302535321072 0.909735376251797 0.417067545528244 0.460107770989798 -0.516307074859654 -0.333994077331822 -0.504124744955962 -0.945794320817293 -0.915934553082780 -0.975458595671737 -1.09943707404275 -1.11254211607374 -1.29739980589100 -1.23440439602665 -0.953807504156356 -1.12240274852172 -0.609284630192522 -0.592560286759450 -0.402521296049042 -0.510090363150962];
x0 = vec(xa)
y0 = vec(ya)
xbase = collect(linspace(minimum(x0),maximum(x0),100))
p0 = [1.2, 0.5, 0.5] # initial value of parameters
fun(x0, p) = p[1] .* sin.(p[2] .* x0 .- p[3]) # definition of the model
fit = curve_fit(fun,x0,y0,p0) # actual fitting job
yFit = [fit.param[1] * sin(fit.param[2] * x - fit.param[3]) for x in xbase] # building the fitted values
# Plotting..
scatter(x0, y0, label="obs")
plot!(xbase, yFit, label="fitted")
Note that using LsqFit does not solve the problem of dependency from initial conditions highlighted by Gomiero..