WebOctave is a browser interface for the open source Matlab clone GNU Octave (in combination with GNU plot). In short, it provides
- configurable input forms and input validation,
- running octave as a shell process
- output text capturing and displaying in the browser
- displaying figures as images in the browser
- displaying saved files downloadable in the browser
- Result history
- Script management, optional open or hidden script script source
- Ajax support
Motivation
Scientists often use math software for their calculations, such as Matlab, Mathematica, SciLab and Octave, because these packages are optimized for handling and visualization of huge amounts of data. There are already very good solutions to make these functionality web-accessible to any user (e.g. Wolfram Alpha). Server based solutions have some advantages:
- There is no need for clients with high computational performance. Calculations can be performed using a net-book or iPhone.
- The platform and math package installation is well known and not dependent on the client installation
- Data can be visualized in a elaborated way using HTML/CSS
The reason to start this project was the situation that a lot of tiny calculation algorithms were implemented and used by different students in our group, although there was a “common use case” for the calculations. The most students had no experience with programming languages or web applications, but were very familiar with Matlab. What we needed was a system which accepts scientific source code and provides an easy way to configure the input and output modules of the web interface. The major aspect that lead to utilizing Octave was the fact that Octave is licensed under the GPL and can be run as shell process. Furthermore, the use of GNU Plot allows to save figures without displaying them in the UI. Compromizes had to be made according to the performance (Octave has no JIT compiling) and minor deviations from the known Matlab Syntax.
Demo
I made a HTML snapshot to illustrate the UI, you can find it here.
Installation and requirements
To get the application running, you need:
- A web server compatible to Apache, PHP5
- GNU octave
- GNU plot
- The WebOctave interface
You should have a Unix compatible system (Linux, MacOS), I did not test the interface under Windows. As I think the Linux guys will not have any problems to install these packages, the installation manual mainly refers to MacOS.
If you do not have MacPorts on your machine
The installation is simple. The detailed manuals and the download can be found under macports.org. In short the steps you need to do are:
- First you need a valid compiler, which is for the Mac XCode. Download the software from Apple (the Mac IDE is enough, no need for the iPhone development kit; Apple now wants you to register as a Developer, that’s no problem, XCode is freeware).
- Download the current version of macports from macports.org
- If the new folder “/opt” in your system root directory annoys simply hide it by typing
sudo chflags hidden /optin the console - Update the available ports using
sudo port selfupdate
Now you can install, uninstall and update available ports, commonly used commands are port search [a software I search] (to search for software ports), sudo port upgrade outdated (to update installed ports), sudo port uninstall [name of the package] (to uninstall a port). Note that all packages are compiled on your machine, just as under Linux. This may take some time. Before MacPorts installs the software you want, other packages and libraries that are required by this software will be installed.
Web server installation
MacOS 10 has already a preinstalled Apache with PHP5, which you can use. Optionally (as I did) you can install XAMPP.
GNU octave installation
The best way to install GNU octave using the corresponding MacPort:
sudo port install octave
GNU Plot installation
The best way to install GNU octave using the corresponding MacPort:
sudo port install gnuplot
WebOctave installation
You can download the current version here. Put the folder contents in the root directory of your server htdocs (the document root). Make the subfolders tmp and var writable for the Apache server (for test reasons you can just say “writable for everyone” in the folder info – if you run it on localhost).
Write own scripts
The programming language of Octave is pretty much the same as in Matlab. I suppose that you are familiar with this. Detailed documentation about Octave can be found at the Octave Homepage. For the case that you are not familiar with it, here a very short script to introduce the language:
% This is a comment because of the "%"
%-----------------------------------------------------------
% Print something to the text output:
%-----------------------------------------------------------
% Note: Octave accepts " and ' for strings, Matlab only '
disp('This is a text, an end line will be automatically added');
% Note: Octave knows printf like C/C++, Matlab only sprintf, which returns a string, so:
disp(sprintf('The answer to all questions is %d', 42));
%-----------------------------------------------------------
% Variables and types
%-----------------------------------------------------------
% Set some variables
% Note: if no semicolon is added at the end of line,
% the content of the variable will directly printed as
% text output:
text = 'This is a text' % A string
number = 3.1415 % All normal numbers are doubles / 1x1 matrices
row_vector1 = [1,2,3,4,5] % The columns are split with , or blank, [] means matrix
row_vector2 = [1 2 3 4 5] % Here space separated, also a (1,5) matrix
column_vector = [1;2;3;4;5] % This is a row vector, or also interpreted as (5,1) matrix
A = [1,2,3; 4,5,6; 7,8,9] % a matrix with three columns and three rows
B = [1,0,0; 0,1,0; 0,0,1] % Norm matrix, also known as function eye(3).
C = eye(3) % ... as here
% Note: Matlab and Octave are case sensitive, hence variable A is not variable a.
a = 'I am not A'
% Cell arrays, which is almost the same as arrays/collections in other programming languages
cells{1} = 'A string field';
cells{2} = 42;
cells{3} = pi()
% Structures (like in C) are like a folder structure in the file system,
% but separated with a dot:
myVector.x = 10;
myVector.y = 11;
myVector.z = 12
% Note: There are more data types like fixed point integers etc, refer to the octave manual.
%-----------------------------------------------------------
% Clauses
%-----------------------------------------------------------
% if clause, elseif and else:
% Use && for locical AND
% Use || for logical OR
% Use == for equals
% Use ~= for NOT equal
a = 100;
b = 1;
if a == 1001
disp('a is 101'); % This will not be displayed, as 100 is not 1001
elseif a == 100 && b == 10
disp('a is 100 and b is 10'); % This will not be displayed, as 1 is not 10
elseif a == 100 || b == 10
disp('a is 100 or b is 10'); % This will be displayed, as a is indeed 100
else
disp('a and b are something else');
end
%-----------------------------------------------------------
% Loops
%-----------------------------------------------------------
% Count from 0 to 5 (for loop).
% Note: Principally 0:5 generates the vector [1,2,3,4,5], and
% the for loop loops through each of the elements of the vector.
% Note: Because i and j are preset with the imaginary unit of complex numbers
% people often use k as loop variable, not i like in other programming languages.
% However, you can use i and j as well, it does normally not hurt ...
for k=0:5
disp(sprintf('Now k=%d', k));
end
% Count from 0 to 10 in steps of 2
for k=0:2:10
disp(sprintf('Now k=%d', k));
end
%-----------------------------------------------------------
% Plotting
%-----------------------------------------------------------
% Generate a vector [1,2,3,4, ..., 99, 100];
x = 1:100;
% Calculate the square root for each of the elements of the vector
% This is only that we have some "interesting" values to plot ...
y = sqrt(x);
% Now x and y are vectors with the length 100, this is important for plotting.
% Ok, new figure, please:
f = figure();
% Plot y over x:
plot(x,y);
% We want a grid displayed:
grid on;
% Title and labels:
title('y over x');
xlabel('x');
ylabel('y');
%-----------------------------------------------------------
% Load and save files
%-----------------------------------------------------------
% Example only: load CVS data, there are loads of format for the function load()
%cvs_data = load('-ascii', '/path/to/my/file')
x = 1:100; % x = vector from 1 to 100
y = x.^2; % square of each element of x
% Example only: save has loads of options. Here we save x and y in file.txt ...
%save ('-ascii', 'file.txt', 'x','y');
%-----------------------------------------------------------
% Some traps
%-----------------------------------------------------------
% Matlab/Octave always work with matrices if possible, means:
dot_product = [1,2,3] * [4;5;6] % this is = 32
% returns 32, which is 1*4+2*5+3*6
% note: the matrix product must be (1,3) * (3,1), not (1,3) * (1,3),
% otherwise the interpreter will complain because of the matrix dimensions.
% to make a row vector to a colum vector, use the "'" like:
A = [1,2,3]' % this is [1;2;3], now with ; instead of ,
% For matrices this is the tansposed matrix:
A = [1,2,3; 4,5,6; 7,8,9]' % this is = [1,4,7; 2,5,8, 3,6,9]
% To get the product of each elemens of the vectors or matrix, use .*
element_product = [1,2,3] .* [4,5,6] % this is = [4, 10, 18]
% ths same is for division (./) and power of (.^). For plus and minus
% there is no need to set a dot because the matrix operation is already
% to add or substract each element:
plus = [1,2,3] + [3,2,1] % this is = [4,4,4]
minus = [1,2,3] - [3,2,1] % this is = [-2,0,2]
Interfacing to WebOctave
If you write your Octave script, then all you want is getting input, doing stuff with it and generating output. This is how it works:
- Create a subdirectory in the folder
sources. The folder should be conform to the text you can enter in an URL - Create a file called
main.min your directory. This is your Octave script. An example content is: - Create a file called
config.txtin your directory. This is your configuration in JSON format. - Copy the here given example script/config code in the files
- Now browse to your Octave server root. The HTML page should display the name of the script in the list. If you click at it, the input form will appear. Enter your data and press “Compute”. There you go.
Example script:
% Print the script arguments passed by the WebOctave interface:
parameters
% Calculate the BMI
BMI = parameters.weight / ( parameters.height^2 );
% Output
if name == ''
disp(sprintf('Your BMI is %3.1f', BMI));
else
disp(sprintf('The BMI of %s is %3.1f', name, BMI));
end
% Plot something
x = 1:100;
y = sqrt(x);
figure();
plot(x,y);
grid on;
Example configuration:
{
"title": "My script",
"description" : "This is my script that calculates something for me. In this case ... BMI ...",
"timeout" : 10000,
"source_public" : "0",
"results_unfold" : "1",
"figures_unfold" : "1",
"files_unfold" : "1",
"parameters" :
{
"name" :
{
"caption" : "string",
"description" : "Your name ( optional :-) )",
"type" : "string",
"max" : "100",
"default" : ""
},
"weight":
{
"caption" : "Weight",
"description" : "Enter your weight here",
"type" : "double",
"unit" : "kg",
"min" : "30",
"max" : "200",
"preset" : "70"
},
"height":
{
"caption" : "Height",
"description" : "Enter here how tall you are",
"type" : "double",
"unit" : "m",
"min" : "1.2",
"max" : "2.5",
"preset" : "1.80"
}
}
}
Input
As you can see in the source code of the script, all parameters are passed in the structure parameters. Uploaded files are passed as absolute paths, so that you can use the load() function to work with the contents.
Plotting
All you have to to is to use the build-in plot functions. WebOctave will organize the rest. I recommend to call the function figure() for multiple plots. This prevents that the current plot will be overwritten. The figure() function opens a new virtual plot window, which will be converted to an image later.
Save downloadable files
All saved files will be displayed as downloadable by WebOctave, provided that you do not save them in a directory different from the script execution directory (Note: this is a temporary directory, not the subdirectory in sources. Read on for further details).
Invoking script using the URL
WebOctave does not care if the parameters are specified usign POST, FILES or GET. This allows you to run a script without the form. For the BMI example this would look like: /index.php?$=bmi&height=1.8&weight=70. As you can see the script is specified using $=script name. Optionally you can get the results as AJAX if you add a “$js” or a “$ajax”, so /index.php?$js&$=bmi&height=1.8&weight=70
How WebOctave works
To manage more than one user that could use the web application at the same time, WebOctave generates temporary (session based) working directories in the tmp folder. Here are some details about the files generated and used:
- When the script list is requested (by specifying no script in the URL at all), then all script folders are browsed for the config file, the config is loaded and displayed. Every list entry links to a script in the form “
/index.php?$form=script name“ - When a script form is requested (
$form=...), then the script config of this script is read and the input form returned. - When the compute button is pressed, then the following sequence will be performed:
- The script parameters will be validated
- The temporary working directory is generated if it does not exists it will be created, if it exists it will be cleared.
- The main.m is copied to the temporary directory, a temporary start script is generated, which contains the declaration of the parameters and an additional code to convert the plotted figured to images.
- The current working directory is changed to the temporary directory (using
chdir). The intermediate script contains octave commands that make the source directory to an auto-include directory. - The script is executed using Octave, the STDOUT and STDERR fetched.
- The text output is saved in a file, a script information file is written, Conversions to the PHP UI are made.
- If the script history is enabled, the contents of the file will be copied to a subdirectory, which is named by the timestamp when the script was executed.
- If the history list is requested, the session directory is searched for history folders. The info file contents are read and filtered. After this, the list is displayed
- If the history of a calculation is requested, the history is loaded and presented to the PHP UI like a current script result – so displayed.

