D3.JS Tool tip with a dot plot - javascript

<!DOCTYPE html>
<html lang="en">
<head>
<h1> Amount of money spent on gas in a week vs Distance from work(miles)<h1/>
<meta charset="utf-8">
<title>D3: Labels removed</title>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<style type="text/css">
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
</style>
</head>
<body>
<script type="text/javascript">
//Width and height
var w = 1000;
var h = 610;
var padding = 50;
//Static dataset
var dataset = [
[63, 45], [60, 43], [10, 12], [95, 60], [30, 15]
];
/*
//Dynamic, random dataset
var dataset = []; //Initialize empty array
var numDataPoints = 50; //Number of dummy data points to create
var xRange = Math.random() * 1000; //Max range of new x values
var yRange = Math.random() * 1000; //Max range of new y values
for (var i = 0; i < numDataPoints; i++) { //Loop numDataPoints times
var newNumber1 = Math.floor(Math.random() * xRange); //New random integer
var newNumber2 = Math.floor(Math.random() * yRange); //New random integer
dataset.push([newNumber1, newNumber2]); //Add new number to array
}
*/
//Create scale functions
var xScale = d3.scale.linear()
.domain([0, 100]) // This is what is written on the Axis: from 0 to 100
.range([0, w]);
var yScale = d3.scale.linear()
.domain([0, 100 ]) // This is what is written on the Axis: from 0 to 100
.range([h, 0]);
var rScale = d3.scale.linear()
.domain([5, 5])
.range([5, 5]);
//Define X axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(5);
//Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Create circles
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return xScale(d[0]);
})
.attr("cy", function(d) {
return yScale(d[1]);
})
.attr("r", function(d) {
return rScale(d[1]);
});
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>dataset:</strong> <span style='color:red'>" + d.dataset + "</span>";})
svg.selectAll("circle")
svg.selectAll("circle")
.data(dataset)
.enter().append("rect")
.attr("class", "circle")
.attr("x", function(d) { return x(d.dataset); })
.attr("width", 0)
.attr("y", function(d) { return y(d.dataset); })
.attr("height", function(d) { return height - y(d.dataset); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
//X AND Y text
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("x", -175)
.attr("y", 12)
.attr("transform", "rotate(-90)")
.text("Distance from work (Miles) ")
.attr("font-size",'12pt')
.attr("font-weight","bold");
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("x", 700)
.attr("y", 600)
.text("Amount of money spent on gas in a week ")
.attr("font-size",'12pt')
.attr("font-weight","bold");
/*
//Create labels
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d[0] + "," + d[1];
})
.attr("x", function(d) {
return xScale(d[0]);
})
.attr("y", function(d) {
return yScale(d[1]);
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "red");
*/
//Create X axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
//Create Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
function type(d) {
d.dataset = +d.dataset;
return d;
}
</script>
</body>
</html>
Hello im trying to add a tool tip to my circles. When I run the code I dont get an error in my console which makes me think that it works but it does not. I think im missing something simple but I am in general not sure. Would really appreciate any help on this issue. the var.tip part is where I think the biggest problem is at

There are a few problems in the code:
the tooltip plugin should be bound to the data visualization, as documented in the quick usage instructions:
/* Invoke the tip in the context of your visualization */
vis.call(tip)
In your case, svg.call(tip) should be executed before the creation of the circles.
For some reason, the mouseover and mouseout event listeners are attached to some rectangles (classed circle), instead of being attached to the circles.
The tooltips are filled using d.dataset, which is inexistent, hence undefined. Assuming that you want to display the x, y coordinates, d may be used instead.
The snippet below illustrates the fixes.
P.S. You may want to use a more recent version of d3 and of the tooltip plugin, in order to benefit from latest bug fixes and other enhancements.
//Width and height
var w = 1000;
var h = 610;
var padding = 50;
//Static dataset
var dataset = [
[63, 45], [60, 43], [10, 12], [95, 60], [30, 15]
];
//Create scale functions
var xScale = d3.scale.linear()
.domain([0, 100]) // This is what is written on the Axis: from 0 to 100
.range([0, w]);
var yScale = d3.scale.linear()
.domain([0, 100 ]) // This is what is written on the Axis: from 0 to 100
.range([h, 0]);
var rScale = d3.scale.linear()
.domain([5, 5])
.range([5, 5]);
//Define X axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(5);
//Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var tip = d3.tip()
//.attr('class', 'd3-tip')
//.offset([-10, 0])
.html(function(d) {
return "<strong>dataset:</strong> <span style='color:red'>" + d + "</span>";})
svg.call(tip)
//Create circles
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return xScale(d[0]);
})
.attr("cy", function(d) {
return yScale(d[1]);
})
.attr("r", function(d) {
return rScale(d[1]);
})
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
svg.selectAll("circle")
.data(dataset)
.enter().append("rect")
.attr("class", "circle")
.attr("x", function(d) { return x(d.dataset); })
.attr("width", 0)
.attr("y", function(d) { return y(d.dataset); })
.attr("height", function(d) { return height - y(d.dataset); })
//X AND Y text
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("x", -175)
.attr("y", 12)
.attr("transform", "rotate(-90)")
.text("Distance from work (Miles) ")
.attr("font-size",'12pt')
.attr("font-weight","bold");
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("x", 700)
.attr("y", 600)
.text("Amount of money spent on gas in a week ")
.attr("font-size",'12pt')
.attr("font-weight","bold");
//Create X axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
//Create Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
function type(d) {
d.dataset = +d.dataset;
return d;
}
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>

