Build data analysis and visualization tools with

BUILD DATA ANALYSIS
& VISUALIZATION TOOLS
WITH PHP
Robert Aboukhalil
@RobAboukhalil
Outline
The Basics
Backend data analysis
Show progress
Visualize results
Slides: robertaboukhalil.com/talks
Outline
The Basics
Backend data analysis
Show progress
Visualize results
Slides: robertaboukhalil.com/talks
Why web apps for data analysis?
Why web apps for data analysis?
Installing software packages can be a nightmare
If you want them to use it, it has to be usable
Access data/results from anywhere
Sample web app
ginkgo
Outline
The Basics
Backend data analysis
Show progress
Visualize results
Slides: robertaboukhalil.com/talks
Backend Data Analysis
mywebsite.com?n1=5&n2=4
9
index.php?n1=5&n2=4
<?php $n1 = $_GET['n1']; $n2 = $_GET['n2']; echo $n1 + $n2; echo shell_exec("./add.sh $n1 $n2"); ?> add.sh
#!/bin/bash (( out = $1 + $2 )); echo $out Run command line programs with PHP
// Return output as string
$allOutput = shell_exec("./analysis");
// Print output to screen + return as string
$allOutput = system("./analysis", $returnCode);
// Save output in array + return last line as string
$lastLine = exec("./analysis", $arrOutput, $returnCode);
// Print raw (binary) output to browser
header("Content-Type: image/png");
echo file_get_contents("image.png");
// Return binary output of command to browser
header("Content-Type: image/png");
passthru("./resize image.png", $returnCode);
Run programs in the background
// Run command in background
shell_exec("./analysis &");
// Run command in background (for CentOS)
$handle = popen("./analysis &", 'r');
pclose($handle);
index.php?n1=5&n2=4
<?php $n1 = $_GET['n1']; $n2 = $_GET['n2']; echo shell_exec("./add.sh $n1 $n2"); ?> add.sh
#!/bin/bash (( out = $1 + $2 )); echo $out Security
// Escape arguments
$cmd = "./analysis " . escapeshellarg($arg);
shell_exec($cmd);
// Escape command
shell_exec(escapeshellcmd($cmd));
Outline
The Basics
Backend data analysis
Show progress
Visualize results
Slides: robertaboukhalil.com/talks
Show Analysis Progress
mywebsite.com/progress.html
43%
launch.php
<?php shell_exec("./app.sh &"); ?> app.sh
#!/bin/bash for(( i = 1; i <= 100; i++)); do echo $i > progress.txt sleep 2 done status.html
<!-­‐-­‐ jQuery + Bootstrap.js -­‐-­‐> <link rel="stylesheet" href="bootstrap.min.css"> <script src="jquery.min.js"></script> <script src="bootstrap.min.js"></script> <!-­‐-­‐ Progress bar -­‐-­‐> <div class="progress"> <div id="analysis-­‐progress" class="progress-­‐bar"></div> </div> <script> // Set progress function getStatus() { $.get("progress.txt", function(progress) { $("#analysis-­‐progress").width(progress + "%"); }); } // Do this every 1s $(document).ready(function(){ setInterval("getStatus()", 1000); }); </script> launch.php
<?php shell_exec("./app.sh &"); ?> app.sh
#!/bin/bash for(( i = 1; i <= 100; i++)); do echo $i > progress.txt sleep 2 done status.html
<!-­‐-­‐ jQuery + Bootstrap.js -­‐-­‐> <link rel="stylesheet" href="bootstrap.min.css"> <script src="jquery.min.js"></script> <script src="bootstrap.min.js"></script> <!-­‐-­‐ Progress bar -­‐-­‐> <div class="progress"> <div id="analysis-­‐progress" class="progress-­‐bar"></div> </div> <script> // Set progress function getStatus() { $.get("progress.txt", function(progress) { $("#analysis-­‐progress").width(parseInt(progress) + "%"); }); } // Do this every 1s $(document).ready(function(){ setInterval("getStatus()", 1000); }); </script> Alternative to polling
WebSockets
Outline
The Basics
Backend data analysis
Show progress
Visualize results
Slides: robertaboukhalil.com/talks
Visualize results
mywebsite.com/results.html
launch.php
<form action="" method="POST"> x,y coordinates:<br> <textarea name="data" rows="5"></textarea><br><br> <input type="submit" name="cluster" value="Cluster"> </form> <?php if(isset($_POST['cluster'])) { $cmd = "Rscript cluster.R " . escapeshellarg($_POST['data']) . " &"; pclose(popen(escapeshellcmd($cmd), 'r')); } ?> cluster.R
# Clustering library library(mclust) # Parse input args = commandArgs(trailingOnly = TRUE) data = read.csv(con <-­‐ textConnection(args[[1]]), header=FALSE) data = as.matrix(data) close(con) # Clustering allBIC = c() allClassification = list() p = 0 for(G in 2:20) { clust = Mclust(as.matrix(data), G=G) allBIC[G] = clust$bic allClassification[[G]] = clust$classification p = p + 5 writeLines(as.character(p), 'progress.txt') } # Save result to file out = c() for(i in 1:which.max(allBIC)) { tmp = data tmp[setdiff(1:dim(data)[1], which(classif == i)), 2] = "NaN" out = cbind(out, tmp[,2]) } write.csv(out, file="result.txt", quote=FALSE) status.html
<!-­‐-­‐ jQuery + Bootstrap.js -­‐-­‐> <link rel="stylesheet" href="bootstrap.min.css"> <script src="jquery.min.js"></script> <script src="bootstrap.min.js"></script> <!-­‐-­‐ Progress bar -­‐-­‐> <div class="progress"> <div id="analysis-­‐progress" class="progress-­‐bar"></div> </div> <script> // Set progress function getStatus() { $.get("progress.txt", function(progress) { $("#analysis-­‐progress").width(parseInt(progress) + "%"); }); } // Do this every 1s $(document).ready(function(){ setInterval("getStatus()", 1000); }); </script> visualize.html
<!-­‐-­‐ JS Charting library -­‐-­‐> <script src="dygraph-­‐combined.js"></script> <!-­‐-­‐ Where graph is plotted -­‐-­‐> <div id="graphdiv"></div> <!-­‐-­‐ Plot graph -­‐-­‐> <script type="text/javascript"> g = new Dygraph( $("#graphdiv"), // Div containing graph "result.txt", // Path to data file { // Other options strokeWidth: 0, pointSize: 5, drawPoints: true, } ); </script> Summary
// Run command in background
shell_exec("./analysis &");
pclose(popen("./analysis &", 'r’));
// Escape arguments
escapeshellarg($arg);
escapeshellcmd($cmd);
<!-- Bootstrap -->
<div class="progress">
<div id="analysis-progress" class="progress-bar" width="75%"></div>
</div>
<!-- JS Charting library -->
dygraphs.com
# R for data analysis
r-project.org Slides: robertaboukhalil.com/talks