Responsive Heatmap

by ramnathv

HTML

<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//rawgit.com/kristw/75b61f9beeab9b530612/raw/389e984e4041117a9185cf6edad9f6b85a38097a/d3kit.min.js"></script>
<script src="//rawgit.com/gka/d3-jetpack/master/d3-jetpack.js"></script>
<script src="//rawgit.com/Caged/d3-tip/master/index.js"></script>
<link rel="stylesheet" href="//rawgit.com/Caged/d3-tip/master/examples/example-styles.css">
<script src="//rawgit.com/ramnathv/a5a3199538f86817ec1b/raw/f6627fc544e65d8e6186ba87556f743caa3f2730/visutils.js"></script>
<script src="//rawgit.com/ramnathv/1838a632793dc787ca68/raw/1f1bd60ecd673e983320eb4777c1f333a4934594/testdata.js"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<!-- Nav tabs -->
<div class="btn-group" role="group" aria-label="...">
  <a type="button" class="btn btn-default" href='#chart' id='showChart' data-toggle='tab'>Left</a>
  <a type="button" href='#messages' class="btn btn-default data" data-set='iris' data-toggle='tab'>Iris</a>
   <a type="button" href='#messages2' class="btn btn-default data" data-set='iris2' data-toggle='tab'>Iris</a>
   <a type="button" href='#messages4' class="btn btn-default data" data-set='iris' data-toggle='tab'>Iris</a>
</div>

  

  <!-- Tab panes -->
  <div class="tab-content">
    <div role="tabpanel" class="tab-pane fade heatmap" id="chart"></div>
    <div role="tabpanel" class="active tab-pane fade heatmap" id="messages"></div>
    <div role="tabpanel" class="tab-pane" id="settings">...</div>
  </div>

</div>

CSS

body{
  font-family: "Helvetica";
  font-size: 13px;
  padding-top: 40px;
}
.heatmap .y-axis-layer path,
.heatmap .y-axis-layer line{
  fill: none;
}
.heatmap .x-axis-layer path,
.heatmap .x-axis-layer line{
  fill: none;
}
.heatmap .y-axis-layer text,
.heatmap .x-axis-layer text{
  font-size: 11px;
  fill-opacity: 0.6;
}
/*
.heatmap .cell {
  stroke: #ddd;
}
*/
.heatmap .cell .label{
  stroke: black;
  font-size: 10px;
  font-weight: normal;
}
.d3-tip{
  font-weight: normal;
  line-height: 1.4em;
  pointer-events: none !important;
}

CoffeeScript

heatMapConstructor = (skeleton) ->
  layers = skeleton.getLayerOrganizer()
  S =
    x: d3.scale.ordinal()
    y: d3.scale.ordinal()
    c: d3.scale.linear()
  A =
    x: (d) -> d.x
    y: (d) -> d.y
    c: (d) -> d.c
  layers.create(['cells', 'y-axis', 'x-axis', 'accuracy'])
  visualize = ->
    data = skeleton.data()
    opts = skeleton.options()
    x = Math.min(
      skeleton.getInnerWidth(), skeleton.getInnerHeight()
    )
    W_ = x; H_ = x;
    S.x.rangeRoundBands([0, W_]).domain data.map(A.x)
    S.y.rangeRoundBands([0, H_]).domain data.map(A.y)
    #S.c.range(['crimson', 'white', 'purple'])
    #  .domain [-1, 0, 1]
    S.c.range(['white', 'rgb(0, 158, 115)'])
      .domain([0, 1])
    S.c2 = S.c.copy()
      .range(['white', 'darkred'])
    cells = layers.get('cells').selectAll('.cell')
      .data(data)
    cells.enter().append('rect.cell')
    cells.attr
      x: (d) -> S.x A.x(d)
      y: (d) -> S.y A.y(d)
      width: S.x.rangeBand()
      height: S.y.rangeBand()
      stroke: (d) ->
        '#ddd'
      fill: (d) -> 
        if d.x is "Sum" or d.y is "Sum"
            '#fff'
        else if (d.x is d.y)
          S.c A.c(d)
        else
          S.c2 A.c(d)
    cells.exit().remove()
    tooltipFn = (d) ->
      if (d.x is 'Sum' or d.y is 'Sum')
        return "Count of #{d.y}: #{d.Freq}"
      if (d.x is d.y)
        prefix = 'correctly'
      else
        prefix = 'incorrectly'
      """
      #{d3.format('%.2f')(d.c)} of <b>#{d.y}</b> are <br/>  #{prefix} classified as <b>#{d.x}</b>
      """
      
    cells
      .filter((d) -> d.y != 'Sum')
      .call attachTooltip, {html: tooltipFn}
    
    labels = layers.get('cells').selectAll('.hlabel')
      .data(data)
    labels.enter().append('text.hlabel')
    labels.attr
      x: (d) -> S.x(A.x(d)) + S.x.rangeBand()/2
      y: (d) -> S.y(A.y(d)) + S.y.rangeBand()/2
      "text-anchor": "middle"
      "alignment-baseline": "middle"
      "pointer-events": "none"
      "fill-opacity": 0.8
     ...