Get Y value of line from X pixel value in ChartJS 2 - charts

I have a line graph in chartjs, and I want to find the Y value for an arbitrary point on the line given the pixel value from the x axis.
My Graph
Currently I'm hooking into the afterDatasetsDraw event to add that shaded region to the graph, but I also want to find out the values of the black line (Axis B) at the start and end of the shaded region, which don't necessarily line up with my data points.
afterDatasetsDraw: function (chart) {
var options = chart.config.options.plugins.shader;
if (!options.hasOwnProperty('points')) {
return;
}
if (options.points.length < 2) {
return;
}
var ctx = chart.chart.ctx;
var x1, y1, x2, y2, x3, y3, x4, y4, x0, xf;
console.log(chart);
x0 = chart.scales['x-axis-0'].left;
xf = chart.scales['x-axis-0'].right;
x1 = ((xf - x0) * 0.12) + x0; // start shading at 12% in for example
y1 = chart.scales['A'].bottom;
x2 = x1;
y2 = chart.scales['A'].top;
x3 = ((xf - x0) * 0.66) + x0; // end shading at 66% for example
y3 = y2;
x4 = x3;
y4 = y1;
// console.log(chart.scales['B'].getValueForPixel(x1));
// console.log(chart.scales['B'].getValueForPixel(x3));
// console.log(chart.scales['A'].getValueForPixel(x1));
// console.log(chart.scales['A'].getValueForPixel(x3));
// console.log(chart.scales['x-axis-0'].getValueForPixel(x1));
// console.log(chart.scales['x-axis-0'].getValueForPixel(x3));
ctx.fillStyle = 'rgba(127, 127, 127, 0.3)';
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x3, y3);
ctx.lineTo(x4, y4);
ctx.lineTo(x1,y1);
ctx.closePath();
ctx.fill();
}
});
I would assume from the docs that I could use the scales getValueForPixel() method (as is shown commented out) but those are returning strange values. The X-axis values are coming back as 1 and 3 which as far as I can tell are the indexes of the closest data point. The Y scales are returning numbers that don't correspond with anything in the dataset or the rendered graph.

Related

Moving a star marker along a hexagon trajectory?

