Creating a Web App with MATLAB and the MEAN Stack
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 while
loop. 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:
- Send the data to the browser using the
emit()
function of socket.io - 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.