This is a scatter plot of the Iris data set.
The purpose of this example is to show one approach for using Model.js to make reusable visualization modules. This also introduces a way to isolate reusable reactive flows that are reusable between visualizations.
Notice that if you open this in a new window, it responds when you resize the browser window. This is coded in such a way that the visualization size can be controlled via CSS.
This example is a lead-in to The Reactivis Concept, which takes generalization of D3 patterns further.
The code for this is derived from example 106 of the screencast Introduction to D3.js.
xxxxxxxxxx
<html>
<head>
<meta charset="utf-8">
<title>D3 Example</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="model-min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Poiret+One' rel='stylesheet' type='text/css'>
<style>
body {
background-color: lightgray;
}
.axis text {
font-family: 'Poiret One', cursive;
font-size: 16pt;
}
.axis .label {
font-size: 20pt;
}
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.visualization {
position: fixed;
top: 50px;
bottom: 50px;
left: 280px;
right: 280px;
background-color: white;
border-radius: 25px;
border-style: dotted;
border-width: 2px;
}
circle:hover {
stroke-width: 2px;
stroke: black;
}
</style>
</head>
<body>
<div class="visualization" id="scatterPlotContainer"></div>
<script>
function ScatterPlot(container){
var model = Model();
var svg = container.append("svg");
var g = svg.append("g");
var xAxisG = g.append("g")
.attr("class", "x axis");
var xAxisLabel = xAxisG.append("text")
.style("text-anchor", "middle")
.attr("class", "label");
var yAxisG = g.append("g")
.attr("class", "y axis");
var yAxisLabel = yAxisG.append("text")
.style("text-anchor", "middle")
.attr("class", "label");
var xAxis = d3.svg.axis()
.orient("bottom")
.tickFormat(d3.format("s"))
.outerTickSize(0);
var yAxis = d3.svg.axis()
.orient("left")
.tickFormat(d3.format("s"))
.outerTickSize(0);
// This encapsulates the D3 margin convention from https://bl.ocks.org/mbostock/3019563
model.when(["outerWidth", "outerHeight", "margin"],
function(outerWidth , outerHeight , margin){
model.set({
innerWidth: outerWidth - margin.left - margin.right,
innerHeight: outerHeight - margin.top - margin.bottom
});
});
model.when(["outerWidth" ], function (outerWidth ){ svg.attr("width" , outerWidth ); });
model.when(["outerHeight"], function (outerHeight){ svg.attr("height", outerHeight); });
model.when("margin", function (margin){
g.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
});
model.when("innerHeight", function (innerHeight){
xAxisG.attr("transform", "translate(0," + innerHeight + ")");
});
model.when(["innerWidth", "xAxisLabelOffset", "xAxisLabelText"],
function(innerWidth, xAxisLabelOffset, xAxisLabelText){
xAxisLabel
.attr("x", innerWidth / 2)
.attr("y", xAxisLabelOffset)
.text(xAxisLabelText);
});
model.when(["innerHeight", "yAxisLabelOffset", "yAxisLabelText"],
function(innerHeight, yAxisLabelOffset, yAxisLabelText){
yAxisLabel
.attr("transform", "translate(-" + yAxisLabelOffset + "," + (innerHeight / 2) + ") rotate(-90)")
.text(yAxisLabelText);
});
(function (){
var xScale = d3.scale.linear();
model.when(["data", "xAccessor"], function(data, xAccessor){
model.xScaleDomain = d3.extent(data, xAccessor);
});
model.when(["xScaleDomain", "innerWidth"], function (xScaleDomain, innerWidth){
model.xScale = xScale.domain(xScaleDomain).range([0, innerWidth]);
});
}());
(function (){
var yScale = d3.scale.linear();
model.when(["data", "yAccessor"], function(data, yAccessor){
model.yScaleDomain = d3.extent(data, yAccessor);
});
model.when(["yScaleDomain", "innerHeight"], function (yScaleDomain, innerHeight){
model.yScale = yScale.domain(yScaleDomain).range([innerHeight, 0]);
});
}());
(function (){
var rScale = d3.scale.linear();
model.when(["data", "rColumn"], function(data, rColumn){
model.rScaleDomain = d3.extent(data, function (d){ return d[rColumn]; });
});
model.when(["rScaleDomain", "rMin", "rMax"], function (rScaleDomain, rMin, rMax){
model.rScale = rScale.domain(rScaleDomain).range([rMin, rMax]);
});
}());
model.when(["xScale", "xAxisNumTicks"], function (xScale, xAxisNumTicks){
xAxisG.call(xAxis.scale(xScale).ticks(xAxisNumTicks));
});
model.when(["yScale", "yAxisNumTicks"], function (yScale, yAxisNumTicks){
yAxisG.call(yAxis.scale(yScale).ticks(yAxisNumTicks));
});
model.when("xColumn", function (xColumn){
model.xAccessor = function (d){ return d[xColumn]; };
});
model.when(["xScale", "xAccessor"], function (xScale, xAccessor){
model.x = compose(xScale, xAccessor);
});
model.when("yColumn", function(yColumn){
model.yAccessor = function (d){ return d[yColumn]; };
});
model.when(["yScale", "yAccessor"], function (yScale, yAccessor){
model.y = compose(yScale, yAccessor);
});
model.when("rColumn", function(rColumn){
model.rAccessor = function (d){ return d[rColumn]; };
});
model.when(["rScale", "rAccessor"], function (rScale, rAccessor){
model.r = compose(rScale, rAccessor);
});
model.when("colorColumn", function(colorColumn){
model.colorAccessor = function (d){ return d[colorColumn]; };
});
model.when(["colorScale", "colorAccessor"], function (colorScale, colorAccessor){
model.color = compose(colorScale, colorAccessor);
});
model.when(["data", "x", "y", "r", "color"], function(data, x, y, r, color){
var circles = g.selectAll("circle").data(data);
circles.enter().append("circle");
circles
.attr("cx", x)
.attr("cy", y)
.attr("r", r)
.attr("fill", color)
circles.exit().remove();
});
return model;
}
// https://en.wikipedia.org/wiki/Function_composition
function compose(g, f){
return function(d){ return g(f(d)); };
}
function main(){
var container = d3.select("#scatterPlotContainer");
var scatterPlot = ScatterPlot(container);
scatterPlot.set({
outerWidth: 100,
outerHeight: 500,
margin: { left: 80, top: 10, right: 15, bottom: 80 },
rMin: 2, // "r" stands for radius
rMax: 15,
xColumn: "sepal_length",
yColumn: "petal_length",
rColumn: "sepal_width",
colorColumn: "species",
colorScale: d3.scale.category10(),
xAxisLabelText: "Sepal Length (cm)",
xAxisLabelOffset: 65,
xAxisNumTicks: 10,
yAxisLabelText: "Petal Length (cm)",
yAxisLabelOffset: 35,
yAxisNumTicks: 5
});
function type(d){
d.sepal_length = +d.sepal_length;
d.sepal_width = +d.sepal_width;
d.petal_length = +d.petal_length;
d.petal_width = +d.petal_width;
return d;
}
d3.csv("iris.csv", type, function (data) {
scatterPlot.data = data;
});
function setSize(){
var containerNode = container.node();
scatterPlot.set({
outerWidth: containerNode.clientWidth,
outerHeight: containerNode.clientHeight
});
}
d3.select(window).on("load" , setSize);
d3.select(window).on("resize", setSize);
}
main();
</script>
</body>
</html>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js