I want to move a star marker along hexagon trajectory similar to "Circle trajectory" that I have added at the end of my question. Thanks.
This is the source code to that I have written yet for creating concentric hegzagons but I don't know how to move a star marker which traverses the concentric hexagons, I had written a similar simulation code for circle trajectory but I couldn't do it for hexagon.
%clc; % Clear the command window.
%close all; % Close all figures (except those of imtool.)
%clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 20;
angles = linspace(0, 360, 7);
radii = [20, 35, 50,70];
% First create and draw the hexagons.
numberOfHexagons = 4;
% Define x and y arrays. Each row is one hexagon.
% Columns are the vertices.
x1=radii(1) * cosd(angles)+50;
y1 = radii(1) * sind(angles)+50;
x2=radii(2) * cosd(angles)+50;
y2 = radii(2) * sind(angles)+50;
x3=radii(3) * cosd(angles)+50;
y3 = radii(3) * sind(angles)+50;
x4=radii(4) * cosd(angles)+50;
y4 = radii(4) * sind(angles)+50;
plot(x1 , y1, 'b');
hold on
plot(x2, y2, 'b');
hold on
plot(x3, y3, 'b');
hold on
plot(x4, y4, 'b');
hold on
% Connecting Line:
plot([70 100], [50 50],'color','b')
axis([0 100 0 100])
hold on
Circle trajectory:
% Initialization steps.
format long g;
format compact;
fontSize = 20;
r1 = 50;
r2 = 35;
r3= 20;
xc = 50;
yc = 50;
% Since arclength = radius * (angle in radians),
% (angle in radians) = arclength / radius = 5 / radius.
deltaAngle1 = 5 / r1;
deltaAngle2 = 5 / r2;
deltaAngle3 = 5 / r3;
theta1 = 0 : deltaAngle1 : (2 * pi);
theta2 = 0 : deltaAngle2 : (2 * pi);
theta3 = 0 : deltaAngle3 : (2 * pi);
x1 = r1*cos(theta1) + xc;
y1 = r1*sin(theta1) + yc;
x2 = r2*cos(theta2) + xc;
y2 = r2*sin(theta2) + yc;
x3 = r3*cos(theta3) + xc;
y3 = r3*sin(theta3) + yc;
plot(x1,y1,'color',[1 0.5 0])
hold on
plot(x2,y2,'color',[1 0.5 0])
hold on
plot(x3,y3,'color',[1 0.5 0])
hold on
% Connecting Line:
plot([70 100], [50 50],'color',[1 0.5 0])
% Set up figure properties:
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0, 0, 1, 1]);
drawnow;
axis square;
for i = 1 : length(theta1)
plot(x1(i),y1(i),'r*')
pause(0.1)
end
for i = 1 : length(theta2)
plot(x2(i),y2(i),'r*')
pause(0.1)
end
for i = 1 : length(theta3)
plot(x3(i),y3(i),'r*')
pause(0.1)
end
I would generalize your problem with parametric function for the trajectory. In it use rotation kernel which you want here few examples in C++/VCL/GDI (sorry I am not Matlab friendly but the equations should be the same in Matlab too) for circle,square and hexagon rotation kernels:
void getpnt_circle(double &x,double &y,double &pi2,double r,double t) // (x,y) = circle(r,t) t=<0,1>
{
pi2=2.0*M_PI; // circumference(r=1) 6.283185307179586476925286766559
t*=pi2;
x=r*cos(t);
y=r*sin(t);
}
//---------------------------------------------------------------------------
void getpnt_square(double &x,double &y,double &pi2,double r,double t) // (x,y) = square(r,t) t=<0,1>
{
pi2=8.0; // circumference(r=1)
// kernel
const int n=4; // sides
const double x0[n]={+1.0,+1.0,-1.0,-1.0}; // side start point
const double y0[n]={-1.0,+1.0,+1.0,-1.0};
const double dx[n]={ 0.0,-2.0, 0.0,+2.0}; // side tangent
const double dy[n]={+2.0, 0.0,-2.0, 0.0};
int ix;
t-=floor(t); // t = <0, 1.0)
t*=n; // t = <0,n)
ix=floor(t); // side of square
t-=ix; // distance from side start
x=r*(x0[ix]+t*dx[ix]);
y=r*(y0[ix]+t*dy[ix]);
}
//---------------------------------------------------------------------------
void getpnt_hexagon(double &x,double &y,double &pi2,double r,double t) // (x,y) = square(r,t) t=<0,1>
{
pi2=6.0; // circumference(r=1)
// kernel
const int n=6; // sides
const double c60=cos(60.0*M_PI/180.0);
const double s60=sin(60.0*M_PI/180.0);
const double x0[n]={+1.0,+c60,-c60,-1.0,-c60,+c60}; // side start point
const double y0[n]={ 0.0,+s60,+s60, 0.0,-s60,-s60};
const double dx[n]={-c60,-1.0,-c60,+c60,+1.0,+c60}; // side tangent
const double dy[n]={+s60, 0.0,-s60,-s60, 0.0,+s60};
int ix;
t-=floor(t); // t = <0, 1.0)
t*=n; // t = <0,n)
ix=floor(t); // side of square
t-=ix; // distance from side start
x=r*(x0[ix]+t*dx[ix]);
y=r*(y0[ix]+t*dy[ix]);
}
//---------------------------------------------------------------------------
void TMain::draw()
{
if (!_redraw) return;
// clear buffer
bmp->Canvas->Brush->Color=clBlack;
bmp->Canvas->FillRect(TRect(0,0,xs,ys));
int e;
double r,t,x,y,c,dr=15.0,dl=15.0;
int xx,yy,rr=3;
bmp->Canvas->MoveTo(xs2,ys2);
bmp->Canvas->Pen->Color=clAqua;
bmp->Canvas->Brush->Color=clBlue;
for (r=dr,t=0.0;;)
{
// get point from selected kernel
// getpnt_circle (x,y,c,r,t);
// getpnt_square (x,y,c,r,t);
getpnt_hexagon(x,y,c,r,t);
// render it
xx=xs2+x;
yy=ys2+y;
bmp->Canvas->LineTo(xx,yy);
bmp->Canvas->Ellipse(xx-rr,yy-rr,xx+rr,yy+rr);
// update position
r+=dr*dr/(r*c);
t+=dl/(r*c); t-=floor(t);
if (r>=xs2) break;
if (r>=ys2) break;
}
// render backbuffer
Main->Canvas->Draw(0,0,bmp);
_redraw=false;
}
//---------------------------------------------------------------------------
You can ignore the VCL/GDI rendering stuff.
xs,ys is full and xs2,ys2 is half resolution of window to scale the plot properly...
dl is distance between markers [pixels]
dr is distance between spiral screws [pixels]
the spiral is sampled with r,t step depending on the actual circumference (that is what the pi2 or c is for). The getpnt_xxxxx function will return x,y coordinate of your shape from parameter t=<0,1> and actual radius r. It also returns the actual value of circumference/r ratio called pi2
Here preview of the 3 kernels used for spiral ...