Related

D3.JS bar graph column offset while adding new data

I'm currently working with D3.JS attempting to add to an existing graph every 24 hours. Using JSON data like this:
[{"name": "bill", "val": 28}, {"name": "kevin", "val": 46}, {"name": "ryan", "val": 23},{"name": "ville", "val": 56}]
I have a frequency value on my Y axis, and a username on my xaxis. I think I have my placement function correct, but when adding a new column (although the offset should stay the same) all columns are shifted out of place. The goal is to be able to add columns (new data) and keep the columns (rects) above the proper username.
Here is my current working code:
<html>
<head>
<script type="text/javascript" src="d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script type="data/json" src="data.json"></script>
<style>
#chart rect{
fill: #4aaeea;
}
#chart text{
fill: white;
font: 10px sans-serif;
text-anchor: end;
}
.axis text{
font: 10px sans-serif;
}
.axis path, .axis line{
fill: none;
stroke : #fff;
shape-rendering: crispEdges;
}
body{
background: #1a1a1a;
color : #eaeaea;
padding : 5px;
}
</style>
</head>
<body>
<div id="chart"</div>
<script>
var margin ={top:20, right:30, bottom:30, left:40},
width=960-margin.left - margin.right,
height=500-margin.top-margin.bottom;
// scale to ordinal because x axis is not numerical
var x = d3.scale.ordinal().rangeRoundBands([0, width], .1);
//scale to numerical value by height
var y = d3.scale.linear().range([height, 0]);
var chart = d3.select("#chart")
.append("svg") //append svg element inside #chart
.attr("width", width+(2*margin.left)+margin.right) //set width
.attr("height", height+margin.top+margin.bottom); //set height
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom"); //orient bottom because x-axis will appear below the bars
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var data;
d3.json("http://localhost:8000/data.json", function(error, data){
if (error) return console.warn(error);
x.domain(data.map(function(d){ return d.name}));
y.domain([0, d3.max(data, function(d){return d.val})]);
var bar = chart.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d, i){
return "translate("+x(d.name)+", 0)";
});
console.log(margin.left);
bar.append("rect")
.attr("y", function(d) {
return y(d.val);
})
.attr("x", function(d,i){
return x(margin.left + 2);
})
.attr("height", function(d) {
return height - y(d.val);
})
.attr("width", Math.min.apply(null, [x.rangeBand()-2, 100]));
//.attr("width", x.rangeBand()); //set width base on range on ordinal data
bar.append("text")
.attr("x", (margin.left * 2.2))
.attr("y", function(d) { return y(d.val) })
.attr("dy", ".75em")
.text(function(d) { return d.val; });
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate("+margin.left+","+ height+")")
.call(xAxis);
chart.append("g")
.attr("class", "y axis")
.attr("transform", "translate("+margin.left+",0)")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
});
function type(d) {
d.name = +d.name; // coerce to number
return d;
}
</script>
I have done a few adjustments to the positional attributes of g elements containing bar rect elements and dx and dy attributes of text elements.
Hope this working code snippet helps.
var margin = {
top: 20,
right: 30,
bottom: 30,
left: 40
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// scale to ordinal because x axis is not numerical
var x = d3.scale.ordinal().rangeRoundBands([0, width], .1);
//scale to numerical value by height
var y = d3.scale.linear().range([height, 0]);
var chart = d3.select("#chart")
.append("svg") //append svg element inside #chart
.attr("width", width + margin.left + margin.right) //set width
.attr("height", height + margin.top + margin.bottom); //set height
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom"); //orient bottom because x-axis will appear below the bars
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var data = [{
"name": "bill",
"val": 28
}, {
"name": "kevin",
"val": 46
}, {
"name": "ryan",
"val": 23
}, {
"name": "ville",
"val": 56
}];
x.domain(data.map(function(d) {
return d.name
}));
y.domain([0, d3.max(data, function(d) {
return d.val
})]);
var barWidth = Math.min.apply(null, [x.rangeBand() - 2, 100]);
var bar = chart.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d, i) {
return "translate(" + x(d.name) + ", " + y(d.val) + ")";
});
bar.append("rect")
.attr("y", 0)
.attr("x", barWidth - 10)
.attr("height", function(d) {
return height - y(d.val);
})
.attr("width", barWidth);
bar.append("text")
.attr("x", barWidth - 10)
.attr("y", 0)
.attr("dx", barWidth / 2)
.attr("dy", ".75em")
.text(function(d) {
return d.val;
});
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(" + margin.left + "," + height + ")")
.call(xAxis);
chart.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin.left + ",0)")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
function type(d) {
d.name = +d.name; // coerce to number
return d;
}
#chart rect {
fill: #4aaeea;
}
#chart text {
fill: white;
font: 10px sans-serif;
text-anchor: end;
}
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #fff;
shape-rendering: crispEdges;
}
body {
background: #1a1a1a;
color: #eaeaea;
padding: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="chart" </div>

d3 - multiple overlaying charts with custom DOM element

I'm new to d3, but pretty familiar with the HighCharts api.
I've seen lots of examples of multiple d3 charts on the same page; but can't seem to find examples of one chart overlaying/sitting directly on top of another chart. Is this possible?
With HighCharts, you can define multiple chart types in the plotOptions config object. Is there something similar with d3? Or, how could you do this with d3?
I would effectively like to have a line graph on top of a bar chart. There will be different 'stages' according to the data, so some of the bar's could be inactive/empty.
Additionally, I need to display an indicator to show where the 'stage' is currently; and ensure that this is all responsive.
Example (rough mockup):
After researching d3 and looking for similar examples, I am thinking that maybe d3 isn't the best choice for this; maybe a custom CSS/JS/HTML solution (inside an angular app) would be better.
Any recommendations or pointers would be very appreciated.
Here's a quick mock-up started from this excellent bar chart example:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.point rect {
fill: steelblue;
}
.point circle {
fill: orange;
}
.point rect:hover {
fill: brown;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: orange
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 75, right: 20, bottom: 30, left: 40},
width = 600 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
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("body").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 + ")");
var data = "abcdefghijklmnopqrstuvwxyz".split("").map(function(d){
return {
letter: d,
bar: Math.random() * 10,
line: Math.random() * 10
};
})
x.domain(data.map(function(d) { return d.letter; }));
y.domain([0, d3.max(data, function(d) { return d3.max([d.bar, d.line]); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text");
var points = svg.selectAll(".point")
.data(data)
.enter().append("g")
.attr("class", "point");
points.append('rect')
.attr("x", function(d) { return x(d.letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.bar); })
.attr("height", function(d) { return height - y(d.bar); });
points.append('circle')
.attr("r", 5)
.attr("cx", function(d){ return x(d.letter) + x.rangeBand() / 2; })
.attr("cy", function(d){ return y(d.line)});
var line = d3.svg.line()
.x(function(d) { return x(d.letter) + x.rangeBand() / 2; })
.y(function(d) { return y(d.line); });
svg.append("path")
.attr("class", "line")
.datum(data)
.attr("d", line);
var indicator = svg.append("g")
.attr("r", 5)
.attr("transform", "translate(" + (x("q") + x.rangeBand() / 2) + "," + -20 + ")");
indicator.append("circle")
.attr("r", 40)
.style("fill", "red");
indicator.append("text")
.text("!")
.style("fill", "white")
.style("text-anchor", "middle")
.style("alignment-baseline", "middle")
.style("font-size", 70);
indicator.append("line")
.attr("y1", 20)
.attr("y2", height + 20)
.attr("x1", 0)
.attr("x2", 0)
.style("stroke", "red")
.style("stroke-width", "4px");
</script>
New Solution Based on Comments
Given your input data, here's a new example. I went a bit overboard here, so please ask question on any confusing bits. I tried to comment it out:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
rect {
fill: steelblue;
}
circle {
fill: orange;
}
rect:hover {
fill: brown;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: orange
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {
top: 75,
right: 20,
bottom: 30,
left: 40
},
width = 600 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
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("body").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 + ")");
// here's your data
var data =
{
'point1': [{
'value': 50
}, {
'value': 100
}, {
'value': 100
}, {
'value': 150
}],
'point2': [{
'value': 25
}, {
'value': 40
}, {
'value': 60
}],
'point3': [{
'value': 25
}]
};
// d3ify your data
// d3 likes arrays of objects, you have an object of objects
// so first make it an array
var barData = d3.entries(data);
// set x domain
x.domain(barData.map(function(d){ return d.key }));
// create lineData
var lineData = [];
barData.forEach(function(d0, i){
d0.mean = d3.mean(d0.value, function(d1){ return d1.value });
d0.max = d3.max(d0.value, function(d1){ return d1.value});
var N = d0.value.length,
// this is an inner scale
// that represents each bar
s = d3.scale.linear().range([
x(d0.key) + (x.rangeBand() / N) / 2,
x(d0.key) + x.rangeBand()
]).domain([
0, N
])
d0.value.forEach(function(d1, j){
lineData.push({
x: s(j), // this is the pixel position of x, it's jittered on the bar
y: d1.value // this is the user position of y
})
});
});
// set y domain
y.domain([0, d3.max(barData, function(d) {
return d.max;
})]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text");
// draw bars
var bars = svg.selectAll(".bar")
.data(barData)
.enter()
.append('rect')
.attr('class', 'bar')
.attr("x", function(d) {
return x(d.key);
})
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d.mean);
})
.attr("height", function(d) {
return height - y(d.mean);
});
// add points
var points = svg.selectAll('point')
.data(lineData)
.enter()
.append('circle')
.attr('class', 'point')
.attr("r", 5)
.attr("cx", function(d) {
return d.x; // already pixel position
})
.attr("cy", function(d) {
return y(d.y)
});
var line = d3.svg.line()
.x(function(d) {
return d.x; // already pixel position
})
.y(function(d) {
return y(d.y);
});
svg.append("path")
.attr("class", "line")
.datum(lineData)
.attr("d", line);
var indicator = svg.append("g")
.attr("transform", "translate(" + (x("point2") + x.rangeBand() / 2) + "," + -20 + ")");
indicator.append("circle")
.attr("r", 40)
.style("fill", "red");
indicator.append("text")
.text("!")
.style("fill", "white")
.style("text-anchor", "middle")
.style("alignment-baseline", "middle")
.style("font-size", 70);
indicator.append("line")
.attr("y1", 20)
.attr("y2", height + 20)
.attr("x1", 0)
.attr("x2", 0)
.style("stroke", "red")
.style("stroke-width", "4px");
</script>
Happy d3ing!

How to create SVG with grid lines using D3JS

I am planning to build a graph that will be designed by user by drag drop. I want to add grid lines to it. Currently I doing like:
var svg = d3.select("#canvas").append("svg")
.attr("width", width)
.attr("height", height);
for (var i = 0; i <= 10; i++) {
svg.append("line")
.attr("x1", i*60)
.attr("y1", 0)
.attr("x2", i*60)
.attr("y2", 600)
.attr("stroke-width", 0.5)
.attr("stroke", "grey");
svg.append("line")
.attr("x1", 0)
.attr("y1", i * 60)
.attr("x2", 600)
.attr("y2", i * 60)
.attr("stroke-width", 0.5)
.attr("stroke", "grey");
}
Is there a better way of doing this? Also, except the first and last lines in the grid, the other lines are appearing thick.
https://jsfiddle.net/krishnasarma/rnyzkfrf/
Any help with simple drag drop of an image/object is greatly appreciated.
Please see the below code
index.html
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 12px Arial;
}
text.shadow {
stroke: #fff;
stroke-width: 2.5px;
opacity: 0.9;
}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
.grid .tick {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
.area {
fill: lightsteelblue;
stroke-width: 0;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 30, right: 20, bottom: 35, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse;
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
var area = d3.svg.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.close); });
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
var svg = d3.select("body")
.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 for the x grid lines
function make_x_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5)
}
// function for the y grid lines
function make_y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
}
// Get the data
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Add the filled area
svg.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
// Draw the x Grid lines
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat("")
)
// Draw the y Grid lines
svg.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
)
// Add the valueline path.
svg.append("path")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// Add the text label for the X axis
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height+margin.bottom) + ")")
.style("text-anchor", "middle")
.text("Date");
// Add the white background to the y axis label for legibility
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("x", margin.top - (height / 2))
.attr("dy", ".71em")
.style("text-anchor", "end")
.attr("class", "shadow")
.text("Price ($)");
// Add the text label for the Y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("x", margin.top - (height / 2))
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Price ($)");
// Add the title
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text("Price vs Date Graph");
});
</script>
</body>
data.csv
date,close
1-May-12,58.13
30-Apr-12,53.98
27-Apr-12,67.00
26-Apr-12,89.70
25-Apr-12,99.00
24-Apr-12,130.28
23-Apr-12,166.70
20-Apr-12,234.98
19-Apr-12,345.44
18-Apr-12,443.34
17-Apr-12,543.70
16-Apr-12,580.13
13-Apr-12,605.23
12-Apr-12,622.77
11-Apr-12,626.20
10-Apr-12,628.44
9-Apr-12,636.23
5-Apr-12,633.68
4-Apr-12,624.31
3-Apr-12,629.32
2-Apr-12,618.63
30-Mar-12,599.55
29-Mar-12,609.86
28-Mar-12,617.62
27-Mar-12,614.48
26-Mar-12,606.98
d3noob’s block #e1aa

