acer

32343 Reputation

29 Badges

19 years, 327 days
Ontario, Canada

Social Networks and Content at Maplesoft.com

MaplePrimes Activity


These are answers submitted by acer

Regarding your Question 2, yes, you can construct procedures that can selectively apply trig formulas according to their argument.

Here is one example of using applyrule to selectively apply a formula.

There are several other ways to accomplish your goal. For example, you could programmatically build some side-relation equations -- using chosen names or arguments -- for use within a call to simplify. Or you could utilize applyrule with a general rule and temporarily freeze the trig calls you want untouched. And most of these approaches could be abstracted further, where one writes procedures which generate the rules, or procedures which generate procedures.

restart;

 

Rdcos := proc(ff::algebraic,nm::list(algebraic):=anything)
                local tp, x;
                if nm=anything then tp := nm;
                else tp := :-identical(op(nm));
                end if;
                applyrule([cos(x::tp)^2=(cos(2*x)+1)/2,
                           cos(x::tp)^(-2)=2/(cos(2*x)+1)], ff);
              end proc:

 

Rdcos( 2*cos(t)^2-1 );

cos(2*t)

Rdcos( cos(t)^2 );

(1/2)*cos(2*t)+1/2

Rdcos( cos(p*t+q)^(-2) );

2/(cos(2*p*t+2*q)+1)

# targeted
Rdcos( cos(p*t+q)^(-2) + cos(a*t+c)^(-2), [a*t+c] );

1/cos(p*t+q)^2+2/(cos(2*a*t+2*c)+1)

foo := expand( cos(2*t) + cos(2*s)/2 + 1 + cos(2*phi) ) + cos(3*y)^2;

2*cos(t)^2-3/2+cos(s)^2+2*cos(phi)^2+cos(3*y)^2

# targeted
Rdcos(foo, [t]);

cos(2*t)-1/2+cos(s)^2+2*cos(phi)^2+cos(3*y)^2

# targeted
Rdcos(foo, [t, s]);

cos(2*t)+(1/2)*cos(2*s)+2*cos(phi)^2+cos(3*y)^2

Rdcos(foo);
simplify(%-foo);

cos(2*t)+3/2+(1/2)*cos(2*s)+cos(2*phi)+(1/2)*cos(6*y)

0

 

Download targeted_doubleangle.mw

The call rand(1 .. 2) constructs and returns a procedure which can then be called to obtained a (random) number in the given range.

If instead you call rand(1 .. 2)() then the constructed procedure will be called immediately and return an actual number.

But you don't need to call rand each time through the loop. You can call it once, outside the loop, to construct the random number generating procedure. Then, inside the loop, you can call that procedure to get actual numbers.

restart

a := Vector[row](1 .. 10)

Vector[row](%id = 18446884022782214982)

randomize()

r := rand(1 .. 2); for k to 10 do if r() < 3/2 then a[k] := "H" else a[k] := "T" end if end do

a

Vector[row](%id = 18446884022782214982)

NULL

Download CoinToss_acc.mw

You cannot sensibly assign to xi and xi[0] like that. I suggest using another name instead of xi[0]. The name xi__0 will also prettyrpint as a subscripted name.

restart;
l := -2;
m := 1;
k := sqrt(-1/(6*beta))/l;
w := (1/5)*alpha/(beta*l);
a[2] := -12*sqrt(-1/(6*beta))*alpha*m^2/(5*l*l);
a[0] := 0;
a[1] := 0;
F := -l*C[1]/(m*(C[1]+cosh(l*(xi+xi__0))-sinh(l*(xi+xi__0))));
beta := -2;
alpha := 3;
C[1] := -1/1000;
xi__0 := 1;
xi := k*x-t*w;
u := a[0]+a[1]*F+a[2]*F*F;

plot3d(u, x = -3 .. 3, t = -3 .. 3);

Any fixed image will look pixelated if you zoom in enough. Your example creates a 500-by-500 pixel image, so of course it'll look pixelated with even a moderate amount of zoom, if embedded at the same resolution.

You can either increase the resolution of the image (you had it as 500-by-500), or you can dynamically recreate the image as you zoom in.

Eg, (with all the calls in separete Execution Groups or Document Blocks!)

restart;
# Compare these next two results.
# You can chop, crop, and then rescale the one with higher resolution,
# to get the effect of zooming.

