Component State - Maple Programming Help

 Component State

A new construct in the DocumentTools:-Components package called State allows you to manage computation state that will survive through a saved worksheet and through restart.  Programming your applications using this construct also makes it easier to embed multiple different versions of the same application, with different data and options. Consider the following two interactive pie chart examples created using the package below.

 Options Annular: 3-D: Color: blueblue/rosebrightbrowndark graydefaultgreengreen/bluegreen/violetlight bluelight graypurpleredtanyellowyellow/red Explode: none ABCDEFG Labels: defaultnonerelativeabsolute Outline: Sector: 0..3600..180180..3600..90

$\mathrm{PieChartPlot}\left(\left[1,1,3,4,4,5,5,5,7\right]\right);$

 Options Annular: 3-D: Color: blueblue/rosebrightbrowndark graydefaultgreengreen/bluegreen/violetlight bluelight graypurpleredtanyellowyellow/red Explode: none 13457 Labels: defaultnonerelativeabsolute Outline: Sector: 0..3600..180180..3600..90

The PieChartPlot command module is defined below.  The SetDefaults command creates a state variable, which is used to hold all mutable information relating to this application, including the plot data and options settings.  Additionally, the InsertContent command now accepts a state option that can be used with the state component variable name.  When reexecuting—even with different data—the application can call GetProperty("",'contentstate') in order to access the state of the application that is being replaced.  In this way it can inherit whatever properties it wants from the previous application and preserve them when displaying the new data.

Small Example with Explanation

This example defines an application that uses a slider to move along the $x$-axis of a plot.  When you drag the slider to the right, the plot view will move to the right along the $x$-axis.  The slider will then snap back to the middle position, allowing you to grab it and move it to the right again.  In this way you can move further and further along the $x$-axis.

Tip: To interact with this example, open this help page as a worksheet.

The application can be described as follows:

 • Highlighted in blue are the main components—Plot, Slider, and hidden State
 • Highlighted in orange is the variable created as part of the State component description.  Make sure this occurs earlier in the code than anything that uses it.
 > moveLeftRightApp := proc( fn )     local stateVariable, xmap;     uses DocumentTools, DocumentTools:-Layout, DocumentTools:-Components;     #define the application layout and components     xmap := InsertContent( Worksheet( Table( Column(), Row( Cell( Textfield(        State('stateVariable', position = 0, func = fn),        Plot(identity="Plot0"),        "\n",        Slider(-10..10, 'identity'="Slider0", 'position'=0, 'width'=400,               'action'=sprintf("slideX(%s,\"Plot0\",\"Slider0\")",stateVariable)))     ) ) ) ),     'output'=table );     #set the initial plot (slideX is defined below)     slideX(stateVariable,xmap["Plot0"],xmap["Slider0"]); end proc:

The action handler—the code that gets run when someone moves the slider—is defined below.  It gets passed the state variable, from which it can see and update the current position offset.  The position records how far left or right we have scrolled along the $x$-axis.  We get the slider value, adjust our position, redraw the moved plot, and snap the slider back to the middle.

 > slideX := proc( stateVar, plotCompName, sliderCompName )     local delta, p;     delta := DocumentTools:-GetProperty(sliderCompName,'value');     stateVar:-position := stateVar:-position + delta;     p := plot(stateVar:-func,x=stateVar:-position-10..stateVar:-position+10, 'view'=['default',-1..1]);     DocumentTools:-SetProperty(plotCompName,'value', p);     DocumentTools:-SetProperty(sliderCompName,'value',0); end proc:

Note that the above two procedures could be put in startup code (via Edit>Startup Code), or they can be auto-initialized by setting Format>AutoExecute>Set.  If either is done, when this worksheet is loaded both of these procedure definitions will be executed.

Now that the app and handler are defined, we can run a command to insert the content:

 > moveLeftRightApp( Re(x^(-.1))*sin(x) );



Peeking into Existing Content To "Remember" Settings

In the following modification to moveLeftRightApp, we call DocumentTools:-GetProperty("",'contentstate');   This will return non-NULL if the content that we are inserting is going to replace existing content. We then additionally check if we are about to replace the same kind of content—by putting a unique signature on the state variable.  If the signatures match, then we can initialize the new app based on some of the settings of the old app.  For example, here we start at the same position that was previously left.

Two things need to happen:

 • Check for previous content and access that content's state.
 • Call InsertContent with the state option, giving it the name of the state variable.

 > moveLeftRightApp2 := proc( fn )     local stateVariable, prev, pos, xmap;     uses DocumentTools, DocumentTools:-Layout, DocumentTools:-Components;     # check if there was prior state in the previous output                     prev := GetProperty("",'contentstate');                     if prev::module('signature') and prev:-signature = "moveLeftRight" then         pos := prev:-position;     else         pos := 0;     end if;     #define the application layout and components     xmap := InsertContent( Worksheet( Table( Column(), Row( Cell( Textfield(        State('stateVariable', 'position' = pos, 'func' = fn, 'signature'="moveLeftRight"),        Plot(identity="Plot0"),        "\n",        Slider(-10..10, 'identity'="Slider0", 'position'=0, 'width'=400,               'action'=sprintf("slideX(%s,\"Plot0\",\"Slider0\")",stateVariable)))     ) ) ) ),     'state'=convert(stateVariable,string),     'output'=table );     #set the initial plot (slideX is defined below)     slideX(stateVariable,xmap["Plot0"],xmap["Slider0"]); end proc:

If you open this help page as a worksheet you can try reexecuting the following example with different values for the negative exponent.  Notice that the $x$-axis offset remains the same between executions.

 > moveLeftRightApp2( Re(x^(-.5))*sin(x) );

 >