2

How does one make a basic scatter plot like the one below using Plottable.js?

  • Is there something wrong with my JSON?
  • How to reveal the minus scales?
  • Would you have done anything else differently?

Style doesn't matter, the default Plottable.js one is fine.

enter image description here

window.onload = function() {
  var coordinates = [
    {
      x:"-5", 
      y:"3"
    }, {
      x:"2", 
      y:"-1,5"
    }, {
      x:"5", 
      y:"2,5"
    }
  ];
  
  var xScale = new Plottable.Scale.Linear();
  var yScale = new Plottable.Scale.Linear();
  var colorScale = new Plottable.Scale.Color("10");

  var xAxis = new Plottable.Axis.Numeric(xScale, "bottom");
  var yAxis = new Plottable.Axis.Numeric(yScale, "left");

  var plot = new Plottable.Plot.Scatter(xScale, yScale)
                      .addDataset(coordinates)
                      .project("x", "", xScale)
                      .project("y", "", yScale)
                      .project("fill", "", colorScale);
  
  var chart = new Plottable.Component.Table([
      [yAxis, plot],
      [null,  xAxis]
  ]);

  chart.renderTo("#my_chart");
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Test</title>
    <link rel="stylesheet" href="https://rawgit.com/palantir/plottable/develop/plottable.css">
  </head>
  <body>
    <svg width="100%" height="600" id="my_chart"></svg>
    <script src="https://rawgit.com/mbostock/d3/master/d3.min.js"></script>
    <script src="https://rawgit.com/palantir/plottable/develop/plottable.min.js"></script>
  </body>
</html>
Flynt Hamlock
  • 349
  • 2
  • 12
  • Are you getting any console errors? What output if any are you getting? "Would you have done anything else differently" doesn't really fit with stackoverflow as it's too opinionated. Code review type stuff fits a bit better at programmers stackexchange. – scrappedcola Mar 24 '15 at 15:53
  • 2
    @scrappedcola Code Review stuff usually fits better at [codereview.se] - I suggest you take a look at the [CR Help Center](http://www.codereview.stackexchange.com/help/on-topic) (hint: code that doesn't work as expected is explicitly off-topic)... and [Programmers' Help Center](http://www.programmers.stackexchange.com/help/on-topic), too. – Mathieu Guindon Mar 24 '15 at 15:58
  • Although this seems like a fine enough [so] question... – nhgrif Mar 24 '15 at 16:00
  • Are you really asking how to draw a **four quadrant plot** (sometimes called a student style axis) with *plottable.js*? I'd be [surprised](http://plottablejs.org/docs/classes/plottable.axis.numeric.html#constructor) if it supports such a thing. Might be time to really learn d3.js.... – Mark Mar 24 '15 at 16:42
  • Thanks @Mark, I had no idea what they were called. I just started doing high school level math. Will be drawing a lot of graphs in the time to come. Is there no way around having to learn D3? I find its code extremely confusing. I thought Plottable was to D3 what jQuery is to JavaScript? – Flynt Hamlock Mar 25 '15 at 08:44
  • 1
    A suggestion, Flynt: When giving the data in the first few lines, encode the numbers as numbers and not strings (ie: take away the quotation marks). Plottable will autoconvert the strings to numbers for you, but nothing good can come of relying on automatic type conversion when you can just specify the type yourself. – dandelion Mar 30 '15 at 19:40

2 Answers2

2

Mark has the right idea - the table system doesn't natively support this layout, so you need to take some manual control over how they are laid out. However, using somewhat obscure parts of the Plottable API, there is a cleaner and better-supported way to lay out the chart you want, which doesn't have the problem of the axes being slightly offset.

The first change is we are going to stop using the table layout engine entirely, since it isn't able to do what we want. Instead, we will plop all the components together in a Component.Group. A Group just overlays components in the same space without trying to position them at all.

var chart = new Plottable.Component.Group([yAxis, xAxis, plot]);

Then we are going to use the alignment and offset methods that are defined on the base (abstract) component class. We set the x-alignment of the y axis to "center" and the y-alignment of the x axis to "center" This will put the axes in the center of the chart.

var xAxis = new Plottable.Axis.Numeric(xScale, "bottom").yAlign("center"); var yAxis = new Plottable.Axis.Numeric(yScale, "left").xAlign("center");

We're not quite done at this point, since to really center the axes we need to shift them back by one half of their own width. The width is only calculated when the chart is rendered (strictly speaking, in the computeLayout call, but that is an internal detail), so we need to set an offset after the chart is rendered:

chart.renderTo("#plottable"); xAxis.yOffset(xAxis.height()/2); yAxis.xOffset(-yAxis.width()/2);

You can see the final result here (it's a fork of Mark's plnkr). Note that now the axes are aligned on the center of the chart, as the center dot is perfectly on 0,0.

dandelion
  • 1,742
  • 1
  • 15
  • 18
1

Here's a couple examples I just put together. The first is the straight d3 way of doing what you are asking. The second is a hacked up plottable.js. With plottable.js I can't find a way to position the axis outside of their table system, I had to resort to manually moving them. The table system they use is designed to relieve the developer of having to manually position things. This is great and easy, of course, until you want to control where to position things.

Here's the hack, after you render your plottable:

  // move the axis...
  d3.select(".y-axis")
    .attr('transform',"translate(" + width / 2 + "," + 0 + ")");        
  d3.select(".x-axis")
    .attr("transform", "translate(" + 48 + "," + height / 2 + ")");

Note, I didn't remove the left side margin (the 48 above) that plottable puts in. This could be hacked in as well, but at that point, what is plottable providing for you anyway...

It should be noted that the different appearance of each plot is entirely controlled through the CSS.

Complete d3 scatter plot:

// D3 EXAMPLE
var margin = {
  top: 20,
  right: 20,
  bottom: 20,
  left: 20
},
  width = 500 - margin.left - margin.right,
  height = 500 - margin.top - margin.bottom;

var x = d3.scale.linear()
  .range([0, width]);

var y = d3.scale.linear()
  .range([height, 0]);

var xAxis = d3.svg.axis()
  .scale(x)
  .orient("bottom");

var yAxis = d3.svg.axis()
  .scale(y)
  .orient("left");

var svg = d3.select("#d3").append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

x.domain([-100, 100]);
y.domain([-100, 100]);

svg.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(" + 0 + "," + height / 2 + ")")
  .call(xAxis);

svg.append("g")
  .attr("class", "y axis")
  .attr("transform", "translate(" + width / 2 + "," + 0 + ")")
  .call(yAxis)
  .append("text");

svg.selectAll(".dot")
  .data(data)
  .enter().append("circle")
  .attr("class", "dot")
  .attr("r", function(d) {
    return d.r;
  })
  .attr("cx", function(d) {
    return x(d.x);
  })
  .attr("cy", function(d) {
    return y(d.y);
  })
  .style("fill", function(d) {
    return d.c;
  });

enter image description here

Plottable.js:

  // PLOTTABLE.JS
  var xScale = new Plottable.Scale.Linear();
  var yScale = new Plottable.Scale.Linear();

  var xAxis = new Plottable.Axis.Numeric(xScale, "bottom");
  var yAxis = new Plottable.Axis.Numeric(yScale, "left");

  var plot = new Plottable.Plot.Scatter(xScale, yScale);
  plot.addDataset(data);

  function getXDataValue(d) {
    return d.x;
  }
  plot.project("x", getXDataValue, xScale);
  function getYDataValue(d) {
    return d.y;
  }
  plot.project("y", getYDataValue, yScale);
  function getRDataValue(d){
    return d.r;
  }
  plot.project("r", getRDataValue);
  function getFillValue(d){
    return d.c;
  }
  plot.project("fill", getFillValue);
  var chart = new Plottable.Component.Table([
                    [yAxis, plot],
                    [null,  xAxis]
                  ]);
  chart.renderTo("#plottable");

  d3.select(".y-axis")
    .attr('transform',"translate(" + width / 2 + "," + 0 + ")");

  d3.select(".x-axis")
    .attr("transform", "translate(" + 48 + "," + height / 2 + ")");

enter image description here

Mark
  • 106,305
  • 20
  • 172
  • 230
  • Couple of follow-ups if you don't mind: 1) how to center the axes on origo? -- 2) what's wrong with my JSON? http://jsbin.com/pazecifaxe/1/edit -- 3) any idea how to display the actual coordinates next to the dots? – Flynt Hamlock Mar 28 '15 at 21:20
  • @FlyntHamlock, I updated your [link](http://jsbin.com/wapezaceza/1/edit?html,js,output) 1.) Set equal domains on your ranges: `xScale.domain([-5, 5]);` 2.) You x and ys are strings, it looks like plottable.js trys to parse them but is using an American locale (ie `1.5` vs `1,5`) 3.) this is a harder one, I'm running out the door now, I'll take a look tomorrow. – Mark Mar 28 '15 at 22:21
  • @FlyntHamlock, and again, with this level of customization you are looking for just use `d3.js`... – Mark Mar 28 '15 at 22:24
  • Awesome, thanks again! As for d3.js, I don't know, I guess I'm just not comfortable with the level of complexity in the code. UPDATE: Just came across http://dimplejs.org -- maybe I should just go with that? – Flynt Hamlock Mar 29 '15 at 10:24