Skip to content

Instantly share code, notes, and snippets.

@nimezhu
Last active August 29, 2015 14:01
Show Gist options
  • Save nimezhu/11549081 to your computer and use it in GitHub Desktop.
Save nimezhu/11549081 to your computer and use it in GitHub Desktop.
Scatter Plot Version 0.3

Scatter Plot Version 0.3 Features:

  • Read URL (include google sheet URL )
  • Read Local File
  • Save SVG without server
  • Input text and plot
  • multiple column ( real sheet )
  • csv / tsv option
  • correlation button
<html lang="en">
<head>
<meta charset="utf-8">
<title>plot data with d3js and html5</title>
<link rel="stylesheet" href="mydiv.css">
<link rel="stylesheet" href="http://nvd3.org/assets/css/nv.d3.css">
<link rel="stylesheet" href="http://www.jeasyui.com/easyui/themes/default/easyui.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://eligrey.com/demos/FileSaver.js/FileSaver.js"></script>
<script src="http://www.jeasyui.com/easyui/jquery.easyui.min.js"></script>
<script src="http://nvd3.org/assets/js/nv.d3.js"></script>
<script src="mathUtils.js"></script>
<link rel="stylesheet" href="http://nvd3.org/assets/css/nv.d3.css">
<style>
body {
font:10px sans-serif;
}
</style>
<script>
$(function() {
$("#chart").resizable();
});
</script>
</head>
<body>
<div class="easyui-layout" fit="true" style="width:100%;height:100%;min-width:960px;margin:0 auto">
<div style="width:210px; background-color: aliceblue" region="west" title="DATA SOURCE" >
<div class="easyui-accordion" >
<div id="url" class="myDiv" title="read url">
<label>google sheet data url: <input type="text" id="data-url" placeholder="https://docs.google.com/spreadsheet/pub?key=0AmT_T9xa0mQ1dFpjdmR1UTdjcmVSb1NvTm51SWZGekE&output=csv" style="width:100%;"/></label>
<button id="url-button" value="read" onclick="readUrl()">read</button>
</div>
<div id="input" class="mydiv" title="read local file">
<h5>File Format</h5>
<select id="file_sep">
<option value="tsv">tsv</option>
<option value="csv">csv</option>
</select>
<input type="file" id="file" name="file"/>
<a href="newdemo.tsv">Example Data</a>
</div>
<div title="input text" id="text-data" class="myDiv">
<textArea id="input-text" style="height:50%;width:100%">
X,Y,group
0.2,0.3,1
0.3,0.2,2
0.5,0.7,1
0.8,0.7,2
0.7,0.8,2
</textArea>
<button id="render-input-text-button" onclick="readInputText()">read</button>
<button id="clear-input-text-button" onclick="clearInputText()">clear</button>
</div>
</div>
</div>
<div id="FIGURE" style=" height:100% ; background-color: white" region="center" class="myDiv" title="FIGURE" align="center">
<div id="chart" class="easyui-resizable" style="padding:20px height:98%;width:98%;border:1px solid">
<svg id="scatter"></svg>
</div>
</div>
<div id="right" region="east" style="background-color: aliceblue; width:210px; text-align:center; height:100%" title="CONTROL PANEL">
<div id="controls" class="myDiv" style="height:30%">
<form id="svg-options">
<label>Filename: <input type="text" class="filename" id="svg-filename" placeholder="demo.scatter"/>.svg</label>
<input type="submit" value="Save"/>
</form>
Fitting the Canvas<br>
<button id="resize-button" value="resize" onclick="resize()">resize figure</button><br>
Clear the Canvas<br>
<button id="scatter-clear-button" value="clear" onclick="clearScatter()">clear figure</button>
<br>
X: <input type="number" id="X" placeholder="1" step="1"><br>
Y: <input type="number" id="Y" placeholder="2" step="1"><br>
<button id="plot" onclick="plot()">PLOT</button>
<div id="cols">
</div>
<div id="console">
</div>
<div id="correlation-output">
</div>
<button id="correlation" value="correlation" onclick="correlation()">correlation</button>
</div>
</div>
<div style="font-size: 90%" align="center" region="south">
<p>source code are under <a href="http://www.gnu.org/licenses/gpl-3.0.txt">GPL LICENSE</a>.<br />
Copyright &copy; <a href="https://github.com/nimezhu">zhuxp</a><br /></p>
<p>Please contact
<a href="mailto:[email protected]">zhuxp</a>
with your questions, comments, and suggestions.</p>
</div>
</div>
<script>
var svg_options_form = document.getElementById("svg-options");
var svg_filename = document.getElementById("svg-filename");
svg_options_form.addEventListener("submit", function(event) {
event.preventDefault();
var BB = Blob;
var svg = document.getElementById("scatter");
var svg_xml = (new XMLSerializer).serializeToString(svg);
saveAs(
new BB(
[svg_xml]
, {type: "text/plain;charset=" + document.characterSet}
)
, (svg_filename.value || svg_filename.placeholder) + ".svg"
);
}, false);
</script>
<script>
var chart = nv.models.scatterChart()
.showDistX(true) //showDist, when true, will display those little distribution lines on the axis.
.showDistY(true)
.transitionDuration(350)
.color(d3.scale.category10().range());
//Configure how the tooltip looks.
chart.tooltipContent(function(key) {
return '<h3>' + key + '</h3>';
});
//Axis settings
chart.xAxis.tickFormat(d3.format('.02f'));
chart.yAxis.tickFormat(d3.format('.02f'));
//We want to show shapes other than circles.
chart.scatter.onlyCircles(false);
nv.utils.windowResize(chart.update);
var sheet=[];
var sheet_header=[];
var colGroup=0;
var colX=0;
var colY=0;
function renderScatter(myData)
{
d3.select('#scatter').text('')
.datum(myData)
.call(chart);
};
function resize()
{
chart.update();
}
function correlation()
{
var dots=d3.select("#scatter .nv-point-clips").selectAll("circle").data();
var x=[];
var y=[];
for(var i in dots)
{
d=dots[i];
x.push(d[4].x);
y.push(d[4].y);
}
$("#correlation-output").html("<h2> correlation value </h2> <br>" + mathUtils.getPearsonsCorrelation(x,y));
}
function parseCSV(text, lineTerminator, cellTerminator) {
var lines = text.split(lineTerminator);
sheet_header=lines[0].split(cellTerminator);
colGroup=sheet_header.length-1;
sheet=[]
//TODO change div list header view
var s="<ol>";
for(i in sheet_header)
{
s+="<li>"+sheet_header[i]+"</li>";
}
$("#cols").html(s);
for(var j=1; j<lines.length; j++){
if(lines[j] != ""){
var d = lines[j].split(cellTerminator);
sheet.push(d)
}
}
}
function plot()
{
X= document.getElementById("X");
Y= document.getElementById("Y");
colX=X.value ||X.placeholder;
colY=Y.value ||Y.placeholder;
colX-=1;
colY-=1;
var s="";
s+="X = "+sheet_header[colX] +"<br>";
s+="Y = "+sheet_header[colY] +"<br>";
$("#console").html(s)
var data=[],
shapes = ['circle', 'cross', 'triangle-up', 'triangle-down', 'diamond', 'square' ],
grp2id = {};
for (i0 in sheet)
{ var d=sheet[i0]
t_gName = String(d[colGroup]); //}else{ t_gName = String(0); } //Group IDs from column 3
if( grp2id[ t_gName ] == undefined ){
grp2id[ t_gName ] = data.length;
data.push({
key: 'Group ' + t_gName,
values: []
});
}
i = grp2id[ t_gName ];
data[i].values.push({
x: parseFloat(d[colX])
, y: parseFloat(d[colY])
//, size: parseFloat(d[colSize]) //Math.random() //Configure the size of each scatter point
, shape: shapes[i % 6]//(Math.random() > 0.95) ? shapes[j % 6] : "circle" //Configure the shape of each scatter point.
});
}
renderScatter(data);
}
function clearScatter()
{
d3.select('#scatter').text('')
}
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
// Only process image files.
var file=files[0]
var reader = new FileReader();
s=$("#file_sep").val();
var sep="\t";
if (s=="csv") {sep=","};
reader.onloadend = (function(evt) {
parseCSV(evt.target.result,"\n",sep);
});
reader.readAsText(file)
}
function httpGet(theUrl)
{
var xmlHttp = null;
xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false );
xmlHttp.send( null );
return xmlHttp.responseText;
}
function readUrl()
{
var url=document.getElementById("data-url").value || document.getElementById("data-url").placeholder;;
parseCSV(httpGet(url),"\n",",");
//render(d3.csv(url));
}
function readInputText()
{
parseCSV(document.getElementById("input-text").value,"\n",",");
}
function clearInputText()
{
document.getElementById("input-text").value=""
}
document.getElementById('file').addEventListener('change', handleFileSelect, false);
</script>
</body>
</html>
var mathUtils = {};
mathUtils.getPearsonsCorrelation = function(x, y)
{
var shortestArrayLength = 0;
if(x.length == y.length)
{
shortestArrayLength = x.length;
}
else if(x.length > y.length)
{
shortestArrayLength = y.length;
console.error('x has more items in it, the last ' + (x.length - shortestArrayLength) + ' item(s) will be ignored');
}
else
{
shortestArrayLength = x.length;
console.error('y has more items in it, the last ' + (y.length - shortestArrayLength) + ' item(s) will be ignored');
}
var xy = [];
var x2 = [];
var y2 = [];
for(var i=0; i<shortestArrayLength; i++)
{
xy.push(x[i] * y[i]);
x2.push(x[i] * x[i]);
y2.push(y[i] * y[i]);
}
var sum_x = 0;
var sum_y = 0;
var sum_xy = 0;
var sum_x2 = 0;
var sum_y2 = 0;
for(var i=0; i<shortestArrayLength; i++)
{
sum_x += x[i];
sum_y += y[i];
sum_xy += xy[i];
sum_x2 += x2[i];
sum_y2 += y2[i];
}
var step1 = (shortestArrayLength * sum_xy) - (sum_x * sum_y);
var step2 = (shortestArrayLength * sum_x2) - (sum_x * sum_x);
var step3 = (shortestArrayLength * sum_y2) - (sum_y * sum_y);
var step4 = Math.sqrt(step2 * step3);
var answer = step1 / step4;
return answer;
}
html,body{margin:5;padding:5;}
body {
font: 10px sans-serif;
}
/*.myDiv { width: 250px; height: 240px; padding: 0.5em; } */
input { size:200;}
svg {margin: 0 auto;}
.myDiv {
border:0px solid black;
margin-bottom: 1cm;
/*
-webkit-border-top-left-radius:6px;
-webkit-border-top-right-radius:6px;
-moz-border-radius-topleft:6px;
-moz-border-radius-topright:6px;
border-top-left-radius:6px;
border-top-right-radius:6px;
/*width:300px; */
font-size:8pt; /* or whatever */
/* background-color: aliceblue */
}
.myDiv h2 {
padding:4px;
color:#fff;
margin:0;
background-color:black;
font-size: 10pt; /* or whatever */
font-family:Arial;
}
.myDiv p {
font-family:Arial;
/*padding:4px; */
}
.middle h2 {
padding:4px;
color:#fff;
margin:0;
background-color:navy;
font-size: 10pt; /* or whatever */
font-family:Arial;
}
textarea {
width: 60%;
height: 60%;
border: 3px solid #cccccc;
padding: 3px;
font-family: Tahoma, sans-serif;
background-image: url(bg.gif);
background-position: bottom right;
background-repeat: no-repeat;
}
li:hover {
background-color: #FFFFCC;
}
td:hover {
background-color: #FFFFCC;
}
table {width:100px}
td {white-space:nowrap;overflow:hidden;width:100px}
x y group(optional)
0.221410954947665 1.75671556305175 3
-0.14384477246951 0.833296493742626 2
-2.72707159877262 -1.37988555552024 1
-1.94525017949989 1.94470404375896 2
0.701912436380002 -0.355518906643944 1
1.00381770465223 4.47254303290322 3
0.921151529428613 0.714451832779669 3
-2.4038219558177 -2.62573344684136 1
2.11259112141152 -0.614074162106395 2
0.321755113363256 3.812232890888 3
-0.179835301704901 2.27576557403705 3
0.191891523517438 1.06603931826444 3
-0.711902680870067 -0.872141909110146 2
-1.09120067351496 0.969013729179679 1
1.27530812305597 0.509536176702982 2
1.09586434991115 2.22008420399256 3
0.432487466224259 0.683603994101275 3
-1.56546243194973 0.359620388484655 1
3.05328814501173 2.02740798026072 3
-0.176754987269587 0.226008176420442 1
0.78025330296606 -1.60142371179814 1
-0.149739424818111 1.24328054173913 3
-0.320814527716024 0.171011614349623 1
1.11316645216034 0.140511395224203 1
0.177795462011684 0.337722415288204 2
1.1351416903283 -0.684260380960271 1
0.850126201327063 0.366409380510145 2
0.177521720634847 0.861365771835762 3
0.762568007767942 -1.72213881552669 2
-1.16956820308358 1.56108680002824 1
1.84717908478115 3.11449558358388 3
-0.636868203431587 2.55751671377565 3
-0.779262263230981 1.07341530210678 2
-0.0509532853625598 0.0724061449560978 2
0.217694845375921 2.70538269605254 3
0.0107796806789758 0.735232162208241 2
1.4426211045936 2.16482961230635 3
-0.7017132543089 -0.398898975377984 1
-0.00317020897363607 2.0779089523853 3
1.07683493800352 1.4601762939861 3
-0.561403954673307 -0.47848526268963 1
1.88404093094635 2.70944134664617 3
1.4058662986064 3.31844461419933 3
-0.702433543666667 -0.568942815873394 1
-0.533599593953849 0.701772174292222 1
-1.43636106525605 -3.11052089580086 2
-0.559999007041227 -1.29982521674276 1
-0.854179628143211 -0.364947058841963 1
0.370217923428329 1.94964986540748 3
1.84555411818571 -2.41631443325474 2
0.377081518633901 -1.12429072943635 1
0.0971672705971388 0.0940552985278462 2
0.829330351783144 3.96669704344894 3
-1.77945007305147 -0.518231864627032 2
1.07337768553739 1.9572099506676 3
-2.15441125773632 2.76352640975576 3
-0.670166047506202 -1.22126259377303 1
0.709652611536635 3.74116395770998 3
-0.185120915039143 2.48844409800729 3
-0.86231044699216 0.690000276662868 2
-2.53239627441143 1.01290628134944 1
1.01891071890602 0.413163746186858 1
-0.873383721038156 0.51772986275557 2
-0.166233133923813 -0.926008148368687 2
1.68561532711093 0.25335976410475 2
-1.9034949570211 0.547718451658653 1
-1.56123501403395 -0.35311074807945 1
0.376716824582123 1.74061280552336 3
0.464742685912667 2.92801771992114 3
0.705653997960755 1.15635861721772 1
-1.29202368123776 3.94227435252527 3
-0.729653824592513 0.873048875748533 1
0.483946136520121 0.287235310221425 2
1.08224126270344 -1.13304298818931 2
1.77834760068475 3.07192814006425 3
1.12560788094441 2.46270804452994 3
1.78170235005337 1.76080269455559 3
1.91786152439588 0.519421510969493 3
0.894506835601214 2.52340379768473 2
0.512086877921218 3.60508335943685 3
-0.311287683089728 0.285889755917236 2
-1.63593727823034 -1.9735176599523 1
0.195724162483265 1.60272482179758 3
-0.382609646153061 -0.302433082718229 2
1.59160649962187 1.16376621890112 3
-2.28881453585252 0.471896623297596 1
1.36010655266098 0.906279329785026 3
-2.4986599436014 -1.2869556299839 1
-0.173718848553705 -1.32879301486481 1
0.905517122673339 -1.47400215371805 2
0.0553298270484327 -2.47397797491279 2
-0.728640346779411 0.457416152543923 2
1.04244971526977 1.05563983288002 3
0.3097547404931 0.869549353673898 3
-0.234112381112234 0.697173652498862 2
0.7384813398699 2.42538223238026 3
-0.51755282004229 0.0880895231802099 2
0.457759793512253 1.46326298579549 3
1.02760006360689 -0.960035813230912 2
-2.73292415737238 -0.683091148341922 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment