Skip to content

Commit

Permalink
Start of a Manipulate() function
Browse files Browse the repository at this point in the history
  • Loading branch information
axkr committed Jul 13, 2019
1 parent 17da8ff commit 9525f04
Show file tree
Hide file tree
Showing 12 changed files with 3,124 additions and 2,305 deletions.
20 changes: 20 additions & 0 deletions symja_android_library/doc/functions/Manipulate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## Manipulate

```
Manipulate(plot, {x, min, max})
```

> generate a JavaScript control for the expression `plot` which can be manipulated by a range slider `{x, min, max}`.
**Note**: This feature is not available on all supported platforms.

### Examples

In the console apps, this command shows an HTML page with a JavaScript plot control,
where the value of the variable `a` can be manipulated by a slider in the range `[0..10]`.

```
>> Manipulate(Plot(Sin(x)*Cos(1 + a*x), {x, 0, 2*Pi}), {a,0,10})
```

2 changes: 2 additions & 0 deletions symja_android_library/doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ for a full description of their possible arguments, options, etc., see their ent
* [MachineNumberQ](functions/MachineNumberQ.md)
* [MangoldtLambda](functions/MangoldtLambda.md)
* [ManhattanDistance](functions/ManhattanDistance.md)
* [Manipulate](functions/Manipulate.md)
* [Map](functions/Map.md)
* [MapIndexed](functions/MapIndexed.md)
* [MapThread](functions/MapThread.md)
Expand Down Expand Up @@ -803,3 +804,4 @@ for a full description of their possible arguments, options, etc., see their ent
* [Xor](functions/Xor.md)
* [YuleDissimilarity](functions/YuleDissimilarity.md)
* [Zeta](functions/Zeta.md)

Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,9 @@ public class ToggleFeature {
* If <code>true</code>, enable experimental financial functions
*/
public static boolean FINANCE = true;

/**
* If <code>true</code>, enable experimental f<code>MANIPULATE()</code> function
*/
public static boolean MANIPULATE = true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package org.matheclipse.core.builtin;

import java.io.IOException;

import org.matheclipse.core.basic.Config;
import org.matheclipse.core.basic.ToggleFeature;
import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.eval.interfaces.AbstractEvaluator;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.ISymbol;

public class ManipulateFunction {
private final static String MATHCELL = //
"MathCell( id, [ `1` ] );\n" + //
"\n" + //
"parent.update = function( id ) {\n" + //
"\n" + //
// " var phase = document.getElementById( id + 'phase' ).value;\n" + //
" `2`" + //
"\n" + //
" `3`" + //
// " var p2 = plot( x => Math.cos(x-phase), [0, 2*Math.PI], { color: 'purple' } );\n" + //
// "\n" + //
// " var data = [ p1, p2 ];\n" + //
"\n" + //
" var config = { type: 'svg' };\n" + //
"\n" + //
" evaluate( id, data, config );\n" + //
"\n" + //
"}";

/**
*
* See <a href="https://pangin.pro/posts/computation-in-static-initializer">Beware of computation in static
* initializer</a>
*/
private static class Initializer {

private static void init() {
F.Manipulate.setEvaluator(new Manipulate());
}
}

private static class Manipulate extends AbstractEvaluator {

@Override
public IExpr evaluate(final IAST ast, EvalEngine engine) {
try {
if (ast.arg1().isAST(F.Plot)) {
IAST plot = (IAST) ast.arg1();
if (plot.size() == 3 && plot.arg2().isList()) {
IAST plotRange = (IAST) plot.arg2();
if (plotRange.isAST3() && plotRange.arg1().isSymbol()) {
ISymbol plotSymbol = (ISymbol) plotRange.arg1();
if (ast.arg2().isList()) {
IAST sliderRange = (IAST) ast.arg2();
if (sliderRange.isAST3() && sliderRange.arg1().isSymbol()) {
String js = MATHCELL;
String sliderSymbol = OutputFunctions.toJavaScript(sliderRange.arg1());

// { type: 'slider', min: 0, max: 2*Math.PI, name: 'phase', label: 'phase' }

StringBuilder slider = new StringBuilder();
slider.append("{ type: 'slider', min: ");
slider.append(OutputFunctions.toJavaScript(sliderRange.arg2()));
slider.append(", max: ");
slider.append(OutputFunctions.toJavaScript(sliderRange.arg3()));
slider.append(", name: '");
slider.append(sliderSymbol);
slider.append("', label: '");
slider.append(sliderSymbol);
slider.append("' }\n");
js = js.replaceAll("`1`", slider.toString());

// var a = document.getElementById( id + 'a' ).value;
StringBuilder variable = new StringBuilder();
variable.append("var ");
variable.append(sliderSymbol);
variable.append(" = document.getElementById( id + '");
variable.append(sliderSymbol);
variable.append("' ).value;\n");
js = js.replaceAll("`2`", variable.toString());

// plot( x => (Math.sin(x*(1+a*x))), [0, 2*Math.PI], { } )
StringBuilder function = new StringBuilder();
function.append("var p1 = plot( ");
function.append(OutputFunctions.toJavaScript(plotSymbol));
function.append(" => (");
function.append(OutputFunctions.toJavaScript(plot.arg1()));
function.append("), [");
function.append(OutputFunctions.toJavaScript(plotRange.arg2()));
function.append(", ");
function.append(OutputFunctions.toJavaScript(plotRange.arg3()));
function.append("], { } );\n");
// var data = [ p1, p2 ];
function.append(" var data = [ p1 ];");

js = js.replaceAll("`3`", function.toString());

return F.JSFormData(js, "mathcell");
}
}
}
}
}
} catch (IOException ioex) {
if (Config.SHOW_STACKTRACE) {
ioex.printStackTrace();
}
} catch (RuntimeException rex) {
if (Config.SHOW_STACKTRACE) {
rex.printStackTrace();
}
}
return F.NIL;
}

@Override
public int[] expectedArgSize() {
return IOFunctions.ARGS_2_2;
}

@Override
public void setUp(final ISymbol newSymbol) {
newSymbol.setAttributes(ISymbol.HOLDALL);
}
}

public static void initialize() {
if (ToggleFeature.MANIPULATE) {
Initializer.init();
}
}

private ManipulateFunction() {

}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

package org.matheclipse.core.builtin;

import java.io.IOException;
import java.io.StringWriter;

import org.matheclipse.core.basic.Config;
Expand Down Expand Up @@ -324,10 +325,7 @@ public IExpr evaluate(final IAST ast, EvalEngine engine) {
}
}
if (floatJava) {
DoubleFormFactory factory = DoubleFormFactory.get(true, false);
StringBuilder buf = new StringBuilder();
factory.convert(buf, arg1);
return F.$str(buf.toString());
return F.$str(toJavaDouble(arg1));
}
String resultStr = javaForm(arg1, strictJava, usePrefix);
return F.$str(resultStr);
Expand Down Expand Up @@ -356,10 +354,7 @@ private static class JSForm extends AbstractCoreFunctionEvaluator {
public IExpr evaluate(final IAST ast, EvalEngine engine) {
try {
IExpr arg1 = engine.evaluate(ast.arg1());
DoubleFormFactory factory = DoubleFormFactory.get(true, false);
StringBuilder buf = new StringBuilder();
factory.convert(buf, arg1);
return F.$str(buf.toString());
return F.$str(toJavaScript(arg1));
} catch (Exception rex) {
if (Config.SHOW_STACKTRACE) {
rex.printStackTrace();
Expand Down Expand Up @@ -447,6 +442,20 @@ public void setUp(ISymbol newSymbol) {
}
}

public static String toJavaDouble(final IExpr arg1) throws IOException {
DoubleFormFactory factory = DoubleFormFactory.get(true, false);
StringBuilder buf = new StringBuilder();
factory.convert(buf, arg1);
return buf.toString();
}

public static String toJavaScript(final IExpr arg1) throws IOException {
DoubleFormFactory factory = DoubleFormFactory.get(true, false);
StringBuilder buf = new StringBuilder();
factory.convert(buf, arg1);
return buf.toString();
}

public static void initialize() {
Initializer.init();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ public class AST2Expr {
"InterpolatingFunction", "InterpolatingPolynomial", "IntersectingQ", "Intersection", "Inverse",
"InverseFourier", "InverseBetaRegularized", "InverseCDF", "InverseErf", "InverseErfc", "InverseFunction",
"InverseGammaRegularized", "InverseHaversine", "InverseLaplaceTransform", "InverseSeries",
"JaccardDissimilarity", "JacobiMatrix", "JacobiSymbol", "JacobiZeta", "JavaForm", "JSForm", "Join",
"KnownUnitQ", "KolmogorovSmirnovTest", "KOrderlessPartitions", "KPartitions", "KroneckerDelta", "Kurtosis",
"Last", "LCM", "LeafCount", "LaguerreL", "LaplaceTransform", "LeastSquares", "LegendreP", "LegendreQ",
"Length", "Less", "LessEqual", "LetterQ", "Level", "LevelQ", "Limit", "Line", "LinearModelFit",
"JaccardDissimilarity", "JacobiMatrix", "JacobiSymbol", "JacobiZeta", "JavaForm", "JSForm", "JSFormData",
"Join", "KnownUnitQ", "KolmogorovSmirnovTest", "KOrderlessPartitions", "KPartitions", "KroneckerDelta",
"Kurtosis", "Last", "LCM", "LeafCount", "LaguerreL", "LaplaceTransform", "LeastSquares", "LegendreP",
"LegendreQ", "Length", "Less", "LessEqual", "LetterQ", "Level", "LevelQ", "Limit", "Line", "LinearModelFit",
"LinearProgramming", "LinearRecurrence", "LinearSolve", "LiouvilleLambda", "List", "ListConvolve",
"ListCorrelate", "ListLinePlot", "ListPlot", "ListQ", "Literal", "Log", "Log2", "Log10", "LogGamma",
"LogNormalDistribution", "LogicalExpand", "LogisticSigmoid", "LogIntegral", "LowerCaseQ",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,40 @@
*/
public class Console {

protected final static String MATHCELL_PAGE = //
"<html>\n" + //
"<head>\n" + //
"<title>MathCell</title>\n" + //
"<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">\n" + //
"<style></style>\n" + //
"</head>\n" + //
"\n" + //
"<body>\n" + //
"\n" + //
"<script src=\"https://cdn.jsdelivr.net/gh/paulmasson/mathcell@1.3.0/build/mathcell.js\"></script>\n"
+ //
"\n" + //
"<p style=\"text-align: center; line-height: 2\"><span style=\"font-size: 20pt\">MathCell</span></p>\n"
+ //
"\n" + //
"<div class=\"mathcell\" style=\"height: 4in\">\n" + //
"<script>\n" + //
"\n" + //
"var parent = document.scripts[ document.scripts.length - 1 ].parentNode;\n" + //
"\n" + //
"var id = generateId();\n" + //
"parent.id = id;\n" + //
"\n" + //
"`1`\n" + //
"\n" + //
"parent.update( id );\n" + //
"\n" + //
"</script>\n" + //
"</div>\n" + //
"\n" + //
"</body>\n" + //
"</html>";//

/**
* 60 seconds timeout limit as the default value for Symja expression evaluation.
*/
Expand Down Expand Up @@ -517,6 +551,17 @@ private String printResult(IExpr result) throws IOException {
ex.printStackTrace();
}
}
} else if (result.isAST(F.JSFormData, 3) && result.second().toString().equals("mathcell")) {
try {
String manipulateStr = ((IAST) result).arg1().toString();
String html = MATHCELL_PAGE;
html = html.replaceAll("`1`", manipulateStr);
return Console.openHTMLOnDesktop(html);
} catch (Exception ex) {
if (Config.SHOW_STACKTRACE) {
ex.printStackTrace();
}
}
}
}
StringBuilder strBuffer = new StringBuilder();
Expand All @@ -537,6 +582,15 @@ public static String openSVGOnDesktop(IAST show) throws IOException {
return temp.toString();
}

public static String openHTMLOnDesktop(String html) throws IOException {
File temp = File.createTempFile("tempfile", ".html");
BufferedWriter bw = new BufferedWriter(new FileWriter(temp));
bw.write(html);
bw.close();
Desktop.getDesktop().open(temp);
return temp.toString();
}

// private String[] prettyPrinter3Lines(final String inputExpression) {
// IExpr result;
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.concurrent.TimeUnit;

import org.matheclipse.core.basic.Config;
import org.matheclipse.core.basic.ToggleFeature;
import org.matheclipse.core.eval.exception.AbortException;
import org.matheclipse.core.eval.exception.ReturnException;
import org.matheclipse.core.eval.exception.Validate;
Expand Down Expand Up @@ -585,6 +586,17 @@ private String printResult(IExpr result) throws IOException {
ex.printStackTrace();
}
}
} else if (result.isAST(F.JSFormData, 3) && result.second().toString().equals("mathcell")) {
try {
String manipulateStr = ((IAST) result).arg1().toString();
String html = Console.MATHCELL_PAGE;
html = html.replaceAll("`1`", manipulateStr);
return Console.openHTMLOnDesktop(html);
} catch (Exception ex) {
if (Config.SHOW_STACKTRACE) {
ex.printStackTrace();
}
}
}
}

Expand Down
Loading

0 comments on commit 9525f04

Please sign in to comment.