Is it possible to plot from inside a procedure in Maple? - maple

I was hoping the procedure below would create a plot. It does not
xsquared := proc() plot(x^2); return ; end proc
xsquared()
Is there a reason, and is there a workaround for automating plot creation?

Plots get rendered (ie. displayed) by virtue of being printed.
Your procdure does indeed create a plot, but your procedure also finishes by returning NULL. That is, you procedure is written to throw away the created plot, rather than return it.
Let's alter your procedure so that it returns the plot instead of throwing it away. (There are shorter ways to do this, but I'll make it assign the plot to a local variable, as you might want this more general usage later on.)
xsquared := proc()
local P;
P := plot(x^2);
return P;
end proc;
Now lets call xsquared but suppress the output by terminating with a full colon. We'll assign the result to some name, to keep the example more general.
Notice that no plot is rendered. That's because we suppressed the result from being printed, by terminating with a full colon.
This := xsquared():
If we print the value assigned to This then we'll see a plot rendered.
This;
That was done at the "top level", outside any procedure. So we were able to print the value assigned to This merely by evaluating it.
Another way would be to simply avoid suppressing the output from the call to xsquared, by terminating with a semicolon. Recall that merely printing a plot will cause it to be rendered. So allowing the output to print will cause it to be rendered.
xsquared();
That leaves the behaviour of having a procedure cause the plot to be rendered even if the plot (plot structure) is not actually returned by any call to that procedure. Once again, recall that a plot gets rendered when it is printed. We can force the printing of the plot from within the procedure.
xsquared := proc()
local P;
P := plot(x^2);
print(P);
return NULL;
end proc;
xsquared():
The above call to the new version of xsquared causes the plot to be printed and rendered even though it is not returned by the call.

Related

How to trace out a curve