ImageTools:-Embed(Fractals:-EscapeTime:-Julia(900,
                                     -0.01*(1.0+I)+(-1.7-1.7*I),
                                     0.01*(1.0+I)+(1.7+1.7*I),
                                     -0.8 + 0.16*I,
                                     iterationlimit=70, output=layer1)):

ImageTools:-Embed(Fractals:-EscapeTime:-Julia(500,
                                     -0.01*(1.0+I)+(-1.7-1.7*I),
                                     0.01*(1.0+I)+(1.7+1.7*I),
                                     -0.8 + 0.16*I,
                                     iterationlimit=70, output=layer1)):


restart;
# Or you can regenerate and redisplay, to the modest size, as you zoom.

Explore( Fractals:-EscapeTime:-Julia(500,
                                     -0.01*(3.0+I)+(-2.0-2.0*I)/exp(zoom),
                                     0.01*(3.0+I)+(2.0+2.0*I)/exp(zoom),
                                     -0.8 + 0.16*I,
                                     iterationlimit=70, output=layer1)
         , parameters=[ zoom=0.0..4.0 ]
         , size=[500,500]
         , animate
         , placement=left );

julia_zoom.mw

Another alternative is to create a high resolution image just once, and then Explore the fixed smaller resolution (say, 500-by-500) effect of using ImageTools:-Scale to chop and scale that original, thus zooming in. That would also let you pan around. And most of the computational time would be "up front". Here's an example of that with a 6000-by-6000 starting image. (Reduce that initial size, if it uses too much memory for you.) As you can see, no matter how high the resolution of the original, eventually zooming in far enough to a fixed image willl result in a pixelated look. Hence my preference for the former scheme above, where the computation is re-done for every "zoomed" range.

restart;

N := 6000;

# This first computation takes some time. (7sec for me, but YMMV)
raw := Fractals:-EscapeTime:-Julia(N,
                                   -0.01*(1.0+I)+(-1.7-1.7*I),
                                   0.01*(1.0+I)+(1.7+1.7*I),
                                   -0.8 + 0.16*I,
                                   iterationlimit=70, output=layer1):

Z:=proc(N,cv,ch,s)
   uses ImageTools;
   if not [cv,ch]::list(posint) then
     return 'procname'(args);
   end if;
   Scale(raw[ceil(cv-(N/2-s)/2)..floor(cv+(N/2-s)/2),
             ceil(ch-(N/2-s)/2)..floor(ch+(N/2-s)/2)],
             1..500,1..500);
end proc:

Explore(Z(N, cv, ch, s),
        cv=N/4..3*N/4, ch=N/4..3*N/4, s=0..N/2,
        initialvalues=[cv=N/2, ch=N/2]);

image_zoom.mw

If your whole computation is intended to deal with floating-point arithmetic (like your example) then you can improve performance by using either evalhf or Compile, as shown below.

You have unwisely chosen to show us only a portion of your complete work. It's is possibly that other parts of your complete work will not run directly under evalhf or Compile. But in that case you could still split off the portions which do from those which do not. Help cannot be given for the parts you do not reveal to us.

You mentioned memory issues, and name the figure 4Gb, for your complete work. It's not clear at all whether that refers to bytes used or bytes allocated. It's also unclear whether you're main difficulty is in how long the computation takes, or whether the whole problem requires excessive allocation of memory.

restart; FF := proc (xx::Array, nn::integer) local gg, i, j; gg := 0; for i by 3 to nn do for j from i+3 by 3 to nn do gg := gg+1/((xx[i]-xx[j])^2+(xx[i+1]-xx[j+1])^2+(xx[i+2]-xx[j+2])^2) end do end do; return gg end proc; N := 10^4-1; A := Array(1 .. N, [seq(i^2, i = 1 .. N)], datatype = float[8]); CodeTools:-Usage(evalhf(FF(A, N)))

9999

memory used=1.36KiB, alloc change=0 bytes, cpu time=2.09s, real time=2.09s, gc time=0ns

0.166139869037898848e-2

restart; FF := proc (xx::(Array(datatype = float[8])), nn::integer) local gg, i, j; gg := 0.; for i by 3 to nn do for j from i+3 by 3 to nn do gg := gg+1/((xx[i]-xx[j])^2+(xx[i+1]-xx[j+1])^2+(xx[i+2]-xx[j+2])^2) end do end do; return gg end proc; cFF := Compiler:-Compile(FF); N := 10^4-1; A := Array(1 .. N, [seq(i^2, i = 1 .. N)], datatype = float[8]); CodeTools:-Usage(cFF(A, N))