How to find Orientation of axis of contour in matlab?

I want to find Orientation, MajorAxisLengthand MinorAxisLength of contour which is plotted with below code.
clear
[x1 , x2] = meshgrid(linspace(-10,10,100),linspace(-10,10,100));
mu = [1,3];
sigm = [2,0;0,2];
xx_size = length(mu);
tem_matrix = ones(size(x1));
x_mesh= cell(1,xx_size);
for i = 1 : xx_size
x_mesh{i} = tem_matrix * mu(i);
end
x_mesh= {x1,x2};
temp_mesh = [];
for i = 1 : xx_size
temp_mesh = [temp_mesh x_mesh{i}(:)];
end
Z = mvnpdf(temp_mesh,mu,sigm);
z_plat = reshape(Z,size(x1));
figure;contour(x1, x2, z_plat,3, 'LineWidth', 2,'color','m');
% regionprops(z_plat,'Centroid','Orientation','MajorAxisLength','MinorAxisLength');
In my opinion, I may have to use regionprops command but I don't know how to do this. I want to find direction of axis of contour and plot something like this
How can I do this task? Thanks very much for your help
Rather than trying to process the graphical output of contour, I would instead recommend using contourc to compute the ContourMatrix and then use the x/y points to estimate the major and minor axes lengths as well as the orientation (for this I used this file exchange submission)
That would look something like the following. Note that I have modified the inputs to contourc as the first two inputs should be the vector form and not the output of meshgrid.
% Compute the three contours for your data
contourmatrix = contourc(linspace(-10,10,100), linspace(-10,10,100), z_plat, 3);
% Create a "pointer" to keep track of where we are in the output
start = 1;
count = 1;
% Now loop through each contour
while start < size(contourmatrix, 2)
value = contourmatrix(1, start);
nPoints = contourmatrix(2, start);
contour_points = contourmatrix(:, start + (1:nPoints));
% Now fit an ellipse using the file exchange
ellipsedata(count) = fit_ellipse(contour_points(1,:), contour_points(2,:));
% Increment the start pointer
start = start + nPoints + 1;
count = count + 1;
end
orientations = [ellipsedata.phi];
% 0 0 0
major_length = [ellipsedata.long_axis];
% 4.7175 3.3380 2.1539
minor_length = [ellipsedata.short_axis];
% 4.7172 3.3378 2.1532
As you can see, the contours are actually basically circles and therefore the orientation is zero and the major and minor axis lengths are almost equal. The reason that they look like ellipses in your post is because your x and y axes are scaled differently. To fix this, you can call axis equal
figure;contour(x1, x2, z_plat,3, 'LineWidth', 2,'color','m');
axis equal
Thank you #Suever. It help me to do my idea.
I add some line to code:
clear
[X1 , X2] = meshgrid(linspace(-10,10,100),linspace(-10,10,100));
mu = [-1,0];
a = [3,2;1,4];
a = a * a';
sigm = a;
xx_size = length(mu);
tem_matrix = ones(size(X1));
x_mesh= cell(1,xx_size);
for i = 1 : xx_size
x_mesh{i} = tem_matrix * mu(i);
end
x_mesh= {X1,X2};
temp_mesh = [];
for i = 1 : xx_size
temp_mesh = [temp_mesh x_mesh{i}(:)];
end
Z = mvnpdf(temp_mesh,mu,sigm);
z_plat = reshape(Z,size(X1));
figure;contour(X1, X2, z_plat,3, 'LineWidth', 2,'color','m');
hold on;
% Compute the three contours for your data
contourmatrix = contourc(linspace(-10,10,100), linspace(-10,10,100), z_plat, 3);
% Create a "pointer" to keep track of where we are in the output
start = 1;
count = 1;
% Now loop through each contour
while start < size(contourmatrix, 2)
value = contourmatrix(1, start);
nPoints = contourmatrix(2, start);
contour_points = contourmatrix(:, start + (1:nPoints));
% Now fit an ellipse using the file exchange
ellipsedata(count) = fit_ellipse(contour_points(1,:), contour_points(2,:));
% Increment the start pointer
start = start + nPoints + 1;
count = count + 1;
end
orientations = [ellipsedata.phi];
major_length = [ellipsedata.long_axis];
minor_length = [ellipsedata.short_axis];
tet = orientations(1);
x1 = mu(1);
y1 = mu(2);
a = sin(tet) * sqrt(major_length(1));
b = cos(tet) * sqrt(major_length(1));
x2 = x1 + a;
y2 = y1 + b;
line([x1, x2], [y1, y2],'linewidth',2);
tet = ( pi/2 + orientations(1) );
a = sin(tet) * sqrt(minor_length(1));
b = cos(tet) * sqrt(minor_length(1));
x2 = x1 + a;
y2 = y1 + b;
line([x1, x2], [y1, y2],'linewidth',2);

