Related
I'm pretty new to D3.js (I'm a R programmer).
I'm trying to create a scatter and put a legend in the right bottom. However, it's overlapping with chart area.
I've been trying to take some examples in internet with no lucky.
When I try to move it to the right, the names and/or symbols are not visible.
I want to place the legend outside the chart frame, so it won't overlap.
Any help is appreciated.
Here's what I tried so far:
d3.csv('https://gist.githubusercontent.com/netj/8836201/raw/6f9306ad21398ea43cba4f7d537619d0e07d5ae3/iris.csv', function(data) {
// CSV section
var body = d3.select('body')
var selectData = [{
"text": "sepal.length"
},
{
"text": "sepal.width"
},
{
"text": "petal.length"
},
{
"text": "petal.width"
},
]
// setup fill color
var colors = ['#575757', '#5FB1B9', '#C94257'];
var symbol = d3.svg.symbol()
.type('circle')
.size("160")
var cValue = function(d) {
return d.variety;
},
color = d3.scale.ordinal()
.range(colors);
// Select Y-axis Variable
var span = body.append('span')
.text('Select Y-Axis variable: ')
var yInput = body.append('select')
.attr('id', 'ySelect')
.on('change', yChange)
.selectAll('option')
.data(selectData)
.enter()
.append('option')
.attr('value', function(d) {
return d.text
})
.text(function(d) {
return d.text;
})
body.append('br')
// Select X-axis Variable
var span = body.append('span')
.text('Select X-Axis variable: ')
var yInput = body.append('select')
.attr('id', 'xSelect')
.on('change', xChange)
.selectAll('option')
.data(selectData)
.enter()
.append('option')
.attr('value', function(d) {
return d.text
})
.text(function(d) {
return d.text;
})
body.append('br')
// Variables
var body = d3.select('body')
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 50
}
var h = 500 - margin.top - margin.bottom
var w = 500 - margin.left - margin.right
// var formatPercent = d3.format('.2%')
// Scales
// var colorScale = d3.scale.category20()
var xScale = d3.scale.linear()
.domain([
d3.min([0, d3.min(data, function(d) {
return d['sepal.length']
})]),
d3.max([0, d3.max(data, function(d) {
return d['sepal.length']
})])
])
.range([0, w])
var yScale = d3.scale.linear()
.domain([
d3.min([0, d3.min(data, function(d) {
return d['sepal.length']
})]),
d3.max([0, d3.max(data, function(d) {
return d['sepal.length']
})])
])
.range([h, 0])
// SVG
var svg = body.append('svg')
.attr('height', h + margin.top + margin.bottom)
.attr('width', w + margin.left + margin.right)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
// X-axis
var xAxis = d3.svg.axis()
.scale(xScale)
// .tickFormat(formatPercent)
.ticks(6)
.outerTickSize(0)
.tickSize(0)
.orient('bottom')
// Y-axis
var yAxis = d3.svg.axis()
.scale(yScale)
// .tickFormat(formatPercent)
.ticks(6)
.tickSize(-w)
.outerTickSize(0)
.orient('left')
// Circles
var circles = svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('cx', function(d) {
return xScale(d['sepal.length'])
})
.attr('cy', function(d) {
return yScale(d['sepal.length'])
})
.attr('r', '10')
// .attr('stroke', 'black')
.attr('stroke-width', 0.2)
.attr("fill", function(d) {
return color(cValue(d));
})
.attr('fill-opacity', 0.8)
// .attr('fill', function(d, i) {
// return colorScale(i)
// })
.on('mouseover', function() {
d3.select(this)
.transition()
.duration(300)
.ease('elastic')
.attr('r', 15)
.attr('stroke-width', 1)
.attr('fill-opacity', 1)
})
.on('mouseout', function() {
d3.select(this)
.transition()
.duration(100)
.attr('r', 10)
.attr('stroke-width', 0.5)
})
.append('title') // Tooltip
.text(function(d) {
return d.variety +
'\nSepal Length: ' + d['sepal.length'] +
'\nSepal Width: ' + d['sepal.width'] +
'\nPetal Length: ' + d['petal.length'] +
'\nPetal Width: ' + d['petal.width']
})
// X-axis
svg.append('g')
.attr('class', 'axis')
.attr('id', 'xAxis')
.attr('transform', 'translate(0,' + h + ')')
.call(xAxis)
.append('text') // X-axis Label
.attr('id', 'xAxisLabel')
.attr('y', -25)
.attr('x', w)
.attr('dy', '.71em')
.style('text-anchor', 'end')
.text('Sepal Length')
// labels distance from xaxis
svg.selectAll(".axis text")
.attr("dy", 15);
// Y-axis
svg.append('g')
.attr('class', 'axis')
.attr('id', 'yAxis')
.call(yAxis)
.append('text') // y-axis Label
.attr('id', 'yAxisLabel')
.attr('transform', 'rotate(-90)')
.attr('x', 0)
.attr('y', 5)
.attr('dy', '.71em')
.style('text-anchor', 'end')
.text('Sepal Length')
function yChange() {
var value = this.value // get the new y value
yScale // change the yScale
.domain([
d3.min([0, d3.min(data, function(d) {
return d[value]
})]),
d3.max([0, d3.max(data, function(d) {
return d[value]
})])
])
yAxis.scale(yScale) // change the yScale
d3.select('#yAxis') // redraw the yAxis
.transition().duration(500)
.call(yAxis)
d3.select('#yAxisLabel') // change the yAxisLabel
.text(value)
d3.selectAll('circle') // move the circles
.transition().duration(500)
.delay(function(d, i) {
return i * 10
})
.attr('cy', function(d) {
return yScale(d[value])
})
}
function xChange() {
var value = this.value // get the new x value
xScale // change the xScale
.domain([
d3.min([0, d3.min(data, function(d) {
return d[value]
})]),
d3.max([0, d3.max(data, function(d) {
return d[value]
})])
])
xAxis.scale(xScale) // change the xScale
d3.select('#xAxis') // redraw the xAxis
.transition().duration(500)
.call(xAxis)
d3.select('#xAxisLabel') // change the xAxisLabel
.transition().duration(500)
.text(value)
d3.selectAll('circle') // move the circles
.transition().duration(500)
.delay(function(d, i) {
return i * 10
})
.attr('cx', function(d) {
return xScale(d[value])
})
}
// create legend
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(0," + i * 25 + ")";
});
// draw legend colored rectangles
legend.append("path")
.attr('d', symbol)
.attr("transform", "translate(434, 313)") //much easier approach to position the symbols
// .attr("x", w + 34)
// .attr("y", h - 97)
// .attr("width", 18)
// .attr("height", 18)
.style("fill", color);
// draw legend text
legend.append("text")
.attr("transform", "translate(422, 311)")
// .attr("x", w + 24)
// .attr("y", h - 89)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {
return d;
})
})
body {
font-size: 16px;
}
/*
circle {
fill: steelblue;
} */
circle:hover {
fill: orange;
}
.axis text {
font-size: 13px;
/* font-weight: bold; */
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
stroke-width: 0.02px;
}
/* .circle {
fill: orange;
} */
label {
position: absolute;
top: 10px;
right: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script>
<body></body>
Why not just render your legend as HTML and use CSS to help with layout?
d3.csv('https://gist.githubusercontent.com/netj/8836201/raw/6f9306ad21398ea43cba4f7d537619d0e07d5ae3/iris.csv', function(data) {
// CSV section
var body = d3.select('body')
var selectData = [{
"text": "sepal.length"
},
{
"text": "sepal.width"
},
{
"text": "petal.length"
},
{
"text": "petal.width"
},
]
// setup fill color
var colors = ['#575757', '#5FB1B9', '#C94257'];
var symbol = d3.svg.symbol()
.type('circle')
.size("160")
var cValue = function(d) {
return d.variety;
},
color = d3.scale.ordinal()
.range(colors);
var controls = body.append('div').attr('class', 'controls')
// Select Y-axis Variable
var yControls = controls.append('div')
var span = yControls.append('span')
.text('Select Y-Axis variable: ')
var yInput = yControls.append('select')
.attr('id', 'ySelect')
.on('change', yChange)
.selectAll('option')
.data(selectData)
.enter()
.append('option')
.attr('value', function(d) {
return d.text
})
.text(function(d) {
return d.text;
})
// Select X-axis Variable
var xControls = controls.append('div')
var span = xControls.append('span')
.text('Select X-Axis variable: ')
var yInput = xControls.append('select')
.attr('id', 'xSelect')
.on('change', xChange)
.selectAll('option')
.data(selectData)
.enter()
.append('option')
.attr('value', function(d) {
return d.text
})
.text(function(d) {
return d.text;
})
// Variables
var body = d3.select('body')
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 50
}
var h = 500 - margin.top - margin.bottom
var w = 500 - margin.left - margin.right
var xScale = d3.scale.linear()
.domain([
d3.min([0, d3.min(data, function(d) {
return d['sepal.length']
})]),
d3.max([0, d3.max(data, function(d) {
return d['sepal.length']
})])
])
.range([0, w])
var yScale = d3.scale.linear()
.domain([
d3.min([0, d3.min(data, function(d) {
return d['sepal.length']
})]),
d3.max([0, d3.max(data, function(d) {
return d['sepal.length']
})])
])
.range([h, 0])
// SVG
var svgContainer = body.append('div').attr('class', 'svg-container')
var svg = svgContainer.append('svg')
.attr('height', h + margin.top + margin.bottom)
.attr('width', w + margin.left + margin.right)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
// X-axis
var xAxis = d3.svg.axis()
.scale(xScale)
// .tickFormat(formatPercent)
.ticks(6)
.outerTickSize(0)
.tickSize(0)
.orient('bottom')
// Y-axis
var yAxis = d3.svg.axis()
.scale(yScale)
// .tickFormat(formatPercent)
.ticks(6)
.tickSize(-w)
.outerTickSize(0)
.orient('left')
// Circles
var circles = svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('cx', function(d) {
return xScale(d['sepal.length'])
})
.attr('cy', function(d) {
return yScale(d['sepal.length'])
})
.attr('r', '10')
// .attr('stroke', 'black')
.attr('stroke-width', 0.2)
.attr("fill", function(d) {
return color(cValue(d));
})
.attr('fill-opacity', 0.8)
// .attr('fill', function(d, i) {
// return colorScale(i)
// })
.on('mouseover', function() {
d3.select(this)
.transition()
.duration(300)
.ease('elastic')
.attr('r', 15)
.attr('stroke-width', 1)
.attr('fill-opacity', 1)
})
.on('mouseout', function() {
d3.select(this)
.transition()
.duration(100)
.attr('r', 10)
.attr('stroke-width', 0.5)
})
.append('title') // Tooltip
.text(function(d) {
return d.variety +
'\nSepal Length: ' + d['sepal.length'] +
'\nSepal Width: ' + d['sepal.width'] +
'\nPetal Length: ' + d['petal.length'] +
'\nPetal Width: ' + d['petal.width']
})
// X-axis
svg.append('g')
.attr('class', 'axis')
.attr('id', 'xAxis')
.attr('transform', 'translate(0,' + h + ')')
.call(xAxis)
.append('text') // X-axis Label
.attr('id', 'xAxisLabel')
.attr('y', -25)
.attr('x', w)
.attr('dy', '.71em')
.style('text-anchor', 'end')
.text('Sepal Length')
// labels distance from xaxis
svg.selectAll(".axis text")
.attr("dy", 15);
// Y-axis
svg.append('g')
.attr('class', 'axis')
.attr('id', 'yAxis')
.call(yAxis)
.append('text') // y-axis Label
.attr('id', 'yAxisLabel')
.attr('transform', 'rotate(-90)')
.attr('x', 0)
.attr('y', 5)
.attr('dy', '.71em')
.style('text-anchor', 'end')
.text('Sepal Length')
function yChange() {
var value = this.value // get the new y value
yScale // change the yScale
.domain([
d3.min([0, d3.min(data, function(d) {
return d[value]
})]),
d3.max([0, d3.max(data, function(d) {
return d[value]
})])
])
yAxis.scale(yScale) // change the yScale
d3.select('#yAxis') // redraw the yAxis
.transition().duration(500)
.call(yAxis)
d3.select('#yAxisLabel') // change the yAxisLabel
.text(value)
d3.selectAll('circle') // move the circles
.transition().duration(500)
.delay(function(d, i) {
return i * 10
})
.attr('cy', function(d) {
return yScale(d[value])
})
}
function xChange() {
var value = this.value // get the new x value
xScale // change the xScale
.domain([
d3.min([0, d3.min(data, function(d) {
return d[value]
})]),
d3.max([0, d3.max(data, function(d) {
return d[value]
})])
])
xAxis.scale(xScale) // change the xScale
d3.select('#xAxis') // redraw the xAxis
.transition().duration(500)
.call(xAxis)
d3.select('#xAxisLabel') // change the xAxisLabel
.transition().duration(500)
.text(value)
d3.selectAll('circle') // move the circles
.transition().duration(500)
.delay(function(d, i) {
return i * 10
})
.attr('cx', function(d) {
return xScale(d[value])
})
}
// create legend
var legendContainer = body.append('div')
.attr('class', 'legend-container')
var legend = legendContainer.selectAll(".legend")
.data(color.domain())
.enter().append("div")
.attr("class", "legend")
// draw legend colored rectangles
legend.append("span")
.attr("class", "legend-color")
.style("background-color", color);
// draw legend text
legend.append("span")
.text(function(d) {
return d;
})
})
body {
font-size: 16px;
display: flex;
flex-wrap: wrap;
}
.controls {
flex: 1 1 100%;
}
.legend-container {
align-items: center;
flex: 0 1 auto;
align-self: center;
margin: 0 auto;
}
circle:hover {
fill: orange;
}
.axis text {
font-size: 13px;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
stroke-width: 0.02px;
}
label {
position: absolute;
top: 10px;
right: 10px;
}
.legend {
margin-bottom: 0.5em;
}
.legend-color {
width: 20px;
height: 20px;
display: inline-block;
border-radius: 50%;
vertical-align: middle;
margin-right: 1em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script>
<body></body>
With this approach you end up with a structure like this:
body
.controls
.svg-container
svg
.legend-container
which can make responsive layouts especially easy with CSS.
Hopefully Mike Bostock comes swinging in to my rescue on this one.
(EDIT: With the help of Andrea Crawford's answer below this is the working version)
JS Fiddle: https://jsfiddle.net/dfcarter/kd0dkrL8/
I have written a chart in d3 to allow on the fly user changes (colors, selected data, etc)
Well it is mainly working but when you remove the lower ordinals it stops centering on the graph and starts to creep downward.
Looks Fine - removing the first 3 seems fine
Looks Unacceptable - removing the Last 3 and the chart is toward the bottom of the graph area
The Core of the D3 for reference:
(The Fiddle works correctly I don't see why the external reference to spectrum is not working so look at the fiddle)
var $pop = $('#my_custom_menu'),
notHov = 1; // Hover flag
$pop.hover(function() {
notHov ^= 1;
}); // Toggle flag on hover
$(document).on('mouseup keyup', function(e) {
if (notHov || e.which == 27) $pop.fadeOut();
});
/////// CALL POPUP
$('.my_custom_menu').click(function() {
$pop.stop().fadeIn();
});
function updateStream(color) {
var label1 = d3.selectAll(".layer")
.filter(function(d, i) {
return i === clickIndex;
})
.style("fill", color);
}
$("#showPalette").spectrum({
showPalette: true,
palette: [
['black', 'white', 'blanchedalmond'],
['rgb(255, 128, 0);', 'hsv 100 70 50', 'lightyellow']
],
change: updateStream
});
var clickIndex = 0;
$("#textDisplayName").keyup(function(event) {
if (event.keyCode == 13) {
//alert(eval($("#stream").val) + " , " + eval($("#textDisplayname").val));
var newValue = document.getElementById("textDisplayName").value;
var label1 = d3.selectAll("text")
.filter(function(d, i) {
return i === clickIndex;
})
.text(newValue);
}
});
chart("data.csv", "blue");
var datearray = [];
var colorrange = [];
function csv(url, callback) {
d3.text(url, function(text) {
callback(text && d3.csv.parse(text));
});
}
function drawgrid() {
}
function chart(csvpath, color) {
if (color == "blue") {
colorrange = ["#045A8D", "#2B8CBE", "#74A9CF", "#A6BDDB", "#D0D1E6", "#F1EEF6"];
} else if (color == "pink") {
colorrange = ["#980043", "#DD1C77", "#DF65B0", "#C994C7", "#D4B9DA", "#F1EEF6"];
} else if (color == "orange") {
colorrange = ["#B30000", "#E34A33", "#FC8D59", "#FDBB84", "#FDD49E", "#FEF0D9"];
}
strokecolor = colorrange[0];
var format = d3.time.format("%m/%d/%y");
var margin = {
top: 20,
right: 40,
bottom: 30,
left: 30
};
var width = document.body.clientWidth - margin.left - margin.right - 200;
var height = 400 - margin.top - margin.bottom;
var tooltip = d3.select("body")
.append("div")
.attr("class", "remove")
.style("position", "absolute")
.style("z-index", "20")
.style("visibility", "hidden")
.style("top", "30px")
.style("left", "55px");
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height - 10, 0]);
var getColor = d3.scale.ordinal()
.range(colorrange);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(d3.time.weeks);
var yAxis = d3.svg.axis()
.scale(y);
var yAxisr = d3.svg.axis()
.scale(y);
var stack = d3.layout.stack()
.offset("silhouette")
.values(function(d) {
return d.values;
})
.x(function(d) {
return d.date;
})
.y(function(d) {
return d.value;
});
var nest = d3.nest()
.key(function(d) {
return d.key;
});
var area = d3.svg.area()
.interpolate("cardinal")
.x(function(d) {
return x(d.date);
})
.y0(function(d) {
return y(d.y0);
})
.y1(function(d) {
return y(d.y0 + d.y);
});
var svg = d3.select(".chart").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 + ")");
function randomData() {
return Math.random() * 9;
}
var dates = ["07/08/2016", "07/09/2016", "07/10/2016", "07/11/2016", "07/12/2016", "07/13/2016", "07/14/2016", "07/15/2016", "07/16/2016", "07/17/2016", "07/18/2016"];
var numberOfSeries = 7,
numberOfDataPoint = 7,
data = [];
for (var i = 0; i < numberOfSeries; ++i) {
for (var j = 0; j < numberOfDataPoint; ++j) {
data.push({
key: i,
value: randomData(),
date: Date.parse(dates[j])
});
}
}
var layerData = nest.entries(data);
var checkholder = d3.select("#checkboxHolder")
var legend = checkholder.selectAll(".legend")
.data(layerData)
.enter().append("div")
legend.append("input")
.attr("type", "checkbox")
.attr("id", function(d, i) {
return "check" + i
});
legend.append("label")
.attr("for", function(d, i) {
return "check" + i
})
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.html(function(d) {
return d.key;
});
legend.on('change', function(d) {
d.disabled = !d.disabled;
d3.transition().duration(600).each(redraw);
});
var xaxisnode = svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
var yaxisnode = svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ", 0)")
.call(yAxis.orient("right"));
//svg.append("g")
// .attr("class", "y axis")
// .call(yAxis.orient("left"));
function redraw() {
var activeLayers = layerData.filter(function(d1) {
return !d1.disabled;
});
var layers = stack(activeLayers);
x.domain(d3.extent(data, function(d) {
return d.date;
}));
y.domain([0, d3.max(data, function(d) {
if (!d.disabled) return d.y0 + d.y;
})]);
svg.selectAll(".layergroup").remove();
var layergroup = svg.selectAll(".layergroup")
.data(layers)
.enter().append("g")
.attr("class", "layergroup");
var paths = layergroup.append("path")
.attr("class", "layer")
.attr("d", function(d) {
return area(d.values);
})
.style("fill", function(d, i) {
return getColor(i);
});
layergroup.append("text")
.datum(function(d) {
return {
name: d.key,
value: d.values[d.values.length - 1]
};
})
.attr("transform", function(d) {
return "translate(" + x(d.value.date) + "," + y(d.value.y0 + d.value.y / 2) + ")";
})
.attr("x", -6)
.attr("dy", ".35em")
.attr("class", "pathLabel")
.text(function(d) {
return d.name;
});
//var clickIndex = 0;
//paths.on("click", function (d, i) {
// clickIndex = i;
// svg.selectAll("text").filter(function (d, i) { return i === clickIndex }).attr("transform", function (d) { var coords = d3.mouse(svg.node()); return "translate(" + coords[0] + "," + coords[1] + ")"; })
//});
xaxisnode.call(xAxis);
yaxisnode.call(yAxis.orient("right"));
const drag = d3.behavior.drag()
.origin(function(d) {
return d;
})
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended)
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
}
var dragIndex = 0;
function dragged(d, i) {
dragindex = i;
const elem = svg.selectAll(".pathLabel").filter(function(d, i) {
return i === dragindex;
});
elem.attr('transform', function(d) {
var coords = d3.mouse(svg.node());
return "translate(" + coords[0] + "," + coords[1] + ")";
});
//elem.attr('y', +elem.attr('y') + d3.event.dy)
}
function dragended(d) {}
svg.selectAll(".layer")
.attr("opacity", 1)
.on("mouseover", function(d, i) {
svg.selectAll(".layer").transition()
.duration(250)
.attr("opacity", function(d, j) {
return j != i ? 0.6 : 1;
})
})
.on("mousemove", function(d, i) {
mousex = d3.mouse(this);
mousex = mousex[0];
var invertedx = x.invert(mousex);
invertedx = invertedx.getMonth() + invertedx.getDate();
var selected = (d.values);
for (var k = 0; k < selected.length; k++) {
datearray[k] = selected[k].date
datearray[k] = datearray[k].getMonth() + datearray[k].getDate();
}
mousedate = datearray.indexOf(invertedx);
pro = d.values[mousedate].value;
mouse = d3.mouse(d3.select("#letable").node());
d3.select(this)
.classed("hover", true)
.attr("stroke", strokecolor)
.attr("stroke-width", "0.5px"),
tooltip.html("<p>" + d.key + "<br>" + pro + "</p>").style("visibility", "visible").style("left", (mouse[0] + 50) + "px").style("top", (mouse[1] + 30) + "px");
})
.on("mouseout", function(d, i) {
svg.selectAll(".layer")
.transition()
.duration(250)
.attr("opacity", "1");
d3.select(this)
.classed("hover", false)
.attr("stroke-width", "0px"), tooltip.html("<p>" + d.key + "<br>" + pro + "</p>").style("visibility", "hidden");
})
.on("contextmenu", function(data, index) {
var position = d3.mouse(this);
d3.select('#my_custom_menu')
.style('position', 'absolute')
.style('left', position[0] + "px")
.style('top', position[1] + "px")
.style('display', 'block');
d3.event.preventDefault();
//d3.select('#stream')
// .attr("value", index);
clickIndex = index;
$('#textDisplayName')
.val(data.key);
}).call(drag);
//d3.select('svg')
// .selectAll('text')
// .data(labels)
// .enter()
// .append('text')
// .text(d => d)
// .attr('fill', 'green')
// .attr('x', (d, i) => 10 + i * 30)
// .attr('y', (d, i) => 15 + i * 30)
// .call(drag)
var vertical = d3.select(".chart")
.append("div")
.attr("class", "remove")
.style("position", "absolute")
.style("z-index", "19")
.style("width", "1px")
.style("height", "380px")
.style("top", "10px")
.style("bottom", "30px")
.style("left", "0px")
.style("background", "#ccc");
d3.select(".chart")
.on("mousemove", function() {
mousex = d3.mouse(d3.select("#letable").node());
mousex = mousex[0] + 5;
vertical.style("left", mousex + "px")
})
.on("mouseover", function() {
mousex = d3.mouse(d3.select("#letable").node());
mousex = mousex[0] + 5;
vertical.style("left", mousex + "px")
});
}
redraw();
}
body {
font: 10px "segoe ui";
}
.chart {
background: #fff;
}
p {
font: 12px "segoe ui";
}
.axis path,
.axis line {
fill: none;
stroke: #CCC;
stroke-width: 2px;
shape-rendering: crispEdges;
}
.pathLabel {
font: bold 16px "Segoe UI";
color: black;
text-shadow: 0 0 3px #FFF;
}
button {
position: absolute;
right: 50px;
top: 10px;
}
#my_custom_menu {
display: none;
padding: 15px 25px;
width: 220px;
background: #fff;
border-radius: 4px;
box-shadow: 0 3px 3px -2px #024;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/2.6.0/d3.min.js"></script>
<!DOCTYPE html>
<body>
<script src="https://bgrins.github.io/spectrum/spectrum.js"></script>
<script src="https://d3js.org/d3.v2.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<link href="https://bgrins.github.io/spectrum/spectrum.css" rel="stylesheet" />
<table id="letable">
<tr>
<td>
<div id="checkboxHolder" style="width:200px;height:400px;overflow:auto;">
</div>
</td>
<td>
<div class="chart" style="width:700px;height:400px">
</div>
</td>
</tr>
</table>
<div id="my_custom_menu">
<input id="textDisplayName" type="text" />
<br />
<input id="showPalette" type="text" />
<br />
<input type="hidden" id="stream" value="" />
</div>
</body>
I'm not an expert on D3 so you may still want to wait for Mr. Bostock, but I think your issue is that inside your redraw function, you have this code:
y.domain([0, d3.max(data, function(d) {
if (!d.disabled) return d.y0 + d.y;
})]);
but if you look at the value of d, it doesn't actually have a disabled property.
You could add a disabled property to the values at the same time you add it to the parent:
legend.on('change', function(d) {
d.disabled = !d.disabled;
$.each(d.values, function(){
this.disabled = d.disabled;
});
d3.transition().duration(600).each(redraw);
});
There's probably a more elegant way to do that, but it seems to fix the issue.
Hi I am new in d3js so I am unable to use mouseover event in given code of pie chart...i have a <div> with id named chart so how can I create some class that mouseover event and show a label?
Here is the code that I am using to draw pie chart:
var w = 300;
var h = 300;
var dataset = [
{"year":"2017-07-01","value":"5"},
{"year":"2017-07-02","value":"10"},
{"year":"2017-07-03","value":"15"},
{"year":"2017-07-04","value":"20"},
{"year":"2017-07-05","value":"25"},
{"year":"2017-07-06","value":"30"},
{"year":"2017-07-07","value":"35"},
{"year":"2017-07-08","value":"40"},
{"year":"2017-07-09","value":"45"},
{"year":"2017-07-10","value":"50"},
{"year":"2017-07-11","value":"55"},
{"year":"2017-07-12","value":"60"},
{"year":"2017-07-13","value":"65"},
{"year":"2017-07-14","value":"70"}
];
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie()
.value(function(d) {
return d.value;
});
var color = d3.scale.category20();
var svg = d3.select("#chart")
.append("svg")
.attr("width", w)
.attr("height", h);
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
Add Styles on your HTML
<style>
#chart {
height: 360px;
position: relative;
width: 360px;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #333;
display: none;
font-size: 12px;
left: 130px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
width: 80px;
z-index: 10;
}
.legend {
font-size: 12px;
}
rect {
stroke-width: 2;
}
</style>
JS side
var width = 360;
var height = 360;
var radius = Math.min(width, height) / 2;
var donutWidth = 75;
var legendRectSize = 18;
var legendSpacing = 4;
var color = d3.scale.category20b();
var svg = d3.select('#chart')
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + (width / 2) +
',' + (height / 2) + ')');
var arc = d3.svg.arc()
.innerRadius(radius - donutWidth)
.outerRadius(radius);
var pie = d3.layout.pie()
.value(function(d) { return d.count; })
.sort(null);
var tooltip = d3.select('#chart')
.append('div')
.attr('class', 'tooltip');
tooltip.append('div')
.attr('class', 'label');
tooltip.append('div')
.attr('class', 'count');
tooltip.append('div')
.attr('class', 'percent');
var path = svg.selectAll('path')
.data(pie(dataset))
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d, i) {
return color(d.data.label);
});
path.on('mouseover', function(d) {
var total = d3.sum(dataset.map(function(d) {
return d.count;
}));
var percent = Math.round(1000 * d.data.count / total) / 10;
tooltip.select('.label').html(d.data.label);
tooltip.select('.count').html(d.data.count);
tooltip.select('.percent').html(percent + '%');
tooltip.style('display', 'block');
});
path.on('mouseout', function() {
tooltip.style('display', 'none');
});
var legend = svg.selectAll('.legend')
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * color.domain().length / 2;
var horz = -2 * legendRectSize;
var vert = i * height - offset;
return 'translate(' + horz + ',' + vert + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) { return d; });
I hope this helps you. You might have to work around, it depends on how you want to show tool tip and how you populate data in your chart.
I assume that what you want is a tooltip. The easiest way to do this is to append an svg:title element to each circle, as the browser will take care of showing the tooltip and you don't need the mousehandler. The code would be something like
vis.selectAll("circle")
.data(datafiltered).enter().append("svg:circle")
...
.append("svg:title")
.text(function(d) { return d.x; });
If you want fancier tooltips, you could use tipsy for example. See here for an example.
I am trying to build a pie chart using the d3. I learned the concept from the site click here but when i hover over a part of pie chart the tooltip is not showing
here's my css style code used
#chart {
height: 360px;
margin: 0 auto; /* NEW */
position: relative;
width: 360px;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #333;
display: none;
font-size: 12px;
left: 130px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
width: 80px;
z-index: 4;
}
.legend {
font-size: 12px;
}
rect {
cursor: pointer; /* NEW */
stroke-width: 2;
}
rect.disabled { /* NEW */
fill: transparent !important; /* NEW */
}
and here's the code for the js part
$rootScope.renderPieChart = function(dataset,dom_element_to_append_to){
var width = $(dom_element_to_append_to).width(),
height = 500,
radius = Math.min(width, height) / 2;
var donutWidth = 75;
var legendRectSize = 18;
var legendSpacing = 4;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var svg = d3.select(dom_element_to_append_to)
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(radius - donutWidth);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.value; });
var tooltip = d3.select(dom_element_to_append_to)
.append('div')
.attr('class', 'tooltip');
console.log(tooltip);
tooltip.append('div')
.attr('class', 'label');
tooltip.append('div')
.attr('class', 'count');
tooltip.append('div')
.attr('class', 'percent');
var path = svg.selectAll('path')
.data(pie(dataset))
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d, i) {
return color(d.data.label + " " + d.data.value);
});
path.on('mouseover', function(d) { // NEW
var total = d3.sum(dataset.map(function(d) { // NEW
return d.value; // NEW
}));
console.log("mouseover"); // NEW
var percent = Math.round(1000 * d.data.value / total) / 10; // NEW
tooltip.select('.label').html(d.data.label); // NEW
tooltip.select('.count').html(d.data.value); // NEW
tooltip.select('.percent').html(percent + '%'); // NEW
tooltip.style('display', 'block'); // NEW
});
path.on('mouseout', function() {
console.log("mouseout"); // NEW
tooltip.style('display', 'none'); // NEW
});
var legend = svg.selectAll('.legend')
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * color.domain().length / 2;
var horz = -2 * legendRectSize;
var vert = i * height - offset;
return 'translate(' + horz + ',' + vert + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) { return d; })
};
it is a function which takes the dataset and the dom element to which the whole pie chart is going to append
and here's a sample dataset
var dataset = [
{ label: 'Abulia', value: 10 },
{ label: 'Betelgeuse', value: 20 },
{ label: 'Cantaloupe', value: 30 },
{ label: 'Dijkstra', value: 40 }
];
instead of display: none, display: block thing in css i have also tried to opacity: 1, opacity: 0 thing but still no result.
Thanks in advance
now it's generating here's a working code
$rootScope.renderPieChart = function(dataset,dom_element_to_append_to){
var width = $(dom_element_to_append_to).width(),
height = $(window).height() - 120,
radius = Math.min(width, height) / 2;
var donutWidth = 75;
var legendRectSize = 18;
var legendSpacing = 4;
dataset.forEach(function(item){
item.enabled = true;
});
/*var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
*/
var color = $rootScope.defaultColorScheme;
var svg = d3.select(dom_element_to_append_to)
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(radius - donutWidth);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.value; });
var tooltip = d3.select(dom_element_to_append_to)
.append('div')
.attr('class', 'tooltip');
tooltip.append('div')
.attr('class', 'label');
tooltip.append('div')
.attr('class', 'count');
tooltip.append('div')
.attr('class', 'percent');
var path = svg.selectAll('path')
.data(pie(dataset))
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d, i) {
return color(d.data.label );
})
.each(function(d) { this._current = d; });
path.on('mouseover', function(d) {
var total = d3.sum(dataset.map(function(d) {
return (d.enabled) ? d.value : 0;
}));
var percent = Math.round(1000 * d.data.value / total) / 10;
tooltip.select('.label').html(d.data.label.toUpperCase()).style('color','black');
tooltip.select('.count').html(d.data.value);
tooltip.select('.percent').html(percent + '%');
/* //console.log(percent);
//console.log(tooltip.select('.percent')); */
tooltip.style('display', 'block');
tooltip.style('opacity',2);
});
path.on('mousemove', function(d) {
tooltip.style('top', (d3.event.layerY + 10) + 'px')
.style('left', (d3.event.layerX - 25) + 'px');
});
path.on('mouseout', function() {
tooltip.style('display', 'none');
tooltip.style('opacity',0);
});
var legend = svg.selectAll('.legend')
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * color.domain().length / 2;
var horz = -2 * legendRectSize;
var vert = i * height - offset;
return 'translate(' + horz + ',' + vert + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color)
.on('click', function(label) { // NEW
var rect = d3.select(this); // NEW
var enabled = true; // NEW
var totalEnabled = d3.sum(dataset.map(function(d) { // NEW
return (d.enabled) ? 1 : 0; // NEW
})); // NEW
if (rect.attr('class') === 'disabled') { // NEW
rect.attr('class', ''); // NEW
} else { // NEW
if (totalEnabled < 2) return; // NEW
rect.attr('class', 'disabled'); // NEW
enabled = false; // NEW
} // NEW
pie.value(function(d) { // NEW
if (d.label === label) d.enabled = enabled; // NEW
return (d.enabled) ? d.value : 0; // NEW
}); // NEW
path = path.data(pie(dataset)); // NEW
path.transition() // NEW
.duration(750) // NEW
.attrTween('d', function(d) { // NEW
var interpolate = d3.interpolate(this._current, d); // NEW
this._current = interpolate(0); // NEW
return function(t) { // NEW
return arc(interpolate(t)); // NEW
}; // NEW
}); // NEW
}); // NEW
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) { return d; })
};
I have a scatter plot matrix for which I need a tooltip. I tried using the following code, but then, it gives me tooltips at random points and not at the exact cells.
Can someone tell me where am I going wrong ? Or is not possible to generate a tooltip for my data?
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
padding: 10px;
}
.axis,
.frame {
shape-rendering: crispEdges;
}
.axis line {
stroke: #ddd;
}
.axis path {
display: none;
}
.frame {
fill: none;
stroke: #aaa;
}
circle {
fill-opacity: .7;
}
circle.hidden {
fill: #ccc !important;
}
.extent {
fill: #000;
fill-opacity: .125;
stroke: #fff;
}
</style>
<body>
<div id="chart3"> </div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
var width = 419,
size = 130,
padding = 19.5,
height = 313;
var x = d3.scale.linear().domain([0,100])
.range([padding / 2, size - padding / 2]);
var y = d3.scale.linear().domain([0,1])
.range([size - padding / 2, padding / 2]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
var color = d3.scale.ordinal()
.domain(['no chemo', 'induction', 'induction+chemoRT', 'concurrent'])
.range(['#ffae19', '#4ca64c', '#4682B4', '#c51b8a']);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([50,70])
.html(function (d) {
var coordinates = d3.mouse(this);
xValue = x.invert(coordinates[0]);
yValue = y.invert(coordinates[1]);
return "<strong> Age Of Patient " + d3.format(".2f")(xValue * 100)+
" <br/> Probability of Survival : " + d3.format(".2f")(yValue*100) + " % </strong>";
});
d3.csv("SurvivalProbability.csv", function (error, data) {
if (error)
throw error;
var domainByTrait = {},
traits = d3.keys(data[0]).filter(function (d) {
return (d == 'AgeAtTx' || d == 'Probability of Survival')
}),
n = traits.length;
traits.forEach(function (trait) {
domainByTrait[trait] = d3.extent(data, function (d) {
return d[trait];
});
});
xAxis.tickSize(size * n);
yAxis.tickSize(-size * n);
var brush = d3.svg.brush()
.x(x)
.y(y)
.on("brushstart", brushstart)
.on("brush", brushmove)
.on("brushend", brushend);
var svg = d3.select("#chart3").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + padding + "," + padding / 2 + ")");
svg.call(tip);
svg.selectAll(".x.axis")
.data(traits)
.enter().append("g")
.attr("class", "x axis")
.attr("transform", function (d, i) {
return "translate(" + (n - i - 1) * size + ",0)";
})
.each(function (d) {
x.domain(domainByTrait[d]);
d3.select(this).call(xAxis);
});
svg.selectAll(".y.axis")
.data(traits)
.enter().append("g")
.attr("class", "y axis")
.attr("transform", function (d, i) {
return "translate(0," + i * size + ")";
})
.each(function (d) {
y.domain(domainByTrait[d]);
d3.select(this).call(yAxis);
});
var cell = svg.selectAll(".cell")
.data(cross(traits, traits))
.enter().append("g")
.attr("class", "cell")
.attr("transform", function (d) {
return "translate(" + (n - d.i - 1) * size + "," + d.j * size + ")";
})
.each(plot)
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
// Titles for the diagonal.
cell.filter(function (d) {
return d.i === d.j;
}).append("text")
.attr("x", padding)
.attr("y", padding)
.attr("dy", ".71em")
.text(function (d) {
return d.x;
});
cell.call(brush);
function plot(p) {
var cell = d3.select(this);
x.domain(domainByTrait[p.x]);
y.domain(domainByTrait[p.y]);
cell.append("rect")
.attr("class", "frame")
.attr("x", padding / 2)
.attr("y", padding / 2)
.attr("width", size - padding)
.attr("height", size - padding);
cell.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("cx", function (d) {
return x(d[p.x]);
})
.attr("cy", function (d) {
return y(d[p.y]);
})
.attr("r", 5)
.style("fill", function (d) {
return color(d.Chemotherapy);
});
}
var brushCell;
// Clear the previously-active brush, if any.
function brushstart(p) {
if (brushCell !== this) {
d3.select(brushCell).call(brush.clear());
x.domain(domainByTrait[p.x]);
y.domain(domainByTrait[p.y]);
brushCell = this;
}
}
// Highlight the selected circles.
function brushmove(p) {
var e = brush.extent();
svg.selectAll("circle").classed("hidden", function (d) {
return e[0][0] > d[p.x] || d[p.x] > e[1][0]
|| e[0][1] > d[p.y] || d[p.y] > e[1][1];
});
}
// If the brush is empty, select all circles.
function brushend() {
if (brush.empty())
svg.selectAll(".hidden").classed("hidden", false);
}
function cross(a, b) {
var c = [], n = a.length, m = b.length, i, j;
for (i = - 1; ++i < n; )
for (j = - 1; ++j < m; )
c.push({x: a[i], i: i, y: b[j], j: j});
return c;
}
d3.select(self.frameElement).style("height", size * n + padding + 20 + "px");
var legendRectSize = 10;
var legendSpacing = 10;
var legend = svg.append("g")
.selectAll("g")
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function (d, i) {
var height = legendRectSize;
var x = 2 * size;
var y = (i * height) + 120;
return 'translate(' + x + ',' + y + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendSpacing)
.text(function (d) {
return d;
});
});
</script>
A screenshot of my data - Survival Probability.csv
Ethnicity,AgeAtTx,Site,Tcategory,Nodal_Disease,ecog,Chemotherapy,Local_Therapy,Probability of Survival,KM OS,OS (months),sex
white,65.93972603,supraglottic,T3,N+,0,no chemo,LP/RT alone,0.366190068,0,112.9,Female
white,69.42465753,supraglottic,T3,N+,0,induction,PLRT,0.396018836,0,24.1,Male
white,68.14246575,supraglottic,T3,N0,3,no chemo,LP/RT alone,0.439289384,0,3.566666667,Female
white,40.30410959,supraglottic,T3,N+,1,no chemo,LP/RT alone,0.512773973,1,226.3,Male
white,47.96438356,supraglottic,T3,N+,0,no chemo,PLRT,0.472208904,0,9.6,Female
white,70.3369863,supraglottic,T3,N+,0,no chemo,LP/RT alone,0.324965753,0,25.26666667,Male
white,60.50136986,supraglottic,T3,N+,2,no chemo,LP/RT alone,0.323424658,0,9.5,Female
white,60.72328767,supraglottic,T3,N+,1,no chemo,LP/RT alone,0.321344178,0,15.03333333,Male
white,59.36986301,supraglottic,T3,N0,1,induction,LP/chemoRT,0.646532534,0,4.5,Male
other,57.64931507,supraglottic,T3,N+,1,concurrent,LP/chemoRT,0.662662671,1,52.73333333,Male
This is an interesting situation. It boils down essentially to element append order and mouse-events. First, let's fix the obvious. You want a tooltip on each circle, so you shouldn't be calling tip.show when you mouse over a cell, but on the circles:
cell.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("cx", function(d) {
return x(d[p.x]);
})
.attr("cy", function(d) {
return y(d[p.y]);
})
.attr("r", 5)
.style("fill", function(d) {
return color(d.Chemotherapy);
})
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
But you'll notice with this change, we don't receive the events on our circles. This is because svg.brush is placing a rect over each cell so that you can select with the extent, and it's receiving the mouse events. So to fix that we change the order of drawing to brush then circle:
var cell = svg.selectAll(".cell")
.data(cross(traits, traits))
.enter().append("g")
.attr("class", "cell")
.attr("transform", function(d) {
return "translate(" + (n - d.i - 1) * size + "," + d.j * size + ")";
});
// add the brush stuff
cell.call(brush);
// now the circles
cell.each(plot);
But we still have a problem. We've got one more rect on top of our circles, the frame rect. Since we don't care about mouse events on it just do a simple:
.style("pointer-events", "none");
Putting this all together:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
padding: 10px;
}
.axis,
.frame {
shape-rendering: crispEdges;
}
.axis line {
stroke: #ddd;
}
.axis path {
display: none;
}
.frame {
fill: none;
stroke: #aaa;
}
circle {
fill-opacity: .7;
}
circle.hidden {
fill: #ccc !important;
}
.extent {
fill: #000;
fill-opacity: .125;
stroke: #fff;
}
</style>
<body>
<div id="chart3"> </div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
var width = 419,
size = 130,
padding = 19.5,
height = 313;
var x = d3.scale.linear().domain([0, 100])
.range([padding / 2, size - padding / 2]);
var y = d3.scale.linear().domain([0, 1])
.range([size - padding / 2, padding / 2]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
var color = d3.scale.ordinal()
.domain(['no chemo', 'induction', 'induction+chemoRT', 'concurrent'])
.range(['#ffae19', '#4ca64c', '#4682B4', '#c51b8a']);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([50, 70])
.html(function(d) {
console.log(d)
var coordinates = d3.mouse(this);
xValue = x.invert(coordinates[0]);
yValue = y.invert(coordinates[1]);
return "<strong> Age Of Patient " + d3.format(".2f")(xValue * 100) +
" <br/> Probability of Survival : " + d3.format(".2f")(yValue * 100) + " % </strong>";
});
//d3.csv("data.csv", function(error, data) {
// if (error)
// throw error;
var data = [{"Ethnicity":"white","AgeAtTx":"65.93972603","Site":"supraglottic","Tcategory":"T3","Nodal_Disease":"N+","ecog":"0","Chemotherapy":"no chemo","Local_Therapy":"LP/RT alone","Probability of Survival":"0.366190068","KM OS":"0","OS (months)":"112.9","sex":"Female"},{"Ethnicity":"white","AgeAtTx":"69.42465753","Site":"supraglottic","Tcategory":"T3","Nodal_Disease":"N+","ecog":"0","Chemotherapy":"induction","Local_Therapy":"PLRT","Probability of Survival":"0.396018836","KM OS":"0","OS (months)":"24.1","sex":"Male"},{"Ethnicity":"white","AgeAtTx":"68.14246575","Site":"supraglottic","Tcategory":"T3","Nodal_Disease":"N0","ecog":"3","Chemotherapy":"no chemo","Local_Therapy":"LP/RT alone","Probability of Survival":"0.439289384","KM OS":"0","OS (months)":"3.566666667","sex":"Female"},{"Ethnicity":"white","AgeAtTx":"40.30410959","Site":"supraglottic","Tcategory":"T3","Nodal_Disease":"N+","ecog":"1","Chemotherapy":"no chemo","Local_Therapy":"LP/RT alone","Probability of Survival":"0.512773973","KM OS":"1","OS (months)":"226.3","sex":"Male"},{"Ethnicity":"white","AgeAtTx":"47.96438356","Site":"supraglottic","Tcategory":"T3","Nodal_Disease":"N+","ecog":"0","Chemotherapy":"no chemo","Local_Therapy":"PLRT","Probability of Survival":"0.472208904","KM OS":"0","OS (months)":"9.6","sex":"Female"},{"Ethnicity":"white","AgeAtTx":"70.3369863","Site":"supraglottic","Tcategory":"T3","Nodal_Disease":"N+","ecog":"0","Chemotherapy":"no chemo","Local_Therapy":"LP/RT alone","Probability of Survival":"0.324965753","KM OS":"0","OS (months)":"25.26666667","sex":"Male"},{"Ethnicity":"white","AgeAtTx":"60.50136986","Site":"supraglottic","Tcategory":"T3","Nodal_Disease":"N+","ecog":"2","Chemotherapy":"no chemo","Local_Therapy":"LP/RT alone","Probability of Survival":"0.323424658","KM OS":"0","OS (months)":"9.5","sex":"Female"},{"Ethnicity":"white","AgeAtTx":"60.72328767","Site":"supraglottic","Tcategory":"T3","Nodal_Disease":"N+","ecog":"1","Chemotherapy":"no chemo","Local_Therapy":"LP/RT alone","Probability of Survival":"0.321344178","KM OS":"0","OS (months)":"15.03333333","sex":"Male"},{"Ethnicity":"white","AgeAtTx":"59.36986301","Site":"supraglottic","Tcategory":"T3","Nodal_Disease":"N0","ecog":"1","Chemotherapy":"induction","Local_Therapy":"LP/chemoRT","Probability of Survival":"0.646532534","KM OS":"0","OS (months)":"4.5","sex":"Male"},{"Ethnicity":"other","AgeAtTx":"57.64931507","Site":"supraglottic","Tcategory":"T3","Nodal_Disease":"N+","ecog":"1","Chemotherapy":"concurrent","Local_Therapy":"LP/chemoRT","Probability of Survival":"0.662662671","KM OS":"1","OS (months)":"52.73333333","sex":"Male"}];
var domainByTrait = {},
traits = d3.keys(data[0]).filter(function(d) {
return (d == 'AgeAtTx' || d == 'Probability of Survival')
}),
n = traits.length;
traits.forEach(function(trait) {
domainByTrait[trait] = d3.extent(data, function(d) {
return d[trait];
});
});
xAxis.tickSize(size * n);
yAxis.tickSize(-size * n);
var brush = d3.svg.brush()
.x(x)
.y(y)
.on("brushstart", brushstart)
.on("brush", brushmove)
.on("brushend", brushend);
var svg = d3.select("#chart3").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + padding + "," + padding / 2 + ")");
svg.call(tip);
svg.selectAll(".x.axis")
.data(traits)
.enter().append("g")
.attr("class", "x axis")
.attr("transform", function(d, i) {
return "translate(" + (n - i - 1) * size + ",0)";
})
.each(function(d) {
x.domain(domainByTrait[d]);
d3.select(this).call(xAxis);
});
svg.selectAll(".y.axis")
.data(traits)
.enter().append("g")
.attr("class", "y axis")
.attr("transform", function(d, i) {
return "translate(0," + i * size + ")";
})
.each(function(d) {
y.domain(domainByTrait[d]);
d3.select(this).call(yAxis);
});
var cell = svg.selectAll(".cell")
.data(cross(traits, traits))
.enter().append("g")
.attr("class", "cell")
.attr("transform", function(d) {
return "translate(" + (n - d.i - 1) * size + "," + d.j * size + ")";
});
cell.call(brush);
cell.each(plot);
// Titles for the diagonal.
cell.filter(function(d) {
return d.i === d.j;
}).append("text")
.attr("x", padding)
.attr("y", padding)
.attr("dy", ".71em")
.text(function(d) {
return d.x;
});
function plot(p) {
var cell = d3.select(this);
x.domain(domainByTrait[p.x]);
y.domain(domainByTrait[p.y]);
cell.append("rect")
.attr("class", "frame")
.attr("x", padding / 2)
.attr("y", padding / 2)
.attr("width", size - padding)
.attr("height", size - padding)
.style("pointer-events", "none");
cell.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("cx", function(d) {
return x(d[p.x]);
})
.attr("cy", function(d) {
return y(d[p.y]);
})
.attr("r", 5)
.style("fill", function(d) {
return color(d.Chemotherapy);
})
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
}
var brushCell;
// Clear the previously-active brush, if any.
function brushstart(p) {
if (brushCell !== this) {
d3.select(brushCell).call(brush.clear());
x.domain(domainByTrait[p.x]);
y.domain(domainByTrait[p.y]);
brushCell = this;
}
}
// Highlight the selected circles.
function brushmove(p) {
var e = brush.extent();
svg.selectAll("circle").classed("hidden", function(d) {
return e[0][0] > d[p.x] || d[p.x] > e[1][0] || e[0][1] > d[p.y] || d[p.y] > e[1][1];
});
}
// If the brush is empty, select all circles.
function brushend() {
if (brush.empty())
svg.selectAll(".hidden").classed("hidden", false);
}
function cross(a, b) {
var c = [],
n = a.length,
m = b.length,
i, j;
for (i = -1; ++i < n;)
for (j = -1; ++j < m;)
c.push({
x: a[i],
i: i,
y: b[j],
j: j
});
return c;
}
var legendRectSize = 10;
var legendSpacing = 10;
var legend = svg.append("g")
.selectAll("g")
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize;
var x = 2 * size;
var y = (i * height) + 120;
return 'translate(' + x + ',' + y + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendSpacing)
.text(function(d) {
return d;
});
//});
</script>