JavaScript
Article

Creating a Web App with MATLAB and the MEAN Stack

By Ritesh Kumar

MATLAB is a high-level language used for technical computing. It integrates computation, visualization, and programming in an easy-to-use environment where problems and solutions are expressed in familiar mathematical notation. There are a lot of projects around the world that are written in MATLAB and developed by millions of scientists and engineers. The data of the various experiments and operations that people obtain from MATLAB can be used to power web applications but there are a couple of hurdles:

  • MATLAB understands matrix format data while web applications prefer data in JSON or XML.
  • Often the data are created and consumed inside a MATLAB program which limits the freedom that developers like to have regarding saving the data, using them, and so on

It’d be a lot easier to create applications if MATLAB provided data in JSON and a web application could use those JSON data from MATLAB to create something wonderful.

In this article we’ll develop a small demo to demonstrate how to have MATLAB and the MEAN stack working together.

About the web Application

The web application will involve real-time transfer of data from MATLAB to the browser. For simplicity we’ll transfer the current time from MATLAB and display it on the browser. We’ll use JSONlab, a toolbox to encode/decode JSON files in MATLAB. The web application will be created using the MEAN stack. If you are not familiar with MEAN stack, I suggest you to read the article An Introduction to the MEAN Stack before moving forward.

Introduction to JSONlab

JSONlab is a free and open-source implementation of a JSON encoder/decoder for the MATLAB language. It can be used to convert a MATLAB data structure (array, struct, cell, struct array and cell array) into JSON formatted string, or decode a JSON file into MATLAB data.

It gives us access to four functions: loadjson(), savejson(), loadubjson() and saveubjson() . The last two functions are used for processing the UBJSON format. loadjson() is used to convert a JSON string into the related MATLAB object. In our project, we’ll only use the savejson() function that converts a MATLAB object (cell, struct, or array) into a JSON string. It can be used in the following ways:

json = savejson(rootname, obj, filename)
json = savejson(rootname, obj, opt)
json = savejson(rootname, obj, 'param1', value1, 'param2', value2, ...)

Since we have to write a file, we’ll use the first signature. It returns a JSON string as well as writing the string on the file.

JSONlab installation

To get started, download JSONlab, unzip the archive, and add the folder’s path to MATLAB’s path list by using the following command:

addpath('/path/to/jsonlab');

If you want to add this path permanently, you need to type pathtool, browse to the JSONlab root folder and add it to the list. Once done, you have to click on “Save”. Then, run rehash in MATLAB, and type which loadjson. If you see an output, it means JSONlab is installed correctly.

MATLAB Code

We need the current time, so we’ll use the clock command. It returns a six-element date vector containing the current date and time in [year month day hour minute seconds] format. To get the time repeatedly, we have put the clock command in an infinite whileloop. So we get the real-time data until the script execution is terminated using Ctrl+C on MATLAB’s command window.

The following code implements this idea:

format shortg;
y=0;
while y = 0
    % c = [year month day hour minute seconds]
    c=clock;
    % Rounding every value to an integer
    c=fix(c);
    x.clock=c;
    % accessing the 4th column of c, i.e hours
    x.hours=c(:,4);
    % accessing the 5th column of c ,i.e minutes
    x.minutes=c(:,5);
    % accessing the 6th column of c, i.e seconds
    x.seconds=c(:,6);
    % converting x into JSON and writing as matlabData.json
    savejson('',x,'data/matlabData.json');
end

In our project, we are concerned about hour, minute, and seconds. The fix(c) function, used in the above code, rounds all the elements of the matrix to the nearest integer. To get the hour data, we need the value of the 4th column of the matrix, so we use the command c(:,4). Using the same approach, we retrieve minutes and seconds.

We’ll send both clock and some of its individual variables separately to the web application to show the conversion of different data-types from a MATLAB object to JSON. While the clock data will be converted into an Array, the value of hours, minutes, and seconds will be converted into a Number as we will see later.

In our project, we’ll use the savejson() function to convert and write the variable x using the JSON format in the file matlabData.json. The rootname parameter will be an empty string for simplicity.

With the previous code, all the MATLAB code we need is done. Now as soon as we run the script, we can observe that the JSON file is created inside the data folder and the data in the file automatically keeps updating itself. An example of the content of the JSON file is shown below:

{
   "hours": 19,
   "minutes": 28,
   "seconds": 28,
   "clock": [2015,5,27,19,28,28]
}

We’ll watch this file and read the latest data using Node.js. Let’s now start building the web application.

The web Application

Now that our data from MATLAB have been converted into JSON and it’s stored in a file, we can independently read this file and obtain the data by watching it for changes. This operation is totally independent from MATLAB. In the remainder of the article, I’ll assume that you have some knowledge of socket.io along with the MEAN stack, even though we will be using only their basic concepts.

Let’s start writing the web application.

Creating Package.json file

To start with our application, let’s define the dependencies of our project. To do so, we’ll create a package.json file that looks like the following:

