I am fairly new to javascript and D3, I am trying to create a tooltip that displays a vertical line and circles on that line along with the value of data in each line. any help would be greatly appreciated ...
here is what I have got so far
I am fairly new to javascript and D3, I am trying to create a tooltip that displays a vertical line and circles on that line along with the value of data in each line. any help would be greatly appreciated ...
here is what I have got so far
function init() {
var formatDate, dataset, header, xScale, yScale, xAxis, yAxis, svg, coalConsLine,
gasConsLine, hydroConsLine, oilConsLine, solarConsLine, windConsLine, toolTip, lineData;
//dimensions
const margin = { top: 30, right: 40, bottom: 70, left: 20 };
const width = 650 - margin.right - margin.left;
const height = 530 - margin.top - margin.bottom;
//format date
formatDate = d3.timeFormat("%Y");
//import data from csv file
d3.csv("Australian_Energy_Production_and_Consumption.csv", function (d) {
return {
//to create new Date object for each year
date: new Date(d.year),
//coal consumption
coalCons: parseFloat(d.coal_consumption),
//coal production
coalProd: parseFloat(d.coal_production),
//electricity generation
elecPrdo: parseFloat(d.electricity_generation),
//gas consumption
gasCons: parseFloat(d.gas_consumption),
//gas production
gasProd: parseFloat(d.gas_production),
//hydro consumption
hydroCons: parseFloat(d.hydro_consumption),
//oil consumption
oilCons: parseFloat(d.oil_consumption),
//oil production
oilProd: parseFloat(d.oil_production),
//solar energy consumption
solarCons: parseFloat(d.solar_consumption),
//wind energy consumption
windCons: parseFloat(d.wind_consumption)
}
}).then(function (data) {
dataset = data;
MultiLineChart(dataset);
});
function MultiLineChart() {
//chart base
svg = d3.select("body")
.append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append('g')
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//append header group
header = svg.append('g')
.attr("class", "chartHeader")
.attr("class", "mainHeader")
.attr("transform", "translate(23," + -margin.top * 0.5 + ")")
.append("text");
//append text to header group
header.append("tspan")
.text("Australian Energy Consumption by Energy Source");
header.append("tspan")
.attr("class", "subHeading")
.attr("x", 0)
.attr("y", 15)
.text("Measured in Terawatt hour (TWh) from 2000-2019")
xScale = d3.scaleTime()
.domain([
d3.min(dataset, function (d) { return d.date; }),
d3.max(dataset, function (d) { return d.date; })])
.nice() //makes scale end in round number, in this case will end in 2020 instead of 2019
.range([0, width]);
xAxis = d3.axisBottom()
.ticks(d3.timeYear.every(1))
.scale(xScale);
yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function (d) {
return Math.max(d.coalCons, d.gasCons, d.hydroCons, d.oilCons, d.solarCons, d.windCons)
})])
.nice()
.range([height, 0]);
yAxis = d3.axisLeft()
.ticks(10)
.scale(yScale);
svg.append("g")
.attr("class", "axis")
.attr("class", "Xaxis")
.attr("transform", "translate(" + margin.left + "," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + margin.left + ", 0)")
.call(yAxis);
//coal energy consumption line genetator
coalConsLine = d3.line()
.x(function (d) { return xScale(d.date); })
.y(function (d) { return yScale(d.coalCons); });
//Creating the coal energy consumption line
svg.append("path")
.datum(dataset)
.attr("class", "coalConsLine")
.attr("class", "consLines")
.attr("transform", "translate(" + margin.left + ", 0)")
.attr("d", coalConsLine)
.style("stroke", "#010E13");
//gas energy consumption line genetator
gasConsLine = d3.line()
.x(function (d) { return xScale(d.date); })
.y(function (d) { return yScale(d.gasCons); });
//Creating the gas energy consumption line
svg.append("path")
.datum(dataset)
.attr("class", "gasConsLine")
.attr("class", "consLines")
.attr("transform", "translate(" + margin.left + ", 0)")
.attr("d", gasConsLine)
.style("stroke", "#ffa600");
toolTip = d3.selectAll(".toolTip");
//define lineData
lineData = d3.select(this).data()[0];
function mouseover() {
toolTip
.style('left', d3.event.clientX + 10 + 'px')
.style('top', d3.event.clientY + 5 + 'px')
.style('opacity', 0.97)
//I don't know how to get the data value
toolTip.select('.year').html("year " + lineData.date);
}
function mousemove() {
toolTip
.style('left', d3.event.clientX + 13 + 'px')
.style('top', d3.event.clientY + 5 + 'px')
}
function mouseout() {
toolTip.style('opacity', 0)
}
d3.selectAll(".consLines")
.on("mouseover", mouseover)
.on('mousemove', mousemove)
.on('mouseout', mouseout);
}
}
window.onload = init;
Related
I am drawing charts with d3 4.2.2 in my Angular2 project. I created a multi series line chart and added zoom and drag properties. Now the chart is zooming on mouse scroll event but it zoom only X-axis and Y-axis. And it can be dragged only X-axis & Y-axis but chart cannot be dragged. When I do zooming or dragging those events are applying only to the two axis es but not for the chart. Following is what I am doing with my code.
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 80,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var zoom = d3.zoom()
.scaleExtent([1, 5])
.translateExtent([[0, -100], [width + 90, height + 100]])
.on("zoom", zoomed);
var svg = d3.select(this.htmlElement).append("svg")
.attr("class", "line-graph")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("pointer-events", "all")
.call(zoom);
var view = svg.append("rect")
.attr("class", "view")
.attr("x", 0.5)
.attr("y", 0.5)
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("fill", "#EEEEEE")
.style("stroke", "#000")
.style("stroke-width", "0px");
// parse the date / time
var parseDate = d3.timeParse("%Y-%m-%d");
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var z = d3.scaleOrdinal(d3.schemeCategory10);
// define the line
var line = d3.line()
.x( (d) => {
return x(d.date);
})
.y( (d) => {
return y(d.lookbookcount);
});
z.domain(d3.keys(data[0]).filter(function (key) {
return key !== "date";
}));
// format the data
data.forEach( (d)=> {
d.date = parseDate(d.date);
});
var lookBookData = z.domain().map(function (name) {
return {
name: name,
values: data.map( (d) => {
return {date: d.date, lookbookcount: d[name], name: name};
})
};
});
x.domain(d3.extent(data, (d) => {
return d.date;
}));
y.domain([
d3.min([0]),
d3.max(lookBookData, (c) => {
return d3.max(c.values,
(d) => {
return d.lookbookcount;
});
})
]);
z.domain(lookBookData.map( (c) => {
return c.name;
}));
var xAxis = d3.axisBottom(x)
.ticks(d3.timeDay.every(1))
.tickFormat(d3.timeFormat("%d/%m"));
var yAxis = d3.axisLeft(y)
.ticks(10);
// Add the X Axis
var gX = svg.append("g")
.style("font", "14px open-sans")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
var gY = svg.append("g")
.style("font", "14px open-sans")
.attr("class", "axis axis--x")
.call(yAxis)
.style("cursor", "ns-resize");
// Add Axis labels
svg.append("text")
.style("font", "14px open-sans")
.attr("text-anchor", "end")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.text("Sales / Searches");
svg.append("text")
.style("font", "14px open-sans")
.attr("text-anchor", "end")
.attr("dx", ".71em")
.attr("transform", "translate(" + width + "," + (height +
(margin.bottom)) + ")")
.text("Departure Date");
var chartdata = svg.selectAll(".chartdata")
.data(lookBookData)
.enter().append("g")
.attr("class", "chartdata");
chartdata.append("path")
.classed("line", true)
.attr("class", "line")
.attr("d", function (d) {
return line(d.values);
})
.style("fill", "none")
.style("stroke", function (d) {
return z(d.name);
})
.style("stroke-width", "2px");
chartdata.append("text")
.datum(function (d) {
return {
name: d.name, value: d.values[d.values.length - 1]
};
})
.attr("transform", function (d) {
return "translate(" +
x(d.value.date) + "," + y(d.value.lookbookcount) + ")";
})
.attr("x", 3)
.attr("dy", "0.35em")
.style("font", "14px open-sans")
.text(function (d) {
return d.name;
});
// add the dots with tooltips
chartdata.selectAll(".circle")
.data(function (d) {
return d.values;
})
.enter().append("circle")
.attr("class", "circle")
.attr("r", 4)
.attr("cx", function (d) {
console.log(d);
return x(d.date);
})
.attr("cy", function (d) {
return y(d.lookbookcount);
})
.style("fill", function (d) { // Add the colours dynamically
return z(d.name);
});
function zoomed() {
view.attr("transform", d3.event.transform);
gX.call(xAxis.scale(d3.event.transform.rescaleX(x)));
}
function resetted() {
svg.transition()
.duration(750)
.call(zoom.transform, d3.zoomIdentity);
}
Any suggestions would be highly appreciated.
Thank you
I want to plot multiple lines and scatter plot on the same d3 chart.And I also define a mouse over function to calculate the distance between the scatter points and the line. Here is my js code:
import measurement from '../datasets/measurement';
// Parse the date / time
var parseDate = d3.time.format("%e/%_m/%Y %H");
// Get the data
d3.csv("../datasets/Book1.csv", function(error, data) {
data.forEach(function (d) {
d.date = parseDate.parse(d.dateHour);
d.estPressure = +d.x_inf;
d.lowPressure = +d.m1std;
d.upPressure = +d.p1std;
});
console.log(data);
// Set the dimensions of the canvas / graph
var margin = {top: 20, right: 50, bottom: 30, left: 66},
body_width = parseInt(d3.select('body').style('width').replace('px','')),
width = body_width - margin.left - margin.right,
height = 1000 - margin.top - margin.bottom;
// Adds the svg canvas
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 + ")");
// Set the ranges
var x = d3.time.scale()
.domain([parseDate.parse("1/5/2016 00"), parseDate.parse("14/5/2016 23")])
// .domain(data.date])
.nice(d3.time.week)
/*.domain(data.map(function (d) {
return d.date;
}))*/
.range([0, width]);
//.rangeRoundBands([0, width], 0.1);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(d3.time.format('%B %e %H:00'));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("text")
.attr("x", 1780)
.attr("y", 940)// text label for the x axis
.style("text-anchor", "end")
.text("Time");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
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("pressure");
y.domain([0, d3.max(data, function (d) {
return d.upPressure;
})]);
var line = d3.svg.line()
.x(function (d) {
return x(d.date);
})
.y(function (d) {
return y(d.estPressure);
});
// Draw line.
var linegraph = svg.selectAll("path.line").data([data], function (d) {
return d.date;
});
linegraph.attr('d', line).style("opacity", 1.0);
linegraph.enter().append("path")
.attr("class", "line")
.attr("d", line);
});
var data1 = measurement.map(function (d) {
Object.keys(d).forEach(function (key) {
d[key] = +d[key];
});
return d;
});
console.log(data1);
// Add the scatterplot
svg.selectAll(".dot")
.data(data1)
.enter().append("circle")
.attr("r", 4)
.attr("cx", function (d) {
return x(d.t);
})
.attr("cy", function (d) {
return y(d.est);
})
.on("mouseover", function (d) { //hover event
tooltip.transition()
.duration(100)
.style("opacity", .9)
.style("left", (d3.event.pageX + 20) + "px")
.style("top", (d3.event.pageY - 30) + "px");
var dist = 0, lowerbound;
data.forEach(function (n) {
if (n.t === d.t) {
dist = d.est - n.pressure ;
if (dist < 0) dist = dist * -1;
}
else if (n.time < d.t) { // linear interpolation for the t
lowerbound = n;
}
});
tooltip.html("<h1>" + "X: " + d.t + " Y: " + d.x + " distance:" + dist.toFixed(3) + "</h1>");
})
.on("mouseout", function (d) {
tooltip.transition()
.duration(200)
.style("opacity", 0);
});
And my csv data for the line chart is like this:
tHour,x_inf,p1std,m1std,dateHour
1,10,10.3,9.2,1/5/2016 00
2,12,16.8,7.2,1/5/2016 01
3,14,21.2,6.8,1/5/2016 02
4,15,19.8,10.2,1/5/2016 03
5,14.5,16.9,12.1,1/5/2016 04
6,18,22.96,13.04,1/5/2016 05
My jason data for the scatter points are like(measurement):
{
"t": 1,
"est": 1
},
{
"t": 3,
"est": 12
},
{
"t": 5,
"est": 14
},
{
Could anyone help me about the code? I am new to d3...And I just can plot only one line here using the dateHour as x and x_inf as y in the csv data. I want to use dateHour data as x and plot three lines using x_inf,p1std,m1std values. It would be so nice if you could also help me with the scatter points.
I'm learning d3js using various examples found online.
I've been trying to plot a chart with dual Y axis and an X-axis. The Y axis on the left side would plot a bar chart against the X-axis and the Y-axis on the right side would plot a line chart against X-axis. The Bar graph plots as exactly as required but the line graph does not. The X-axis is date (2015-10-15 04:10). Following this example.
The code I wrote
var margin = {top: 50, right: 50, bottom: 100, left: 50},
width = 900 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%m/%d/%Y %H:%M:%S").parse;
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var yTxnVol = d3.scale.linear().range([height, 0]);
var yResTime = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(yTxnVol)
.orient("left")
var yAxis2 = d3.svg.axis()
.scale(yResTime)
.orient("right")
.ticks(10);
var svg = d3.selectAll("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 + ")");
d3.csv("../res/data.csv", function(error, data) {
data.forEach(function(d) {
d.AVRG_RESP_TIME = +d.AVRG_RESP_TIME;
d.TXN_VOL = +d.TXN_VOL;
});
x.domain(data.map(function(d) { return d.TYM; }));
yTxnVol.domain([0, d3.max(data, function(d) { return d.TXN_VOL+50; })]);
yResTime.domain([0, d3.max(data, function(d) { return d.AVRG_RESP_TIME+50; })]);
var minDate = d3.min(data, function(d){return d.TYM});
var maxDate = d3.max(data, function(d){ return d.TYM});
var xScale = d3.time.scale().range([0,width]);//.domain([minDate, maxDate]);
xScale.domain(d3.extent(data, function(d) { return new Date(d.TYM); }));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" );
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
svg.append("g")
.attr("class","y axis")
.attr("transform","translate("+width+ ", 0)")
.call(yAxis2)
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.attr("class", "yhover")
.attr("x", function(d) { return x(d.TYM); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return yTxnVol(d.TXN_VOL); })
.attr("height", function(d) { return height - yTxnVol(d.TXN_VOL); })
var line = d3.svg.line()
.x(function(d) { return xScale(new Date(d.TYM));})
.y(function(d) { return d.AVRG_RESP_TIME; });
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
});
The Output Trying to make this to a meaningful line graph. Got NaN error while formatting the dates.
Could someone help me to make this a proper line graph ?
The csv data sample
TYM, AVRG_RESP_TIME, TXN_VOL
2015-10-15 04:00:00, 12, 170
2015-10-15 04:10:00, 18, 220
2015-10-15 04:20:00, 28, 251
2015-10-15 05:00:00, 19, 100
First, fix your csv file. It is improperly formatted and should not have spaces after the comma.
Second, You are trying to mix an ordinal scale and a time scale for you xAxis. This isn't going to work. For your use case, just stick with time.
Here's a reworking of your code with explanatory comments:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>
<body>
<script>
var margin = {
top: 50,
right: 50,
bottom: 100,
left: 50
},
width = 900 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
// x scale should be time and only time
var x = d3.time.scale().range([0, width]);
var yTxnVol = d3.scale.linear().range([height, 0]);
var yResTime = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(yTxnVol)
.orient("left")
var yAxis2 = d3.svg.axis()
.scale(yResTime)
.orient("right")
.ticks(10);
var svg = d3.selectAll("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 + ")");
//d3.csv("data.csv", function(error, data) {
var data = [{"TYM":"2015-10-15 04:00:00","AVRG_RESP_TIME":"12","TXN_VOL":"170"},{"TYM":"2015-10-15 04:10:00","AVRG_RESP_TIME":"18","TXN_VOL":"220"},{"TYM":"2015-10-15 04:20:00","AVRG_RESP_TIME":"28","TXN_VOL":"251"},{"TYM":"2015-10-15 05:00:00","AVRG_RESP_TIME":"19","TXN_VOL":"100"}];
// just make TYM a date and keep it as a date
data.forEach(function(d) {
d.TYM = parseDate(d.TYM);
d.AVRG_RESP_TIME = +d.AVRG_RESP_TIME;
d.TXN_VOL = +d.TXN_VOL;
});
// get our min and max date in milliseconds
// set a padding around our domain of 15%
var minDate = d3.min(data, function(d){
return d.TYM;
}).getTime();
var maxDate = d3.max(data, function(d){
return d.TYM;
}).getTime();
var padDate = (maxDate - minDate) * .15;
x.domain([new Date(minDate - padDate), new Date(maxDate + padDate)]);
yTxnVol.domain([0, d3.max(data, function(d) {
return d.TXN_VOL + 50;
})]);
yResTime.domain([0, d3.max(data, function(d) {
return d.AVRG_RESP_TIME + 50;
})]);
// set an intelligent bar width
var barWidth = (width / x.ticks().length) - 20;
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ", 0)")
.call(yAxis2)
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.attr("class", "yhover")
.attr("x", function(d) {
// center bar on time
return x(d.TYM) - (barWidth / 2);
})
.attr("width", barWidth)
.attr("y", function(d) {
return yTxnVol(d.TXN_VOL);
})
.attr("height", function(d) {
return height - yTxnVol(d.TXN_VOL);
})
.style("fill","orange");
var line = d3.svg.line()
.x(function(d) {
return x(d.TYM);
})
.y(function(d) {
return d.AVRG_RESP_TIME;
});
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line)
.style("fill","none")
.style("stroke","steelblue")
.style("stoke-width","3px");
// });
</script>
</body>
</html>
The issue with the line graph filling with black was due to improper css. The new css property.
.line {
fill: none;
stroke: darkgreen;
stroke-width: 2.5px;
}
For the dates I formatted it to (%Y-%m-%d %H:%M) format and it worked.
I have a linear y scale with a time series x scale. I want to put an overlay that follows the x/y value (similar to http://bl.ocks.org/mbostock/3902569).
The issue is that I'm not able to transform to the proper x scale value; for example when I mouseover my chart it outputs (this data is correct):
{ y: 0.05, x: "2015-07-26 15:08:47" }
{ y: 0.05, x: "2015-07-26 15:08:47" }
{ y: 0.05, x: "2015-07-26 15:08:47" }
Now I want to use this data to draw a point at that location; the issue is that I cannot replicate the above bl.locks.org example, and the transform isn't able to use the x position as a date; so how can I transform that x date to the point on the chart?
My mousemove is below:
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");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var varea = d3.svg.area()
.defined(function(d) { return d.y != null; })
.x(function(d) { return x(parseDate(d.x)); })
.y0(height)
.y1(function(d) { return y(d.y); });
var svg = d3.select(".swatch").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(d3.extent(data, function(d) { return parseDate(d.x); }));
y.domain([0, d3.max(data, function(d) {
if (d.y >= 1) {
return d.y
}
return 1;
})]);
svg.append("path")
.attr("class", "area")
.attr("d", varea(data));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var focus = svg.append("g")
.attr("class", "focus")
.attr("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() {
focus.style("display", null);
})
.on("mouseout", function() {
focus.style("display", "none");
})
.on("mousemove", function() {
var x0 = x.invert(d3.mouse(this)[0]);
var bisect = d3.bisector(function(d) { return parseDate(d.x); }).right;
var item = data[bisect(data, x0)];
focus.attr("transform", "translate(" + x(parseDate(item.x)) + "," + y(item.y) + ")");
focus.select("text").text(item.y);
console.log(x(parseDate(item.x)));
console.log(y(item.y));
});
This code produces errors like the following in the console:
Unexpected value translate(NaN,120) parsing transform attribute.
So, the question is how do I convert the date to a proper coordinate?
Alright, so there were a couple of problems with my code.
I wasn't parsing the x value as a date; so I started parsing it with parseDate (see sample code) and then passed it to the x scale; this allowed me to get proper location on the chart.
The second issue was that display wasn't be set properly (setting it to null in Firefox wasn't allowing it to appear). So I changed that to display: inline; and it started showing up on the chart.
I'm trying to display dates in the x axis and at the same time zoom it when you scroll.
So, I have this code:
<script type="text/javascript">
var data = [
[{'x':20111001,'y':1},{'x':20111002,'y':6},{'x':20111003,'y':11},{'x':20111004,'y':1},{'x':20111005,'y':2},{'x':20111006,'y':12},{'x':20111007,'y':2},{'x':20111008,'y':3},{'x':20111009,'y':13},{'x':20111010,'y':3}],
[{'x':20111001,'y':2},{'x':20111002,'y':2},{'x':20111003,'y':12},{'x':20111004,'y':2},{'x':20111005,'y':3},{'x':20111006,'y':1},{'x':20111007,'y':2},{'x':20111008,'y':7},{'x':20111009,'y':2},{'x':20111010,'y':7}],
[{'x':20111001,'y':3},{'x':20111002,'y':10},{'x':20111003,'y':13},{'x':20111004,'y':3},{'x':20111005,'y':12},{'x':20111006,'y':14},{'x':20111007,'y':6},{'x':20111008,'y':1},{'x':20111009,'y':7},{'x':20111010,'y':9}],
[{'x':20111001,'y':4},{'x':20111002,'y':4},{'x':20111003,'y':14},{'x':20111004,'y':14},{'x':20111005,'y':10},{'x':20111006,'y':15},{'x':20111007,'y':3},{'x':20111008,'y':0},{'x':20111009,'y':3},{'x':20111010,'y':12}]
];
var colors = [
'steelblue',
'green',
'red',
'purple'
]
var b =[];
var parseDate = d3.time.format("%Y%m%d").parse;
data.forEach(function (d) {
f = d;
f.forEach(function(f){
b.push(parseDate(String(f.x)));
})
})
var margin = {top: 20, right: 30, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.time.scale()
.domain([d3.extent(b)])
.range([0, width]);
var y = d3.scale.linear()
.domain([-1, 16])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.tickSize(-height)
.tickPadding(10)
.tickSubdivide(true)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.tickPadding(10)
.tickSize(-width)
.tickSubdivide(true)
.orient("left");
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1, 10])
.on("zoom", zoomed);
var svg = d3.select("body").append("svg")
.call(zoom)
.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);
svg.append("g")
.attr("class", "y axis")
.append("text")
.attr("class", "axis-label")
.attr("transform", "rotate(-90)")
.attr("y", (-margin.left) + 10)
.attr("x", -height/2)
.style("text-anchor", "end")
.text("Ventas (Miles €)");
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var line = d3.svg.line()
.interpolate("linear")
.x(function(d) { return x(d.x); })
.y(function(d) { return y(d.y); });
svg.selectAll('.line')
.data(data)
.enter()
.append("path")
.attr("class", "line")
.transition()
.attr("clip-path", "url(#clip)")
.attr('stroke', function(d,i){
return colors[i%colors.length];
})
.attr("d", line);
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var points = svg.selectAll('.dots')
.data(data)
.enter()
.append("g")
.attr("class", "dots")
.attr("clip-path", "url(#clip)");
points.selectAll('.dot')
.data(function(d, index){
var a = [];
d.forEach(function(point,i){
a.push({'index': index, 'point': point});
});
return a;
})
.enter()
.append('circle')
.attr('class','dot')
.attr("r", 2.5)
.attr('fill', function(d,i){
return colors[d.index%colors.length];
})
.attr("transform", function(d) {
return "translate(" + x(d.point.x) + "," + y(d.point.y) + ")"; }
).on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(d.point.x + "K<br/>" + d.point.y)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.selectAll('path.line').attr('d', line);
points.selectAll('circle').attr("transform", function(d) {
return "translate(" + x(d.point.x) + "," + y(d.point.y) + ")"; }
);
}
</script>
I can make it with numbers but can't implement it with dates. I've checked other examples and how they make it but can't find the way to code it in my chart.
I'd like to know how to display dates on x axis.
Is your question how to make the axis dates instead of just numbers? Or is it how to make the axis pannable? If it's the first, use code like this:
var x=d3.time.scale()
.domain([minDate,maxDate])
The minDate and maxDate have to be javascript Date objects.