How to change color of the dots in D3.js to reflect data on y scale?

I am starting with the d3.js and have decided to build a weather graph but the points (or nodes?) do not change color as they should i.e. not by temperature (position on y scale) but according to their position on x scale? What am I doing wrong?
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 2.5px;
}
.dot {
fill: steelblue;
stroke: steelblue;
stroke-width: 1.5px;
}
</style>
<body>
<script src="d3/d3.min.js" charset="utf-8"></script>
<script>
var tooltip = d3.select('body').append('div')
.style('position','absolute')
var data = [
[new Date(1961, 0, 1), 6.3],
[new Date(2014, 0, 1), 9.4]
];
var margin = {top: 20, right: 30, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var tooltip = d3.select('body').append('div')
.style('position', 'absolute')
.style('padding', '0 10px')
var colors = d3.scale.linear()
.domain([5, 20])
.range(['#000000','#ffffff'])
var x = d3.time.scale()
.domain([new Date(1960, 0, 1), new Date(2015, 0, 1)])
.range([0, width]);
var y = d3.scale.linear()
.domain([5, 10])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("monotone")
.x(function(d) { return x(d[0]); })
.y(function(d) { return y(d[1]); });
var svg = d3.select("body").append("svg")
.datum(data)
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Teplota (ºC)");
svg.append("path")
.attr("class", "line")
.attr("d", line);
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.style('stroke', function(d,i) {
return colors(i);
})
.style('fill', function(d,i) {
return colors(i);
})
.attr("class", "dot")
.attr("cx", line.x())
.attr("cy", line.y())
.attr("r", 1.5)
.on("mouseover", function(d) {
tooltip.html(d[1] + 'ºC')
.style('left', (d3.event.pageX - 35) + 'px')
.style('top', (d3.event.pageY - 30) + 'px')
.style('font-size', '15px')
});
</script>
Your dots are currently being colored by the array index of your data. Doing it this way will color your dots based on their time series (the x axis).
In order to color your circles based on temperature set the call to colors function like so. This will reference the second data point in current array iteration (the temperature).
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.style('stroke', function(d,i) {
return colors(d[1]);
})
.style('fill', function(d,i) {
return colors(d[1]);
})

How to zoom elements inside chart using d3.js

I'm studying the d3.js library and i'm following this tutorial to zoom on chart.I integrated everything and works great.
This is my final program:
<!DOCTYPE html>
<meta charset="utf-8">
<title>Zoom + Pan</title>
<style>
body {
position: relative;
width: 960px;
}
svg {
font: 10px sans-serif;
shape-rendering: crispEdges;
}
rect {
fill: #ddd;
}
.axis path,
.axis line {
fill: none;
stroke: #fff;
shape-rendering: crispEdges;
}
.dot {
}
button {
position: absolute;
right: 30px;
top: 30px;
}
</style>
<button>Reset</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
var margin = {top: 40, right: 50, bottom: 60, left: 70},
width = 1060 - margin.left - margin.right,
height = 700 - margin.top - margin.bottom;
var zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed);
var x = d3.scale.linear()
.domain([-width / 2, width / 2])
.range([0, width]);
var y = d3.scale.linear()
.domain([-height / 2, height / 2])
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height);;
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickSize(-width);
var kmeans = d3.select("body").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 + ")")
.call(zoom);
d3.tsv("test.tsv", function(error, data) {
if (error) throw error;
data.forEach(function(d) {
d.y = +d.y;
d.x = +d.x;
});
x.domain(d3.extent(data, function(d) { return d.x; })).nice();
y.domain(d3.extent(data, function(d) { return d.y; })).nice();
kmeans.append("rect")
.attr("width", width)
.attr("height", height)
kmeans.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", 500)
.attr("y", 50)
.style("text-anchor", "end")
.text("1° Principal Component");
kmeans.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("x", -200)
.attr("y", -50)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("2° Principal Component");
var dot = kmeans.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); })
.style("fill", function(d) { return color(d.cluster); });
var legend = kmeans.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(-100," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
d3.select("button").on("click", reset);
function zoomed() {
kmeans.select(".x.axis").call(xAxis);
kmeans.select(".y.axis").call(yAxis);
}
function reset() {
d3.transition().duration(750).tween("zoom", function() {
var ix = d3.interpolate(x.domain(), [-width / 2, width / 2]),
iy = d3.interpolate(y.domain(), [-height / 2, height / 2]);
return function(t) {
zoom.x(x.domain(ix(t))).y(y.domain(iy(t)));
zoomed();
};
});
}
</script>
this is test.tsv:
x y cluster
-1.0403321821456555 -0.9975352942962847 1 Cluster
-1.0404728255519613 -1.0021499065423058 1 Cluster
-1.0405312135780753 -1.0036348433263207 1 Cluster
-1.0405417259454817 -0.9883123582794969 1 Cluster
-1.0406344016908704 -0.9988259809896288 1 Cluster
-1.0406850822323188 -1.004030268612692 1 Cluster
-1.0406958447337742 -1.0065636473623911 1 Cluster
-1.0408667295862442 -1.0046081788513885 1 Cluster
-1.0408845367165218 -0.995137367062602 1 Cluster
-1.040932294864444 -0.991519347648691 1 Cluster
-1.040976952803462 -0.9833995692226501 1 Cluster
-1.0409896369345166 -0.9951495809699621 1 Cluster
-1.0410051379794218 -0.99448305469843 1 Cluster
-1.0410265061033306 -0.9951333768928067 1 Cluster
-1.0410330574179099 -0.9949308462686461 1 Cluster
-1.0410357249485886 -1.0053243527321372 1 Cluster
-1.0410491702402065 -1.006726904241483 1 Cluster
-1.041049812593761 -0.9865506278675225 1 Cluster
If someone run this code, It shows the plot, but the elments inside it remains unzoomable. Can someone tell me what's is wrong?
In your zoomed() function you only update both axis. You aren't updating the svg elements inside your graph (the svg-circle elements in your case).
If you add the following to your zoomed() function it should work:
kmeans.selectAll(".dot")
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); })
It's maybe worth mentioning that this will obviously not enlarge your circles. This will just adapt the domain of your graph and reposition your element accordingly.
If you are looking for a genuine zoom effect I'd suggest you use something like:
kmeans.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");

Categories

Resources