9999

memory used=1.35KiB, alloc change=0 bytes, cpu time=219.00ms, real time=219.00ms, gc time=0ns

0.166139869037898848e-2

``

Download procedure_new_ac.mw

[edited] I've put my earlier Answer's commentary, into this attached copy of my earlier worksheet. That took about 7 minutes to find a point that attained about 1e-3 as largest equation residual of the problem cast as a global optimization problem. It turned out that minimum point could be used by fsolve to quickly find an actual root. kompletter_nachbau_v0_acer_fsolve_commented.mw

The methodology includes eliminating h[0] by equating the rhs's of two pairs from the three equations containing that that variable (after isolating for it). The variable p was treated specially, and bounds supplied for all remaining variables.

Later, it occurred to me that fsolve could be attempted for every p value attempted, following the inner DirectSearch:-SolveEquations step. I then discovered that the first p value tried was succeeding, for a variety of fixed p values within some bounds. This cut the total computation time down from about 7 minutes to about 7 seconds. And it allows finding multiple distinct roots. kompletter_nachbau_v0_acer_fsolve_3.mw

Then it occurred to me that perhaps having a starting point (for fsolve) that was close to globally optimal in the (sum of squares of residuals) optimization problem might not be necessary for fsolve to succeed in finding an actual root. So here is a revision where SolveEquations provides a feasible (all equations real-valued) starting point for fsolve, where that point may not be particularly close to optimal. The evaluationlimit option is passed to SolveEquations with a relatively small value of 1000. And this subsequently produces an actual root from fsolve. And there are no ranges supplied for any of the variables. And the whole thing takes 1.5 seconds on a fast machine.

(I've put the equations into the Startup Code region, so they don't take up space here.)
Download kompletter_nachbau_v0_DS_fsolve.mw

restart

with(DirectSearch):

str := time[real]():

gleichungssystem2 := subs({Inputparameter}, gleichungssystem1)

altraw := map(lhs-rhs, subs(convert({Inputparameter},rational,exact),
                            gleichungssystem1)):

# Equations containing h[0]
#
h0eqns := [seq(`if`(has(altraw[i], h[0]), i, NULL), i=1..nops(altraw))];

[14, 15, 16]

# Eliminate h[0]
#
extra := rhs(isolate(altraw[14],h[0])) - rhs(isolate(altraw[15],h[0])),
         rhs(isolate(altraw[16],h[0])) - rhs(isolate(altraw[15],h[0])):
alt := altraw[1..13] union {extra}:

# Conditions ensuring arguments of radicals are positive
#
conds := {seq(op(1,aaa)>=0, aaa=indets(alt,radical))}:

 

# Low evaluationlimit may suffice, as it seems what fsolve needs
# is no so much a point that is optimal (of sum of squares of residuals)
# but rather just a decent feasible point (all equations evaluate to real).
#
DSSE := DirectSearch:-SolveEquations([op(gleichungssystem2)],
                                     conds, # union {p>0, p<1e-4},
                                     evaluationlimit=1000):

# Use previous optimal point as initial point to solve those
# same equations. (Weird, that SolveEquation doesn't do this bit.)
#
fans := fsolve(alt, remove(has,{op(DSSE[3])},h[0]));

{p = 0.5873104761e-4, T[0] = -3226.477932, T[1] = -10389.65995, T[2] = -13287.95780, T[3] = -5690.196806, T[4] = -8730.784993, T[5] = -10039.07912, T[6] = 3758.058761, T[7] = 3822.377886, T[8] = 4927.420763, T[9] = 5853.670172, T[10] = 8255.256673, T[11] = 9846.839687, T[12] = 19780.45791, T[13] = 48411.97339}

# Evaluate all original equations at `fans` values, and compute
# h[0] as optimization problem.
#
h0sol := SolveEquations( [op(eval(select(has,gleichungssystem2,{h[0]}), fans))] ):
h0sol[3];

[h[0] = HFloat(-0.00817591521032101)]

# Now fsolve original equations using previous fsolve result
# along with new optimizing h[0] value as starting point.
#
final := fsolve(gleichungssystem2, fans union {op(h0sol[3])});

