15
$\begingroup$

I purchased Mathematica a few days ago, and although I am a mathematician, my programming and Mathematica knowledge is close to zero. So please help and point me to some resources for the following use.

I intend on making some educational materials for my students in the form of web apps. I started learning some basic HTML and JavaScript, but then I found the amazing CDF and HTML integration that Mathematica offers. So I thought it would be more useful, powerful and easy to program some math-based algorithms in Mathematica and use them in HTML.

So, long story short: how can I make an "application" in Mathematica where the user enters a value and the program outputs the result of some algorithms applied to that value?

Concrete example: The Collatz algorithm: The user enters a number $x$, then the program halves it, if it is even or computes $3x+1$ if it is even, all of this while $x \neq 1$. I want an InputField for the user to enter $x$ and after pressing Enter, the program to print the steps that the algorithm makes down to $1$.

Yes, I know, the Collatz algorithm is easy to implement in any (other) language, I just offered it as an example which would be easy for me to understand.

Actually, I can ask something else: would you say Mathematica is best suited for computations and I'd rather use something else for programming math based utilities for my students?

$\endgroup$
  • $\begingroup$ Support for cdf plugin will be soon/is already gone. If you want web applications please take a look at CloudDeploy and related functionalities. $\endgroup$ – Kuba Jun 14 '15 at 9:17
  • $\begingroup$ Thanks, Kuba. Seems more natural and easy with CloudDeploy. Now I only have to find out how to make the content to be deployed, some kind of "app" that I asked about. $\endgroup$ – Adrian Manea Jun 14 '15 at 9:20
  • $\begingroup$ @kuba do you have anything official from WRI to back that statement up? $\endgroup$ – Gordon Coale Jun 14 '15 at 21:15
  • 1
    $\begingroup$ @GordonCoale I added a source to my answer (the first sentence.) $\endgroup$ – C. E. Jun 15 '15 at 5:01
  • $\begingroup$ @Pickett - that useful but only really covers those using Chrome. Mozilla have made no clear statement on NPAPI afaik, and obviously IE will still work regardless (MS Edge not withstanding). Its also worth noting that CloudMMA's UI functionality left a lot to be desired in terms of quality and speed when I used it 3 months back - it wasn't ready for prime time for UI heavy cdf's. So whilst I expect the general trend to be away from CDF - I would be surprised to see it happen for another major version or 2. $\endgroup$ – Gordon Coale Jun 15 '15 at 5:36
14
$\begingroup$

28/2/2018: Wolfram Cloud now supports (quite possibly since several years ago) cross origin requests, so that part of this answer can be ignored. Ajax may be used, just remember to set the API permissions to "public".

Support for the mechanism that makes the CDF browser plugin possible is being phased out, and the CDF player already does not work on the newest versions of Google Chrome. In light of this there is no better time than now to start mixing the Wolfram Language with HTML and Javascript.

The concerns of using Wolfram Language as a backend/server language is no different than when using some other server language. You always have to ask yourself whether you want to implement a certain functionality in the frontend or in the backend. Since Javascript is not very good at math there will probably be lots of time that even a Javascript expert would choose to use the Wolfram Language.

Getting started

In order to get started you need a good HTML/CSS framework and a good Javascript framework that contain all the things you need so you don't have to write them.

  • I recommend to start using Bootstrap for building your designs. The documentation is very nice and it has most of the things you'll need.
  • For Javascript I recommend jQuery which the most popular Javascript framework by far. The documentation is good, there are lots of tutorials online and there are many "plugins" available that provide additional functionality.

I will use this combination in my examples below.

How to deploy Wolfram Language

Wolfram Language provides CloudDeploy and APIFunction which combine to create a RESTful API, and this is how we will call on our Wolfram Language code.

Websites such as Mathematica.Stackexchange or New York Times rely heavily on backend scripts/RESTful APIs. They run Javascript in the frontend that call these scripts when it is appropriate to update the content that the user sees. The technique they use is called "AJAX". Unfortunately it is one thing to send an AJAX request to New York Times' server from newyorktimes.com and it's another thing to send an AJAX request to New York Times' server from your own website. Such "cross domain requests" have been prevented by browsers since the inception of AJAX, and browsers only recently started allowing them and only if the server respond with a specific "header". WRI's server does not respond with this header, which means that we cannot communicate with it using AJAX.

We will see later that this does not matter for images, because we don't need AJAX for those. But it matters when the result is data. Luckily there is a workaround known as "jsonp". It's not the normal type of AJAX, but it works like it. That's what we will be using instead. jQuery will take care of most of the work behind the scenes, but we need to modify our APIFunction as well. This auxiliary function will take care of that:

