Interactive Data Visualization for the Web – What can Interactive Vis do for me? – HTML



Interactive Data Visualization for the Web – What can Interactive Vis do for me? – HTML

0 0


gaggle_2012

A talk given at the Gaggle/Systems Biology workshop in 2012

On Github rbkreisberg / gaggle_2012

Interactive Data Visualization for the Web

Dick Kreisberg

Systems Bioinformatics Workshop

Sept 11, 2012

vis.systemsbiology.net/sbw_2012/

Outline

  • Introduction
  • HTML5
  • D3.js + CSS3 + SVG

In the introduction, we will briefly motivate the the usage of interactive vis and its implementation on the browser. We'll take a look at the components of HTML5 that make interactive vis possible. In the tutorial, we'll create an interactive vis using the key concepts of SVG and the Javascript library D3.js

What can Interactive Vis do for me?

  • Convey meaning
  • Manage the 3 hurdles of data...Scope, Scale, Complexity
  • Provide supporting data and context

Convey - Scope - Explore heterogenous data that requires multiple plot types. Scale - Global views with focal windows (Google Maps). Zoom on demand. Complexity - Networks with greater than 50,000 nodes, 20 million edges. Traversal paths longer than 20 Supporting Data - statistical background Context - Annotations on genes, proteins, microRNA, Clinical information
024612345678910111213141516171819202122XY
Add Edges

HTML

<!doctype html>
<html>
 <head>
  <title>Hello World</title>
  <link rel="stylesheet" type="text/css" href="css/b.css"/>
  <script type="text/javascript"src='js/a.js'></script>
 </head>
 <body>
  <div id="svg_container">    
   <svg width="450" height="300"
           xmlns="http://www.w3.org/2000/svg"></svg>
   <button>Hi!</button>
  </div>
 </body>
</html>

CSS3 Selectors

<div id="BRCA">
 <ul class="mutations">
  <li>1</li>
  <li>2</li>
 </ul>
<div>
with jQuery:
$('#BRCA') == <div>....</div>
$('.mutations') == <ul>...</ul>
$('.mutations li') == [<li>1</li>,<li>2</li>]
$('.mutations li:first') == <li>1</li>
or d3:
d3.select('#BRCA') == <div>....</div>
d3.select('.mutations') == <ul>...</ul>
d3.selectAll('.mutations li') == [<li>1</li>,<li>2</li>]
d3.select('.mutations li:first') == <li>1</li>

SVG

<svg id="updating-plot" xmlns="http://www.w3.org/2000/svg"
	width="450" height="200">
 <g class="canvas" transform="translate(25,15)">
   <g class="axes"></g>
   <g class="labels"></g>
   <g class="data">
     <circle cx="135" cy="150" fill="#F23" stroke="none" r="6"/> </g>
 <rect fill="none" stroke="#0000FF" stroke-width="2"
  x="60" y="30" width="100" height="60" transform="rotate(45)"/>
  <path fill="none" stroke="#444444" stroke-width="2"
    d="M40 70 L240 100"/>
  <text x="100" y="30" class="label">Hello World</text>
  </g>
</svg>
Hello World

ECMAScript5

And the HTML Document API!

Javascript is growing (ES6 is coming) into a full featured tool. It enables a growing number of interactions between the user, the browser, and the data.

D3.js

d3js.org

Javascript library that joins data to the document (DOM). Created by the author of Protovis, Mike Bostock. Several other regular contributors on the project.

D3 is not rigidly coupled to SVG. SVG lends itself to functional operations. D3 does provide high level generators for creating SVG objects quickly.

Let's Make Something

jsfiddle.net/rbkreisberg/cdpcX/ Scatterplot with: axes, ticks, labels, cardinal interpolation, event-driven behavior, periodic behavior.

Follow Along!

jsfiddle.net/rbkreisberg/cdpcX/1/
var w = 450,
    h = 300;

//attach an svg object to the DOM.  Size it appropriately    
var svg = d3.select('#plot')
            .append('svg:svg')
              .attr('width', w)
              .attr('height', h);
    
//draw an outer border.
    svg.append('rect')
        .attr('x', '0')
        .attr('y', '0')
        .attr('width', w)
        .attr('height', h)
        .attr('stroke-width', '2')
        .attr('stroke', 'black')
        .attr('fill', 'none');        

         //attach a title to the graph using a svg:text object    
    svg.append('text')
        .attr('class', 'title')
        .attr('x', w/2 - 40) //position in the center (sorta)
        .attr('y', "14")
        .text('Scatter Plot!');
}

Data -> Rendered Circles

Change of Coordinates

jsfiddle.net/rbkreisberg/cdpcX/2/
F(data) = Viewport.X G(data) = Viewport.Y
//x_scale maps the array index to the viewport
var x_scale = d3.scale.linear()
                  .domain([0,data_array.length-1])
                  .range([0,viewport_width]);