How to do numerical multiple integral (more than triple)?

How to do numerical multiple integral (more than triple) by using Matlab?
For example, I have a function,Y = Func. It has 5 var. Hence, Y= func(a,b,c,d,e). If I want to do the integration with respect to a,b,c,d,e. (var a is the first one, e is the last one.) And region of a = [0 ,b] (this is a function handle), b = [0,c], c= [0.d], d= [0,e], e=[0, Inf].
Now, here is my 'real' question. The code is below
%%%==== just some parameters ====
a=4;
la1=1/(pi*500^2); la2= la1*5;
p1=25; p2=p1/25;
sgma2=10^(-11);
index=1;
g=2./a;
syms r u1 u2 u3 u4 u5
index = -2;
powe= index ;
seta= 10^powe;
xNor = ( (u5./u1).^(a./2)+ (u5./u2).^(a./2) + (u5./u3).^(a./2)+ (u5./u4).^(a./2) + 1 ).^(2./a);
x = (xNor).^(0.5) * seta^(-1/a);
q=pi.*(la1.*p1.^(2./a)+la2.*p2.^(2./a));
%%%==== parameters end ====
fun1 = r./(1+ r.^a );
out1 = int(fun1, x, Inf) ;
out1fcn = matlabFunction(out1); %%===Convert symbolicto function handle
y = #(u5,u4,u3,u2,u1) exp(-u3.*(1+2.*... %%<== in method 3, replace as 'y= exp(-u3.*(1+2.*...'
( out1fcn )./... %%<== in method 3, replace as '( out1 )./...'
( (( (u5./u1).^(a./2)+ (u5./u2).^(a./2) + (u5./u3).^(a./2)+ (u5./u4).^(a./2) + 1 ).^(2./a)).*seta.^(-2./a)))).*...
exp(-sgma2.*q.^(-a./2).* seta.*u3.^(a./2)./...
((( (u5./u1).^(a./2)+ (u5./u2).^(a./2) + (u5./u3).^(a./2)+ (u5./u4).^(a./2) + 1 ).^(2./a)).^(a./2)) );
%%%=== method 1, not working ============ upper ,lower bound should be a number
% y1 = integral( y ,0,#(u2) u2);
% y2 = integral( y1 ,0,#(u3) u3);
% y3 = integral( y2 ,0,#(u4) u4);
% y4 = integral( y3 ,0, Inf);
%%%=== method 2, not working, y1 is already wrong ===============
%%%Undefined function 'minus' for input arguments of type 'function_handle'.
% y1 = quad( y ,0,#(u2) u2);
% y2 = quad( y1 ,0,#(u3) u3);
% y3 = quad( y2 ,0,#(u4) u4);
% y4 = quad( y3 ,0, Inf);
%%%=== method 3. not working, DOUBLE cannot convert the input expression into a double array. ==============
% y1 = int( y ,0,#(u2) u2);
% y2 = int( y1 ,0,#(u3) u3);
% y3 = int( y2 ,0,#(u4) u4);
% y4 = int( y3 ,0, Inf);
% y5 = double(y4)
A Google search showed that it is possible that by 2011 there was no standard numerical option available. This is a library you could consider. Finally, how about using Monte Carlo?
It would depend on if your function is defined symbolically or otherwise. However, if it is defined symbolically then five nested int functions would do the trick.

Finding a root in matlab, not compiling

i have to do an assignment where i have to find the depth of how much the ball is under water depending on the water's density, then i have to plot it. i don't have matlab at home but i'm using octave and for some reason it's not compiling, and it's not saying any errors. here is my code
function my_script()
% weight function
function func = weight(x,p)
func = p *pi* 4- 3 * pi*x ^2 + pi* x ^3;
% make the secant method
function root = secant(func , p, x0, x1, tol, count)
while count ~= 0
y1 = func(x0,p);
y2 = func(x1, p);
k = (x1 - x0)/(y2 - y1);
R = y2 * k;
root = x1 - R;
if abs(func(root,p)) < tol
break;
end
x0 = x1;
x1 = root;
count = count - 1;
end
%create array for depth values
y_val = [];
%input the roots into the array with a loop
for p = 0:0.01:1
t = secant(#weight, p, 0, 1, 0.000001, 1000000);
disp (t);
y_val = [y_val t];
end
% create the x - axis
x_val = 0 : 0.01 : 1;
%plotting the graph
figure;
plot (x_val, y_val)
xlabel('Density');
ylabel('Depth ');
title('Floating Sphere vs Density ');
Another way of creating what you have written is to split it into three different functions.
You'd have the weight function, weight.m,
% weight function
function func = weight(x,p)
func = p *pi* 4- 3 * pi*x ^2 + pi* x ^3;
and the secant method function, secant.m,
% make the secant method
function root = secant(func , p, x0, x1, tol, count)
while count ~= 0
y1 = func(x0,p);
y2 = func(x1, p);
k = (x1 - x0)/(y2 - y1);
R = y2 * k;
root = x1 - R;
if abs(func(root,p)) < tol
break;
end
x0 = x1;
x1 = root;
count = count - 1;
end
%create array for depth values
y_val = [];
%input the roots into the array with a loop
for p = 0:0.01:1
t = secant(#weight, p, 0, 1, 0.000001, 1000000);
disp (t);
y_val = [y_val t];
end
% create the x - axis
x_val = 0 : 0.01 : 1;
%plotting the graph
figure;
plot (x_val, y_val)
xlabel('Density');
ylabel('Depth ');
title('Floating Sphere vs Density ');
Then you'd have my_script():
function my_script()
but it is an empty function, so the output is correct! You have to have all the commands for each function finished before you define the next function.
I have a feeling that you want to take out everything from the end of the while loop onwards from the secant function and put it into the main my_script() function.
Here's your code, Octave style. Observe that I temporarily commented the "disp(t);" statement to avoid a long listing of values. This way, the plot is plotted immediately. Hopefully this helps.
function my_script
%create array for depth values
y_val = [];
%input the roots into the array with a loop
for p = 0:0.01:1
t = secant(#weight, p, 0, 1, 0.000001, 1000000);
%disp (t);
y_val = [y_val t];
endfor
% create the x - axis
x_val = 0 : 0.01 : 1;
%plotting the graph
figure(1)
plot (x_val, y_val)
xlabel('Density');
ylabel('Depth ');
title('Floating Sphere vs Density ');
endfunction
% make the secant method
function root = secant(func , p, x0, x1, tol, count)
while count ~= 0
y1 = func(x0,p);
y2 = func(x1, p);
k = (x1 - x0)/(y2 - y1);
R = y2 * k;
root = x1 - R;
if abs(func(root,p)) < tol
break;
end
x0 = x1;
x1 = root;
count = count - 1;
endwhile
endfunction
% weight function
function func = weight(x,p)
func = p *pi* 4- 3 * pi*x ^2 + pi* x ^3;
endfunction

Fill same color into different contour in matlab

I have two binary circles of one object.They don't connect together. I finished fill color for a circle. Now, I want to fill same color into two circles that don't connect together. This is my code. But it does work. Could you edit help me please?
figure
[xx yy] = meshgrid(1:384,1:384);
phi1 = (sqrt(((xx - 190).^2 + (yy - 260).^2 )) - 15);
phi2 = (sqrt(((xx - 270).^2 + (yy - 200).^2 )) - 20);
phi= sign(phi1).*sign(phi2);
phi(phi==-1)=0;
imshow(phi);
cont = contourc(phi, [0 0])';
cont = cont(2 : end, :);
patch(cont(:, 1), cont(:, 2), 'g', 'EdgeColor', 'w')
Here is a little script to draw a filled circle. You can make it into a function and use hold on and hold off to draw many circles.
r = 2;
xc = 1;
yc = 1;
st = r/100;
x1 = (-r+xc):st:(r+xc);
y1 = yc+sqrt(r^2-(x1-xc).^2);
x2 = x1(end:-1:1);
y2 = yc-sqrt(r^2-(x2-xc).^2);
x = [x1 x2];
y = [y1 y2];
patch(x,y,'g','FaceColor', 'g');
If you want to create a more general shape using implicit definition of the curve, the following works too:
[xx, yy] = meshgrid(1:384,1:384);
phi1 = 15^2 < ((xx-190).^2 + (yy-260).^2);
phi2 = 20^2 < ((xx-270).^2 + (yy-200).^2);
phi = phi1 .* phi2;
contourf(phi, [0,1]);
colormap([0,1,0;1,1,1]);