I am working on a project dealing with closed curves. I want to trace out a curve swept out by a coordinate vector moves. Just to get the code down I'm trying to accomplish the goal using a circle. I am able to animate the motion of the vector with the following command
animate(arrow, [[cos(2*Pi*n/1000),sin(2*Pi*n/1000)], shape = arrow,
scaling = constrained], n=0..1000, frames = 100);
Is there a way to trace the circle that is swept out by this curve. Again my goal is to be able to do this for an arbitrary parameterized curve. Any help is greatly appreciated.
Here is a basic but verbose way to do it,
restart;
plots:-animate(plots:-display,
[ 'plots:-arrow([cos(2*Pi*n/1000),
sin(2*Pi*n/1000)],
shape = arrow)',
'plot([cos(2*Pi*nn/1000),
sin(2*Pi*nn/1000),nn=0..n])',
scaling = constrained ],
n=0..1000, frames = 30);
If that seems complicated then perhaps it's good to review Maple's evaluation rules for procedure calls. Maple normally evaluates the arguments before passing them to the procedure.
But sometimes you don't want that evaluation to occur until, say, the procedure can provide a numeric value for a parameter in some argument. That is to say, sometimes you want to avoid premature evaluation of the arguments.
The seq command deals with this by having so-called special-evaluation rules, where the evaluation of the argument is delayed unto the seq index variable takes on it individual values.
The plots:-animate command allows you to deal with it by separating the main command from its arguments (which get passed separately, in a list). That is often adequate, but not when those arguments in the list also contain full calls to plotting commands which would not evaluate ok (ie. without error, up front) until the animating parameter gets its actual values.
That is why I also used single right-quotes to delay the evaluation of the calls to plots:-arrow and plot in the example above. Those evaluations need to wait until the animating parameter n takes on its actual numeric values.
And another, related approach is to create a procedure which accepts the animating parameter value and constructs a whole frame.
F := proc(n)
plots:-display(
plots:-arrow([cos(2*Pi*n/1000),
sin(2*Pi*n/1000)],
shape = arrow),
plot([cos(2*Pi*nn/1000),
sin(2*Pi*nn/1000),
nn=0..n]),
scaling = constrained);
end proc:
This can be handy as it lets you test beforehand.
F(307.2);
(I didn't bother to optimize F, but you could notice that the sin and cos calls happen twice, and instead do them just once inside the procedure and assign to local variables. That might make things easier when you go on to more involved parametric curves.)
Now the calls to plots:-animate can be terse,
plots:-animate(F, [ n ],
n=0..1000, frames = 30);
The above produces the same animation as before.
Here's another way, by constructing a list containing a sequence of all the frames.
Note that, as written, evaluating F at unknown, unassigned name n produces an error.
F(n);
Error, (in plots/arrow) invalid input: plottools:-arrow
expects its 3rd argument, pv, to be of type {Vector, list,
vector, complexcons, realcons}, but received 0.5000000000e-1*
(cos(0.6283185308e-2*n)^2+sin(0.6283185308e-2*n)^2)^(1/2)
The error occurs because n does not have a numeric value.
But the special-evaluation rules of the seq command allow us to proceed anyway, since it delays the evaluation of F(n) until n gets its values.
# note termination with full colon, to suppress output
S := [seq(F(n), n=0..1000, (1000-0)/(30-1))]:
nops(S); # check that we really got 30 frames
30
plots:-display(S, insequence=true);
That last command also displays the same 30-frame animation.

if statement block in Simulink accumulates last true value

If statement in Simulink is not like in a programming language, it accumulates last true value untill it occurs again.
As it can be seen here, when random value is lower than 0.5 (if condition) output dosn't give zero as one normally expects from if statement.
What is the proper way to use an if? (Where preferably I don't want to put saturation and matlab function)
The Out block within the If Action subsystem has a property to either hold or reset its output when disabled. The default is to hold; you want it to reset. You'll also need to specify 0 as the initial condition, which is what it'll reset to.
So far what I could do this to use an elementary matlab function;
function y = fcn(u)
if u>0
y = u;
else
y = 0;
end
end
but I wondered it would be a proper way of using if block.
Change out blocks property in If action subsystem to 'reset', it looks like it is 'held' in your current implementation

How to deal with error 'Undefined function 'times' for input arguments of type 'struct'.'

A matlab program which was previously working for fine for about 6 months has starting giving the error
'Undefined function 'times' for input arguments of type 'struct'.' The line where this appears is
sampleData.allDiameters= sampleData.allDiameters* pixelToMicron;
When I try methods such as a loop or saving as another variable from one of the structure fields it saves the new variable as a structure, which previously it did not do. Some examples of this:
for n=1:length(measurements)
x=measurements(n); %saves x as 1x1 struct
measurements(n)=x*pixelToMicron;
end
%%%
measurements=sampleData.allDiameters; %saves measurements as a 276x1 struct
This was triggered after a small loop was added which has since been deleted. This was a while loop and hadn't even been included in the main program. Nothing else was edited. For clarity this is the loop (as far as I got with it)
function [sampleData]=sphereCheck(sampleData)
%for each object check how spherical each object is
%Measurement2: use regionprops to measure and record the x and y position
%of the corner of the smallest box which bounds the object [xpos ypos xwidth ywidth]
measurements2=regionprops(sampleData.binImage, 'BoundingBox');
sampleData.allDiameters
counter=1
while counter<length(measurements2)
%[~ ~ a b]=measurements2(counter);
end
I would like know how I can get the structures multiplying again or how I can access the data from the structure to perform operations on it.

Too many input arguments error

I am trying to run my function. it shows
[root, ni]=value1(xu,xl,acceptable)
Error using value1
Too many input arguments.
function[root, ni]=value1(xu,xl,acceptable)
fu=HW10B(xu);
fl=HW10B(xl);
Err=1;
N=0;
if fu*fl>=0
end
while Err>=acceptable;
m=(xu+xl)/2;
fm=HW10B(m)
if fm*fu<0;
fl=m;
else fu=m;
Err=abs(xu-xl)/xu*100;
end
N=N+1;
end
function [ y] = HW10B( x)
%equation of x
y=3*x^3-8*x^2-4*x+9;
end
root=m;
ni=N;
end
function[m, N]=value1(xu,xl,acceptable)
y=#(x)3*x.^3-8.*x.^2-4.*x+9;%//Used anonymous function instead of private
fu=y(xu);%//Used above definition
fl=y(xl);
Err=1;%//Initialise error
N=0;%//Initialise counter
while Err>=acceptable && N<1e4;%//check for convergence
m=(fu+fl)/2;%//Get new midpoint
fm=y(m);%//Get value at midpoint
if fm*fu<0;%//Get left or right value to move
fl=m;
else
fu=m;
Err=abs(fu-fl)/fu*100;%//Calculate the error
end
N=N+1;%//Update iteration counter
end
end
Call it from the command line:
xu=15;xl=2;acceptable=1e-3;
[root, ni]=value1(xu,xl,acceptable)
root =
2.7554
ni =
29
As you can see I cleaned up your code quite a bit. Using the two separate storage variables at the end of the code was just taking up more space than necessary. The if statement fu*fl>0 did not do anything, thus I chucked it out. Finally, you needed to update your values in your functions, thus using the fl, fx and fm, not the xu and xl.
If you call the function exactly as I showed you from the command line (with your own values of course), it should not throw any errors.
What happens in your original code is that you calculate everything once for the input variables, get an error which is larger than acceptable and therefore executes again, taking the same input arguments, returning the same error as before, which is still larger than acceptable. This is what we call an infinite loop. I suggest you check for it using a maximum number of iterations, i.e.
while Err>=acceptable && N<1e4
and change the 1e4 to whatever maximum number of iterations you want to have. If you accidentally end up going infinite, this counter will kill it without having to resort to crtl-c or equivalents.

matlab zoom callback error associated with text function

While trying to execute generation of a series of text boxes in a post-zoom callback function in Matlab, a number of errors are generated, the trace of which is unhelpful in diagnosing and resolving the problem. When the text generation is in the main body of code as follows, the code executes properly and there is no issue executing the minimal post-zoom callback function:
string='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
offset=8;
h=figure;
z=zoom(h);
set(z,'ActionPostCallback',#post_callback);
[ax,plt1,plt2]=plotyy(14:20,1:7,15:17,1:3,#bar,#bar)
ylim([0 10]);
hold on;
set(plt2,'FaceColor','r');
xLim=xlim(gca);
for i=xLim(1)+1:xLim(2)-1
text(i,8,string(i-offset+1),'Clipping','on');
end
function post_callback(obj,evd)
xLim = get(evd.Axes,'XLim');
However, if the text box generation is moved to the #post_callback function, a series of errors result:
string='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
offset=8;
h=figure;
z=zoom(h);
set(z,'ActionPostCallback',#post_callback);
[ax,plt1,plt2]=plotyy(14:20,1:7,15:17,1:3,#bar,#bar)
ylim([0 10]);
hold on;
set(plt2,'FaceColor','r');
function post_callback(obj,evd)
xLim = get(evd.Axes,'XLim');
for i=xLim(1)+1:xLim(2)-1
text(i,8,string(i-offset+1),'Clipping','on');
end
Those errors are, as described in this problem:
Warning: An error occurred during the mode callback.
> In uitools.uimode.fireActionPostCallback at 14
In zoom>local2DButtonUpFcn at 1332
In hgfeval at 63
In uitools.uimode.modeWindowButtonUpFcn at 46
In uitools.uimode.setCallbackFcn>localModeWindowButtonUpFcn at 58
Could someone please enlighten me as to the root cause of the errors?
The error seems to be the same. You should try to use the debugger here. Set a breakpoint in your post callback function. However, there are a few problems in your code. Some are implementation issues, some other problems does not do what you ask them too. You seems to have some programming experience, so I guess that most implementation issue are just bugs. I will list problems and solutions.
1) I cry when I see that you use string as a variable. String is an abstract type (obselete in matlab now since later versions uses char vectors). use instead some other name like str or myString.
2) Unless offset and your variable string is not declared global, they will not be inside the scope of post_callback. Different from C or C++, a variable does not become global when defined in "main" (since you do not even define a main method). If you want to use string or offset inside of post_callback, you must define them inside their scope (inside the function).
3) the loop variable i must not be a cell. Use the method from the previous question to convert it to a double vector.
4) The loop variable i must be an integer in:
text(i,8,string(i-offset+1),'Clipping','on');
since string is defined a variable and variable indices must be integers, xLim does not necessary need to be an integer.
5) I do not think text will give the expected output here. What text does is creating a string and linking it to a point on the plot. This means that every time you zoom you will have a new text in the plot. Unless the texts are located at exactly the same place (which may be possible, but will reqire a lot of work) the plot will look really ugly. If possible, place the text strings in the way that you do in example 1 and remove it from post_callback.