//invert the y_scale such that higher values is closer to the top
var y_scale = d3.scale.linear()
                  .domain([0,1000])
                  .range([viewport_height,0]);
Create Axes
//d3 function to create an axis from x_scale with the domain flipped
var x_axis = d3.svg.axis()
                .scale(x_scale.copy().domain([20,0]))//use the x_scale
                .tickSize(-screen_height)
                .ticks(5)
                .orient('bottom');
    
d3.select('.unclipped-area')
  .append('g')
    .attr('class','x_axis')
    .attr('transform','translate(0,' + screen_height + ')')
    .call(x_axis);  //call the axis generator
Place Data in Viewport, Functionally
var data_array = [
	{x:32, y:224}, //functionally, instead
        {x:47, y:113},
        {x:128, y:63},
        {x:178, y:160},
        ...
        ];
function drawCircles() {
d3.select('.scatter_plot')
  .selectAll('.data_point')
  .data(data_array)
  .enter()
   .append('circle')  //add the circles
    .attr('class', 'data_point')
    .attr('cx', function(point) { return x_scale(point.x); })
    .attr('cy', function(point) { return y_scale(point.y); })
    .attr('r', 4 ) //radius of 4
    .style('fill', 'blue' );//set style fill to blue
}

Data -> Color, Lines

jsfiddle.net/rbkreisberg/cdpcX/3/

Color by Value

z_color_scale = d3.scale.linear()
                    .domain([0,100])
                    .range(['blue','red']);

function drawCircles() {
...
       .attr('r',4)
       .style('fill',function(point) { 
            return z_color_scale(point.z);})
}
function setupRendering() {
    // create the path based on the index and y values    
    create_line = d3.svg.line()
          .x(function(point,i) {return x_scale(i);})
          .y(function(point) {return y_scale(point.y);})
          .interpolate('cardinal')
          .tension(0.7);
}

function drawLine() {
    d3.select('.line_plot')
        .selectAll('.data_line')
        .data([data_array])
      .enter()
      .append('path')	//path = line
        .attr('class','data_line')
        .attr('d',create_line); // 'd' determines the path
}

Animate with Transition()

jsfiddle.net/rbkreisberg/cdpcX/4/
function drawCircles() {
    d3.select('.scatter_plot')
...
.on('mouseover',function()  {  //change size and color on mouseover
	d3.select(this)
	.transition()
	  .duration(500)
	  .attr('r', 15)
	  .style('fill', 'black');
	})
.on('mouseout',function() {  //restore on mouseout
  d3.select(this)
    .transition()
       .duration(500)
       .attr( 'r', 4)                
       .style( 'fill', function(point) { 
             return z_color_scale(point.z); })
});
function appendDataPoint() {
  data_array.push(createDataPoint());// push a new point onto the back
    d3.select('.scatter_plot')
        .selectAll('.data_point')
        .remove();  //remove the circles

      drawCircles(); //redraw circles       

  d3.select('.data_plot')//move the parent panel of the circles to the left
        .attr("transform", null) //reset translation to zero
      .transition()  //begin the transition definition
        .duration(1000)  //for 1000 msec
        .ease("linear")  //at a constant rate        
        .attr("transform", "translate(" + x_scale(-1) + ")") //go left!
        .each("end", appendDataPoint);  //rinse and repeat
  
  data_array.shift(); // pop the oldest data point off of the array
}

Clip Away the Excess

jsfiddle.net/rbkreisberg/cdpcX/5/
//clipPath prevents the data from bleeding over into other areas    
svg.append("defs")
   .append("clipPath")
	  .attr("id", "clip")
   .append("rect")
	  .attr("width", w*0.8)
	  .attr("height", h*0.8);

//the plot area is inset from the border
svg.append('g')
     .attr('class','unclipped-area')  
     .attr('transform' , 'translate(' + ir_x_offset + ',' + ir_y_offset + ')')     
   .append('g')        
     .attr('class','clipped-area')     
     .attr("clip-path", "url(#clip)"); //attach clip

Resources

D3.js

Mike Bostock - bost.ocks.org/mike/ d3js.org github.com/mbostock/d3 D3 Google Groups Stack Overflow

HTML, SVG, Javascript, R

w3schools.com learnsvg.com svgbasics.com codeacademy.compolychart.com/js

Projects @ ISB

Regulome Explorer explorer.cancerregulome.org Transcriptional Regulation & Epigenetic Landscape trel.systemsbiology.net Pubcrawlpubcrawl.systemsbiology.net

Search 'codefor@systemsbiology.org' at code.google.com
dick.kreisberg@systemsbiology.org

Questions?

Reveal.JS

lab.hakim.se/reveal-js/

JSFiddle

jsfiddle.net

NodeJS

nodejs.org

Circos

circos.ca

vis.systemsbiology.net/sbw_2012/
IntroductionHTML5Tutorial