{p = 0.5873104761e-4, T[0] = -3226.477932, T[1] = -10389.65995, T[2] = -13287.95780, T[3] = -5690.196806, T[4] = -8730.784993, T[5] = -10039.07912, T[6] = 3758.058761, T[7] = 3822.377886, T[8] = 4927.420763, T[9] = 5853.670172, T[10] = 8255.256671, T[11] = 9846.839687, T[12] = 19780.45791, T[13] = 48411.97339, h[0] = -0.8175915566e-2}

map(rhs-lhs, eval(gleichungssystem2, final));

{-0.1e-5, -0.2e-9, -0.1e-9, -0.5e-10, -0.24e-10, 0., 0.1e-9, 0.6e-9, 0.13e-8, 0.15e-8, 0.16e-8, 0.2e-8, 0.3e-8}

(time[real]() - str)*'seconds';

1.498*seconds

 

 

Firstly, you need to upload an actual Worksheet or Document, if you want us to be able to see precisely what you have. Use the big green arrow in the Mapleprimes editor pane, to upload and attach.

You need to fix your brackets, which don't always match in several of your examples.

Eg. the call to the eval command in your second proc has mismatched round brackets. It's missing the closing bracket.

And in one of your calls to the procedure you have mismatched square brackets.

There are other syntax problems, some possibly related to attempts at getting implicit multiplication. But it's impossible to be sure without an actual upload.

If 2D Input in a Document is too much trouble for you, you can change the preference to be 1D plaintext Maple notation in  Worksheet. (I suggest this, for new users.)

eq := a*b=a*c;

                        eq := a b = a c

gcd(rhs(eq), lhs(eq))

                               a

map(`/`, eq, gcd(rhs(eq), lhs(eq)));

                             b = c

The assignment W:=V does not make W into a distinct and independent copy of V. It makes W a reference to V. And so, as written, your procedure acts in-place on V.

Change that line to W:=copy(V) if you do not want the operations on entries of W to be operations on V.

See also Section 6.7 of the Programming Manual, Using Data Structures with Procedures.

restart;

switch := proc(V::Vector)
description "This procedure is supposed to take a Vector V and switch entries 1 and 2";
local W,a,b;
W:= copy(V);
a:= W[1];
b:= W[2];
W[1 ] := b;  
W[2] :=a;
W
end proc:

V1:=Vector([1,3,5]);

Vector(3, {(1) = 1, (2) = 3, (3) = 5})

V2:=switch(V1);

Vector(3, {(1) = 3, (2) = 1, (3) = 5})

V1;

Vector(3, {(1) = 1, (2) = 3, (3) = 5})

 

Download awass_copy_vs_inplace.mw