{
  "name": "matlab-mean-demo",
  "version": "1.0.0",
  "description": "A demo web-app using Matlab and MEAN stack",
  "main": "server.js",
  "dependencies": {
    "express": "latest",
    "mongoose": "latest",
    "socket.io": "^1.2.0"
  }

Run npm install in the root folder of the project after creating the file so that all the dependencies will be installed. If you aren’t familiar with npm, I suggest you to read A Beginner’s Guide to npm — the Node Package Manager.

Server side code

This part of the code involves the use of Node.js , Express, and MongoDB. The actions performed by the server are:

  • Serving an index.html file
  • Watching and reading the data from the JSON file
  • Saving the data in a database using MongoDB
  • Sending the data to the browser using socket.io

We’ll create a file called server.js in the root folder where we’ll write the code needed for all the features described.

We serve the static files using Express:

// Defining the root directory for static files
app.use(express.static(__dirname + '/app'));

// Serving the static HTML
app.get("/", function(req, res) {
    res.sendfile("/index.html");
});

Whenever a request is sent to / , the index.html file stored inside the app directory will be served.

To watch the file for any change, we use fs.watch() and for reading the file on each change we use fs.readFile(). As soon as a change is detected, the file is read and we retrieve the data. The whole process is done with the following code:

fs.watch('folderName',function(event,filename){
	fs.readFile('folderName' + filename, function(err,data){
  		console.log(data);
	});
});

When a connection with a client is established and we start getting the data, we perform two operations:

  1. Send the data to the browser using the emit() function of socket.io
  2. Save the data in MongoDB using the mongoose middleware

To perform the second operation, we create a schema of our data and then a model based on that schema. This is done with the code shown below:

// Creation of the schema
var dataSchema = mongoose.Schema({
   clock: Array,
   hours: Number,
   minutes: Number,
   seconds: Number
});

// Creating a model based on schema
var appData = mongoose.model('appData', dataSchema);

In the last statement of the previous snippet, we create the model based on the schema defined. The first argument passed to the function is the singular name of the collection our model is for. Mongoose automatically assigns the plural name to the collection. So here, appData is a model of an appDatas collection.

When we get new data, we create a new instance of that schema with the latest data and save it in the database using the save() method. This instance is known as a document. In the below code savingData is a document.

The final code of this part is shown below:

var express = require('express');
var mongoose = require('mongoose');
var fs = require('fs');
var app = express();

//Make a connection to MongoDB
mongoose.connect('MongoDB://localhost/matlabMeanDemo');
var io = require('socket.io')(app.listen(3000));

//Defining the root directory for static files
app.use(express.static(__dirname + '/app'));

//serving the static HTML
app.get("/", function (req, res) {
    res.sendfile("/index.html");
});

var appData;
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback() {
    var dataSchema;

    dataSchema = mongoose.Schema({
        clock: Array,
        hours: Number,
        minutes: Number,
        seconds: Number
    });
    appData = mongoose.model('appData', dataSchema);

    //Sending and receiving data
    io.on('connection', function (socket) {
        fs.watch('data', function (event, filename) {
            fs.readFile('data/' + filename, function (err, data) {
                if (!err) {
                    try {
                        var x = JSON.parse(data);
                        socket.emit('updated', x);

                        // Create a new instance of appData model
                        // i.e also known as a document
                        var savingData = new appData({
                            clock: x.clock,
                            hours: x.hours,
                            minutes: x.minutes,
                            seconds: x.seconds
                        });
                        //save data
                        savingData.save();
                    } catch (e) {
                        console.log('malformed data');
                    }
                }
            })
        });
    });
});

We are using try and catch to prevent the application from crashing. If we don’t use it and JSON.parse throws an error of unexpected user input because sometimes the data is not completely read due to the fast change rate, the application may crash. Something we want to avoid!

As an additional note, be sure that the MongoDB server is running or the application will crash.

Client side code

In this section we’ll create a simple static HTML page. When new data are received via socket.io, we update the data shown on the page. These data can also be used to create real-time graphs and charts.

Here is the simple code of the index.html file:

<body ng-app="demo" ng-controller="demoController" ng-cloak class="ng-cloak">
    <div>{{data.hours}} : {{data.minutes}} : {{data.seconds}}</div>
</body>

<script src="/path/to/angular.js"></script>
<script src='/path/to/socket.io.js'></script>
<script>
var socket = io.connect();

angular.module('demo', []).controller('demoController', ['$scope', function($scope) {
    socket.on('updated', function(data) {
        $scope.$apply(function(){
            $scope.data = data;
        });
    });
}]);
</script>

The ngCloak directive is used to prevent AngularJS’s template from being briefly displayed by the browser in its raw (uncompiled) form while our application is loading.

Finally, we need to add the following CSS code to make it work in case AngularJS is loaded after the body of the HTML.

[ng\:cloak],
[ng-cloak],
[data-ng-cloak],
[x-ng-cloak],
.ng-cloak,
.x-ng-cloak {
    display: none !important;
}

The controller is written in long function form so we don’t need to inject the arguments.

Whenever new data are received, we need to use $scope.apply() to update the data on the view. $scope.apply() takes a function or an AngularJS expression string , and executes it. Then, it automatically calls $scope.$digest() to update any watchers. An alternative would be $timeout (provided by AngularJS) that is like setTimeout but automatically wraps our code in $apply by default.

Running the application

We need to make sure that MATLAB code and MongoDB server are running before starting the Node.js server. To have the MongoDB server ran, you need to execute the command mongod on the terminal. To run the Node.js server, you have to execute the command node server.js in the root of the project folder.

The static page showing the current time will be served at 127.0.0.1:3000 .

Conclusions

In this article, we created a web application using the MEAN stack which takes data in JSON format from a MATLAB program. The data are converted with the help of JSONlab. The data are then sent to the browser using socket.io, thus changes on the browser are reflected in real-time. The complete source code of this demo is available on GitHub.

I hope that you have enjoyed the article and I look forward to reading your comments.

No Reader comments

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in JavaScript, once a week, for free.