jsonpAPIFunction[args_, f_] := APIFunction[
  Append[args, "callback" -> "String"],
  StringJoin[#callback, "(", ToString@f[#], ")"] &,
  "String"
  ]

BMI counter

In order to create a BMI counter we need to create a form that lets the user input his height and his weight. Then we need to apply the BMI formula to these numbers and show the result. Since this is an exercise in how to do computations with Wolfram Language, not Javascript, the formula (weight/height^2) will be computed in the cloud. In fact this is the APIFunction:

CloudDeploy@jsonpAPIFunction[{
   "weight" -> "Number",
   "height" -> "Number"
   },
  N[#weight/#height^2] &]

The Javascript and HTML is appended to the end of the post, you will see that only very little code is needed. There are instructions there as well that explain how you can try this yourself. This animation shows how smooth it works, even though it asks for the BMI from a server instead of computing it locally:

BMI counter

Domain coloring

This example, which you can also try with the code at the end of the post, is meant to show how to handle APIs that return images. In order to build the example I took Simon Woods' domain coloring function from this question. You have to define his domainPlot function as well, after that you can use this APIFunction:

deployableDomainPlot[assoc_] := domainPlot@ToExpression@assoc["f"]
CloudDeploy@APIFunction[{
   "f" -> "String"
   },
  deployableDomainPlot,
  "PNG"
  ]

The result will look like this:

Domain coloring

HTML/CSS/Javascript Manipulate clone

This example is not included in the code at the end of the post, but I thought I might show the result anyway. It works the same way as the domain coloring example above but the interface is a bit more complicated. I made it with jQuery, jQuery UI and a jQuery tooltip plugin.

Example Manipulate

HTML/CSS/Javascript code

Here is the code you need to test the first two examples above. Note that you need to run the CloudDeploy code given for the examples above to generate your own API URLs. Then you have to put the URLs into the Javascript code, which is in the beginning of the document, in the <head> part of the document.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Wolfram Language API examples</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css">

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>

        <!--- Javascript to interface with the API goes here -->
        <script type="text/javascript">
        BMI_calculator_URL = "<YOUR API URL HERE>";
        domain_coloring_URL = "<YOUR API URL HERE>";

        $(document).ready(function() {
	  		// BMI calculator
		  	$("#height, #weight").change(function() {
			  	if($("#weight").val() > 0 && $("#height").val() > 0) {
			  	$.getJSON(
			  		BMI_calculator_URL+"?weight="+$("#weight").val()+"&height="+$("#height").val()+"&callback=?", 
			  		function(result){
				  		$("#result").text(result);
                    });
                }

                /*
                Note:
                Can't use Ajax like in this code here below because the header
                "Access-Control-Allow-Origin: *" is missing in the API response.
                $("#result").load(
			  		BMI_calculator_URL+"?weight="+$("#weight").val()+"&height="+$("#height").val()
                );
                */
            });

            // Domain coloring
            $(".btn").click(function(){
				$("#function").val($(this).val());
				$("#result2").html(
					"<img src=\""+domain_coloring_URL+"?f="+$(this).val()+"\" />"
                );
            });

            $("#function").change(function(){
				$("#result2").html(
					"<img src=\""+domain_coloring_URL+"?f="+$(this).val()+"\" />"
                );
            });
        });
        </script>
    </head>

    <body>

        <div class="container"><!--- Your code interface goes in this container --->

              <h1>Wolfram Language API examples</h1>

              <h2>BMI calculator</h2>
              <form class="form-horizontal">
                <div class="form-group">
                    <label for="height" class="col-md-2 control-label">Height</label>
                    <div class="col-md-10">
                        <input type="number" class="form-control" id="height" placeholder="Height">
                    </div>
                </div>
                <div class="form-group">
                    <label for="weight" class="col-md-2 control-label">Weight</label>
                    <div class="col-md-10">
                        <input type="number" class="form-control" id="weight" placeholder="Weight">
                    </div>
                </div>
              </form>
              <div class="panel panel-success">
                <div class="panel-heading">
                    Result
                </div>
                <div class="panel-body" id="result">
                    Undefined
                </div>
              </div>

          <h2>Domain coloring</h2>
          <div class="form-group btn-group">
              <button type="button" class="btn btn-default" value="Identity">Identity</button>
              <button type="button" class="btn btn-default" value="Sqrt">Sqrt</button>
              <button type="button" class="btn btn-default" value="Log">Log</button>
          </div>
          <div class="form-group">
              <input type="text" class="form-control" id="function" placeholder="Function">
          </div>

              <div class="panel panel-success">
                <div class="panel-heading">
                    Result
                </div>
                <div class="panel-body" id="result2">
                    Undefined
                </div>
              </div>

    </div><!--- /container --->

  </body>
</html>
$\endgroup$
  • $\begingroup$ Thank you very much, @Pickett! As I said, I'm at the very beginning of my learning to code, so your explanations and references are more than useful. And I could follow your entire answer, so they are clear enough. $\endgroup$ – Adrian Manea Jun 15 '15 at 5:13
9
$\begingroup$

Here is a basic example of how Mathematica code would be deployed.

Get["http://exampledata.wolfram.com/Collatz.m"];
?? Collatz

enter image description here

Collatz[5]

{5, 16, 8, 4, 2, 1}

You can look into APIFunction that you access directly if you want to build an interface with HTML/Javascript, or if you want a simple interface running on Wolfram's cloud you can use FormFunction. The return value of the function can be any expression, but more complex expressions may not work well in their cloud environment.

form = FormFunction[{"x" -> "Integer"}, Collatz[#x] &]
form[]

enter image description here

If I enter 5 and submit, the form disappears and is replaced with {5, 16, 8, 4, 2, 1}. To deploy this function to Wolfram's cloud, use

CloudDeploy[form]

which will return a CloudObject containing a link. You will need to use the Permissions option to control access. Following the link will take you to a page displaying a form, which will disappear and be replaced with the resolved expression after it has been submitted.

enter image description here

$\endgroup$
  • $\begingroup$ Thank you very much! I understand the direction in which I should research now. APIFunction, then EmbedCode seem to be especially helpful for my purpose, in the idea of inclusion in HTML/JS. $\endgroup$ – Adrian Manea Jun 14 '15 at 14:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.