Why presume that the plot command is thread-safe? (It isn't.) Most Library commands are not.

There are many ways for a Library procedure (or module) to be thread-unsafe. (Use of declared globals in procedures is just one of several ways.)

As of Maple 2018, there is no working mechanism to query for thread-safety of an arbitrary Library procedure.

Nor is there any mechanism to work around partial thread-safety by blocking only the thread-unsafe bits.

If such mechanisms existed then there would likely be a great deal more use of the Threads package by other stock commands.

You could also try Grid:-Seq , but be forewarned that it has even worse overhead than Threads, so is less suitable for fine-grained lower level parallelism. And even Threads is not very good there.

But you might be able to effectively distribute calls to a proc that produced many plots of the total sequence. Suppose you wanted 100 frames altogether. You may be able to get a reasonable improvement by calling Grid:-Seq on a call to a custom procedure that individually constructed say 1/4 or 1/2 of those 100 for each call.

If you have executed something like with(IrisData), so that the name Species is rebound, then you may need to reference the global in order to make the kind of indexed reference you have in your posted image of a call to GridPlot.

That is, use the name  IrisData[':-Species']  instead of just IrisData[Species] .

At the end of this attachment I explain the same thing, using the `Sepal Length` example which throws an error when your attached Worksheet is executed as it is. That is, you can always use IrisData[':-`Sepal Length`'] , whether you have or have not executed with(IrisData).

restart

``

with(Statistics)

 

Les Iris de Fisher

 

Les données utilisées ici sont célèbres. Elles ont été collectées par Edgar Anderson . Ce sont les mesures en centimètres des variables suivantes :

1. 

 longueur du sépale (Sepal.Length),

2. 

largeur du sépale (Sepal.Width),

3. 

longueur du pétale (Petal.Length)

4. 

 largeur du pétale (Petal.Width)

pour trois espèces d’iris :

1-Iris setosa,

2-Iris versicolor

3-Iris.virginica.
Sir R.A. Fisher a utilisé ces données pour construire des combinaisons linéaires des variables permettant de séparer au mieux les trois espèces d’iris

 

``

``

 

 

 

 

 

 

NULL

Accès aux données internes

 

NULL

Pour connaître  les données de la distribution de base :

kernelopts(datadir); FileTools:-ListDirectory(FileTools:-JoinPath([kernelopts(datadir), "datasets"]))

["sunspots.csv", "builtin.db", "air_passengers.csv", "canada_crimes.csv", "iris.csv", "fertility_rates.csv"]

Afficher les données

 

IrisData := Import(FileTools:-JoinPath(["datasets", "iris.csv"], base = datadir))

_m139706550967776

NULL

Describe(IrisData)

IrisData :: DataFrame: 150 observations for 5 variables
Sepal Length:  Type: anything  Min: 4.30  Max: 7.90
Sepal Width:   Type: anything  Min: 2.00  Max: 4.40
Petal Length:  Type: anything  Min: 1.00  Max: 6.90
Petal Width:   Type: anything  Min: 0.10  Max: 2.50
Species:       Type: anything  Tally: ["versicolor" = 50, "setosa" = 50, "virginica" = 50]

NULL

CLabels := ColumnLabels(IrisData)

[`Sepal Length`, `Sepal Width`, `Petal Length`, `Petal Width`, Species]

SunSpotsData := Import(FileTools:-JoinPath(["datasets", "sunspots.csv"], base = datadir))

NULL

Describe(SunSpotsData)

SunSpotsData :: DataFrame: 314 observations for 2 variables
Date(Date:-year,Date:-month,Date:-day,Date:-hour,Date:-minute,Date:-second,timezone = Date:-timezone,coefficient = Date:-coeff):  Type: anything  Min: 1700.00  Max: 2013.00
Mean Sunspot Number:                                                                                                              Type: anything  Min: 0.00  Max: 190.20

FertilityData := Import(FileTools:-JoinPath(["datasets", "fertility_rates.csv"], base = datadir))

NULL

Describe(FertilityData)

FertilityData :: DataFrame: 36 observations for 1 variables

Fertility Rate - 2015:  Type: anything  Min: 1.31  Max: 1.96

PassengersData := Import(FileTools:-JoinPath(["datasets", "air_passengers.csv"], base = datadir))

NULL

Describe(PassengersData)

PassengersData :: DataFrame: 144 observations for 1 variables
Monthly Passengers:  Type: anything  Min: 104.00  Max: 622.00

CrimeData := Import(FileTools:-JoinPath(["datasets", "canada_crimes.csv"], base = datadir))

Describe(CrimeData)

CrimeData :: DataFrame: 13 observations for 5 variables

Violent Crime:          Type: anything  Min: 786.62  Max: 7934.95
Property Crime:         Type: anything  Min: 2100.84  Max: 23171.26
Other Criminal Code:    Type: anything  Min: 450.29  Max: 13834.45
Criminal Code Traffic:  Type: anything  Min: 211.57  Max: 1689.95
Federal Statute:        Type: anything  Min: 215.34  Max: 1331.87

NULL

NULL

NULL

Manipulation de IrisData

 

NULL

IrisData

_m139706550967776

IrisData[Species]

NULL

convert(%, set)

{"setosa", "versicolor", "virginica"}

NULL

IrisData[`Sepal Length`]

_m139706541154592

NULL

IrisData[`Sepal Width`]

_m139706541155936

NULL

NULL

IrisData[1 .. 4]

_m139706537258624

NULL

NULL

IrisNum := IrisData[() .. -2]

_m139706551924128

NULL

IrisData[() .. -3]

_m139706540366816

NULL

NULL

NULL

Sommaire statistique

 

 

interface(displayprecision = 4)

DataSummary(IrisNum, summarize = embed)

NULL

Normaliser les données et Histogrammes

 

Median(IrisNum)

_m139706533649376

Histogram(IrisData[:-`Sepal Length`], discrete)

Scale(IrisData[:-`Sepal Length`])

_m139706534007936

scaled := %

_m139706534007936

Mean(scaled), StandardDeviation(scaled)

HFloat(-1.3796371452675278e-15), HFloat(0.9999999999999989)

Histogram(scaled, discrete)

scaled2 := Scale(IrisData[:-`Sepal Length`], center = Median, scale = MedianDeviation)

_m139706691348896

Median(scaled2), MedianDeviation(scaled2)

HFloat(0.0), HFloat(1.0)

Histogram(scaled2, discrete)

Scale(IrisNum)

_m139706541149440

allscaled := %

_m139706541149440

Histogram(allscaled[1], discrete)

NULL

NULL

Aggregate

 

Aggregate(IrisData, :-Species)

_m139706550990496

Aggregate(IrisData, :-Species, function = StandardDeviation, tally)

_m139706688688416

Aggregate(IrisNum, :-`Petal Width`, bounds = quantiles(0, 1/3, 2/3, 1), tally)

_m139706554297024

NULL

Visualisation

 

NULL

with(IrisData)

[`Sepal Length`, `Sepal Width`, `Petal Length`, `Petal Width`, Species]

NULL

LineChart(`Sepal Length`)

NULL

LineChart(IrisNum)

NULL

AreaChart(`Sepal Length`, markers = false)

NULL

AreaChart(IrisNum, datasetlabels = [`$`(``, 150)], markers = false)

NULL


Tom Leslie suggested the following, for before with(IrisData) is executed.
That worked, before that calls to with. But it doesn't work afterwards.

Histogram(IrisData[`Sepal Length`], discrete)

Error, (in DataFrame:-?[]) invalid row index into DataFrame: non-Boolean DataSeries

 

The following works both before and after calling with(IrsiData) .
This seems like your problem in the posted image of code that
called GridPlot.

 

Histogram(IrisData[:-`Sepal Length`], discrete)

 

The following works even if someone assigns any value to the unprotected
name `Sepal Length`.

 

:-`Sepal Length` := 55; Histogram(IrisData[':-`Sepal Length`'], discrete)

55

 

Download IRISdata_ac.mw

 

 

Sometimes the assuming command can get some desired results, without the awkwardness of managing names whose previous assumption have been cleared.

restart;

assume(x>0);

# It can be handy to keep a reference to the
# assumed name, for use below.
#
xa := x;

x

f := sqrt(x);

x^(1/2)

is(f, real);

true

# Remove assumption on x
#
x := 'x';

x

# These are distinct, since f contains the
# assumed name.
#
f - sqrt(x);

x^(1/2)-x^(1/2)

# Substitute for the assumed name.
#
eval(f, xa=x);

x^(1/2)

# Now we can mix the two forms
#
eval(f, xa=x) - sqrt(x);

0

restart;

f := sqrt(x);

x^(1/2)

is(f, real);

false

is(f, real) assuming x>0;

true

 

Download clear_assmp.mw

[edited] I may well have misinterpreted this Question earlier.

Originally I interpreted the question as being about why the timing differences varied, using the same mechanism.

Carl's response below makes me think that the OP may instead be asking why the timing differnce using time[real] varies from that using ProcessClock. So now this Answer has been rewritten.

But I'd still say that comparing such very small timings isn't generally sound. Moreover, in the posted examples the overhead of the time-queries, and the order of their execution, and the printing of output and communication with the GUI, may all interfere. So I don't think that this is a robust testing example for very small timings.

In an earlier Question I recemmended that the OP use the time[real] command, for finding real-world wall clock elapsed time. I'll stand by that. I don't advocate using ProcessClock for that purpose, as I don't think that it's suitable for the job.

To compare wall-clock time, use the command time[real]() at start and at finish, and then take the difference.

This could measure how long it takes a student to respond, between steps or in total, in your interactive application.

Try this.

animation_CommandPlease_ac.mw

There are various keywords for controlling an animation within a Plot Component. These are documented on the PlotComponent Help page.

[edited] You did not say, at all, what kind of animation of sin(x) (or whatever) that you wanted. So I made one up. Tom made up another. The key thing is the use of the SetProperty command and the play keyword, I think. That's is the purpose of this line of code that I wrote at the end of the Button's action code,
   SetProperty("Plot0", ':-play', true, ':-refresh'=true);

First 161 162 163 164 165 166 167 Last Page 163 of 336