line chart with mouseover tooltip is not working in d3.js - javascript
I've created a line chart using this http://bl.ocks.org/d3noob/6eb506b129f585ce5c8a code example. I've managed to recreate it.
that code is
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<body>
<!-- load the d3.js library -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%d-%b-%y").parse,
formatDate = d3.time.format("%d-%b"),
bisectDate = d3.bisector(function(d) { return d.date; }).left;
// Set the ranges
// var x = d3.time.scale().range([0, width]);
var x = d3.scale.ordinal().rangePoints([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.interpolate('basis')
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
// 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 + ")");
var lineSvg = svg.append("g");
var focus = svg.append("g")
.style("display", "none");
// Get the data
var data = [
{
"date": "w1",
"close": 629.32
},
{
"date": "w2",
"close": 124.31
},
{
"date": "w3",
"close": 333.68
},
{
"date": "w4",
"close": 236.23
}
]
// data.forEach(function(d) {
// // d.date = parseDate(d.date);
// d.date = +d.date;
// d.close = +d.close;
// });
// Scale the range of the data
x.domain(data.map(function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Add the valueline path.
lineSvg.append("path")
.attr("class", "line")
.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);
// append the x line
focus.append("line")
.attr("class", "x")
.style("stroke", "blue")
.style("stroke-dasharray", "3,3")
.style("opacity", 0.5)
.attr("y1", 0)
.attr("y2", height);
// append the y line
focus.append("line")
.attr("class", "y")
.style("stroke", "blue")
.style("stroke-dasharray", "3,3")
.style("opacity", 0.5)
.attr("x1", width)
.attr("x2", width);
// append the circle at the intersection
focus.append("circle")
.attr("class", "y")
.style("fill", "none")
.style("stroke", "blue")
.attr("r", 4);
// place the value at the intersection
focus.append("text")
.attr("class", "y1")
.style("stroke", "white")
.style("stroke-width", "3.5px")
.style("opacity", 0.8)
.attr("dx", 8)
.attr("dy", "-.3em");
focus.append("text")
.attr("class", "y2")
.attr("dx", 8)
.attr("dy", "-.3em");
// place the date at the intersection
focus.append("text")
.attr("class", "y3")
.style("stroke", "white")
.style("stroke-width", "3.5px")
.style("opacity", 0.8)
.attr("dx", 8)
.attr("dy", "1em");
focus.append("text")
.attr("class", "y4")
.attr("dx", 8)
.attr("dy", "1em");
// append the rectangle to capture mouse
svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all")
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.select("circle.y")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.close) + ")");
focus.select("text.y1")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.close) + ")")
.text(d.close);
focus.select("text.y2")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.close) + ")")
.text(d.close);
focus.select("text.y3")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.close) + ")")
.text(formatDate(d.date));
focus.select("text.y4")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.close) + ")")
.text(formatDate(d.date));
focus.select(".x")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.close) + ")")
.attr("y2", height - y(d.close));
focus.select(".y")
.attr("transform",
"translate(" + width * -1 + "," +
y(d.close) + ")")
.attr("x2", width + width);
}
</script>
</body>
line is coming correctly but i m not able to set mouseover tooltip like above example..
I m facing error like invert fuction is not defined...
In the chart you linked to, he is using a time-scale for the x-axis (which has an invert-function). You are using an ordinal-scale (which do not have an invert-function).The invert-function is used to calculate the value on the x-axis for a given mouse-position.
A time-scale always has a corresponding x-value for each mouse-position (since it is continous, so no matter where your mouse is, you have a date-time for that position) while an ordinal scale does not have a corresponding x-value for all mouse-positions since it is discrete, i.e. what is the x-value when you have the mouse in-beteen for example w1 and w2?
So your solution would be to change to a time-scale (in which case you have to convert w1,w2,w3 e.t.c. to a date-time object).
Or, if you want to stick with your ordinal-scale, you have to remove the invert function. Since the invert-function is used to calculate the x-value for a given mouse-position, you have to create this logic by your self. Inspiration can be found in Inversion with ordinal scale. So replace var x0 = x.invert(d3.mouse(this)[0]) with
var xPos = d3.mouse(this)[0];
console.log("hovering at " + xPos);
var leftEdges = x.range();
var width = x.rangeBand();
var j;
for(j=0; xPos > (leftEdges[j] + width); j++) {}
//do nothing, just increment j until case fails
console.log("Clicked on " + x.domain()[j]);
var x0 = x.domain()[j];
Related
How do I plot a scatterplot with this kind of dataset?
I am a complete beginner of Javascript and D3. Currently I have been trying to create a scatterplot with x-axis showing the years and percentiles for every year and y-axis showing the values for 3 variables. But I cannot seem to get my code running. Please help. This is the excerpt of the dataset I have now: country_code,year,welfare_type,percentile,avg_welfare,pop_share,welfare_share AUS,2014,income,1,2.706183088,0.009969853,4.13E-04 AUS,2014,income,2,11.03834646,0.010027236,0.001695224 AUS,2014,income,3,15.21296516,0.009923341,0.002312137 AUS,2014,income,4,17.78666642,0.009876024,0.00269041 AUS,2014,income,5,19.65899193,0.009817937,0.002956128 AUS,2014,income,6,21.23338101,0.010270198,0.003339948 AUS,2014,income,7,22.71642933,0.010107506,0.003516624 AUS,2014,income,8,23.88424149,0.010001223,0.003658528 AUS,2014,income,9,24.95633096,0.009820398,0.003753631 AUS,2014,income,10,25.78625374,0.010083031,0.003982182 AUS,2014,income,11,26.61719414,0.00994973,0.004056163 AUS,2014,income,12,27.43463276,0.010096198,0.004242275 AUS,2014,income,13,28.31720791,0.010045165,0.004356616 AUS,2014,income,14,29.23106771,0.009896533,0.004430671 AUS,2014,income,16,30.55067193,0.009863549,0.004615256 AUS,2014,income,15,29.89843511,0.010094814,0.004622624 AUS,2014,income,17,31.20316268,0.010020247,0.004788713 AUS,2014,income,19,32.38771182,0.009888694,0.004905248 AUS,2014,income,18,31.82871304,0.010124787,0.004935677 AUS,2014,income,20,32.95847038,0.00998462,0.005040114 AUS,2014,income,21,33.6474718,0.010047902,0.00517809 AUS,2014,income,22,34.33875307,0.010052882,0.005287092 AUS,2014,income,23,35.01464846,0.0099175,0.005318556 AUS,2014,income,24,35.63748207,0.010094145,0.005509578 AUS,2014,income,26,37.03581494,0.009755934,0.005533916 AUS,2014,income,25,36.26642742,0.009996408,0.005552525 AUS,2014,income,28,38.23585461,0.009992649,0.00585185 AUS,2014,income,29,38.94099912,0.009912763,0.005912125 AUS,2014,income,27,37.61468566,0.010266587,0.005914599 AUS,2014,income,30,39.66490264,0.010092823,0.006131417 AUS,2014,income,31,40.37644593,0.009921456,0.006135434 AUS,2014,income,32,41.02135057,0.00998833,0.006275446 AUS,2014,income,34,42.01105027,0.009758772,0.006279145 AUS,2014,income,33,41.62407432,0.010037465,0.006398975 AUS,2014,income,36,43.03352375,0.010044596,0.006620354 AUS,2014,income,37,43.59007717,0.009950045,0.00664285 AUS,2014,income,35,42.4723306,0.010237364,0.006659414 AUS,2014,income,38,44.05401838,0.009974684,0.006730177 AUS,2014,income,39,44.59078719,0.010080713,0.006884592 AUS,2014,income,40,45.22011959,0.010009614,0.006932515 AUS,2014,income,41,45.78335857,0.009937155,0.006968054 AUS,2014,income,42,46.49121536,0.010059652,0.007163011 AUS,2014,income,44,47.72893726,0.009855791,0.007204686 AUS,2014,income,43,47.10222632,0.010004851,0.007217617 AUS,2014,income,46,48.96673209,0.009786594,0.007339635 AUS,2014,income,45,48.31298287,0.010139416,0.007502717 AUS,2014,income,47,49.62708527,0.010060983,0.007647174 AUS,2014,income,49,51.09694646,0.009849214,0.00770794 AUS,2014,income,48,50.38862979,0.010149339,0.007832711 AUS,2014,income,50,51.83564211,0.010094099,0.008013788 AUS,2014,income,51,52.57598103,0.01003079,0.008077265 AUS,2014,income,52,53.44639201,0.010033813,0.00821346 AUS,2014,income,53,54.36172111,0.009865484,0.008213976 AUS,2014,income,54,55.3113642,0.01011584,0.008569552 AUS,2014,income,55,56.25654416,0.009960817,0.008582421 AUS,2014,income,56,57.0291785,0.009991576,0.008727159 AUS,2014,income,57,57.94137541,0.009839134,0.008731472 AUS,2014,income,58,58.59715086,0.009916506,0.008899733 AUS,2014,income,60,60.15320318,0.010046913,0.00925621 AUS,2014,income,59,59.28244241,0.01025988,0.009315586 AUS,2014,income,61,61.24756855,0.009985114,0.009366636 AUS,2014,income,62,62.45605758,0.010001891,0.0095675 AUS,2014,income,63,63.53518536,0.010014243,0.009744829 AUS,2014,income,64,64.52243794,0.00991656,0.009799718 AUS,2014,income,66,66.6700305,0.009775673,0.009982036 AUS,2014,income,65,65.58589209,0.010078047,0.010123451 AUS,2014,income,68,68.73954583,0.010002134,0.010530309 AUS,2014,income,67,67.67139554,0.010204008,0.01057591 AUS,2014,income,69,69.68166938,0.009959784,0.010629437 AUS,2014,income,70,70.78054852,0.009890164,0.01072159 AUS,2014,income,72,73.10381941,0.009986389,0.011181249 AUS,2014,income,71,71.82035176,0.010175222,0.011192657 AUS,2014,income,73,74.50528527,0.010016861,0.011430376 AUS,2014,income,74,75.81199845,0.009955876,0.011560037 AUS,2014,income,75,77.04250182,0.010042825,0.011850264 AUS,2014,income,76,78.565506,0.009955459,0.011979398 AUS,2014,income,77,80.40478014,0.009977753,0.012287298 AUS,2014,income,78,82.12333785,0.010043796,0.012632993 AUS,2014,income,79,83.79248925,0.009988891,0.012819295 AUS,2014,income,80,85.55768023,0.009991496,0.013092763 AUS,2014,income,81,87.47915,0.010038706,0.013450056 AUS,2014,income,82,89.38254022,0.009986228,0.013670864 AUS,2014,income,83,91.63481485,0.009953002,0.013968713 AUS,2014,income,84,93.91744067,0.010000544,0.01438506 AUS,2014,income,85,96.41946083,0.01005068,0.014842324 AUS,2014,income,86,99.54540544,0.009921946,0.015127246 AUS,2014,income,87,102.9654549,0.010061255,0.015866659 AUS,2014,income,88,105.971401,0.010025493,0.016271822 AUS,2014,income,89,109.1419537,0.009901563,0.016551497 AUS,2014,income,90,112.514213,0.009965222,0.017172604 AUS,2014,income,91,116.3289357,0.010076984,0.017953955 AUS,2014,income,92,120.6459775,0.01006046,0.018589704 AUS,2014,income,93,125.5685177,0.009956968,0.019149158 AUS,2014,income,94,131.9060045,0.010046029,0.020295548 AUS,2014,income,95,139.9451658,0.009996381,0.021426068 AUS,2014,income,96,148.6943539,0.009975502,0.022718048 AUS,2014,income,97,161.3097917,0.009998721,0.024702846 AUS,2014,income,98,181.7236599,0.010022054,0.027893949 AUS,2014,income,99,217.7250904,0.009993702,0.033325498 AUS,2014,income,100,419.3771126,0.010014813,0.064326418 AUS,2016,income,1,2.921344881,0.009891044,4.53E-04 AUS,2016,income,2,10.86946963,0.009887197,0.001684881 AUS,2016,income,3,14.96556705,0.010220573,0.002398038 AUS,2016,income,4,17.41174479,0.009960163,0.00271892 AUS,2016,income,5,18.84613732,0.009949316,0.002939701 AUS,2016,income,6,20.38088749,0.010060453,0.00321461 AUS,2016,income,7,21.94488945,0.009988179,0.003436429 AUS,2016,income,8,22.9706105,0.010022147,0.003609283 AUS,2016,income,10,25.00293992,0.009354153,0.003666766 AUS,2016,income,9,24.0096397,0.009995351,0.003762455 AUS,2016,income,12,26.62725434,0.009971033,0.004162499 AUS,2016,income,13,27.3528324,0.010032514,0.00430229 AUS,2016,income,11,25.76408298,0.010652475,0.004302817 AUS,2016,income,14,28.17373116,0.009973422,0.004405307 AUS,2016,income,15,29.05679359,0.00986932,0.004495961 AUS,2016,income,16,29.93744756,0.010155514,0.004766551 AUS,2016,income,17,30.59293397,0.010010156,0.004801197 AUS,2016,income,18,31.20220578,0.010001867,0.004892761 AUS,2016,income,19,31.63021913,0.009993163,0.00495556 AUS,2016,income,20,32.32867948,0.010001634,0.005069283 AUS,2016,income,21,33.06058859,0.01000566,0.005186136 AUS,2016,income,22,33.67194926,0.009929743,0.005241962 AUS,2016,income,23,34.30940692,0.010074751,0.005419199 AUS,2016,income,24,34.84748724,0.009926655,0.005423279 AUS,2016,income,25,35.29368138,0.009943476,0.005502028 AUS,2016,income,27,36.74800232,0.009728971,0.005605163 AUS,2016,income,26,35.97401424,0.010091598,0.005691627 AUS,2016,income,29,38.19577669,0.009894985,0.005925406 AUS,2016,income,28,37.45386648,0.010306717,0.006052079 AUS,2016,income,30,38.83223624,0.010107443,0.006153488 AUS,2016,income,31,39.40745425,0.009980666,0.006166312 AUS,2016,income,32,40.10945618,0.009983972,0.006278238 AUS,2016,income,33,40.78564161,0.00995818,0.006367587 AUS,2016,income,35,41.63865286,0.009996976,0.006526088 AUS,2016,income,34,41.39825541,0.010074415,0.006538671 AUS,2016,income,36,42.02093891,0.009971631,0.006569307 AUS,2016,income,37,42.62393647,0.010025866,0.006699819 AUS,2016,income,38,43.26897405,0.009984334,0.006773034 AUS,2016,income,39,43.95228489,0.009974039,0.006872902 AUS,2016,income,40,44.61490953,0.010040435,0.007022959 AUS,2016,income,41,45.37646989,0.009964403,0.007088749 AUS,2016,income,42,45.97395005,0.010033745,0.007232068 AUS,2016,income,43,46.65105029,0.009968655,0.007290975 AUS,2016,income,46,48.73932332,0.009553738,0.007300295 AUS,2016,income,44,47.42866471,0.010030614,0.007458578 AUS,2016,income,45,48.02211222,0.009979524,0.007513438 AUS,2016,income,48,50.01934665,0.009986286,0.007831224 AUS,2016,income,49,50.72917496,0.010008305,0.007959869 AUS,2016,income,50,51.46537181,0.010003591,0.008071582 AUS,2016,income,47,49.36311865,0.010466048,0.008099774 AUS,2016,income,51,52.29708356,0.009965039,0.008170414 AUS,2016,income,52,53.21992628,0.009944834,0.008297732 AUS,2016,income,53,53.94076603,0.010028668,0.008481017 AUS,2016,income,54,54.73058001,0.010073508,0.008643675 AUS,2016,income,55,55.66432548,0.009998435,0.008725626 AUS,2016,income,56,56.71593196,0.009997721,0.008889835 AUS,2016,income,58,58.50555862,0.009824501,0.009011461 AUS,2016,income,57,57.57195448,0.009994539,0.009021138 AUS,2016,income,59,59.45792769,0.010138709,0.009451049 AUS,2016,income,60,60.62677419,0.01000758,0.009512204 AUS,2016,income,61,61.80787097,0.00992854,0.009620924 AUS,2016,income,63,63.43629548,0.009874096,0.009820255 AUS,2016,income,62,62.54525396,0.010092093,0.009896081 AUS,2016,income,64,64.60173999,0.010140293,0.010270281 AUS,2016,income,65,65.60493276,0.009991716,0.010276948 AUS,2016,income,66,66.72095274,0.0100073,0.010468074 AUS,2016,income,67,67.93312637,0.009973639,0.010622405 AUS,2016,income,68,69.29769991,0.009953586,0.010813991 AUS,2016,income,69,70.61850675,0.010067056,0.011145732 AUS,2016,income,70,71.88259924,0.010003244,0.01127333 AUS,2016,income,71,73.1759581,0.009903166,0.011361353 AUS,2016,income,73,75.68829689,0.009855145,0.011694438 AUS,2016,income,72,74.49065685,0.010101602,0.01179722 AUS,2016,income,74,76.93036571,0.009955659,0.012007578 AUS,2016,income,77,81.22701085,0.009611704,0.012240199 AUS,2016,income,75,78.2816762,0.010156349,0.012464801 AUS,2016,income,76,79.70407585,0.01002164,0.012522958 AUS,2016,income,79,84.38656413,0.009776858,0.012934814 AUS,2016,income,78,82.90435259,0.010162592,0.013208984 AUS,2016,income,81,88.14204825,0.009881302,0.013654787 AUS,2016,income,80,85.99034668,0.010424978,0.014054405 AUS,2016,income,82,89.83042069,0.010017994,0.014108856 AUS,2016,income,83,91.3544176,0.010030154,0.014365632 AUS,2016,income,84,93.16756247,0.010100337,0.014753267 AUS,2016,income,85,95.15888443,0.009933997,0.014820436 AUS,2016,income,86,97.77003411,0.010059915,0.015420118 AUS,2016,income,87,100.7484106,0.009970617,0.015748813 AUS,2016,income,88,103.3231109,0.010040767,0.016264921 AUS,2016,income,89,106.4835939,0.009997772,0.016690661 AUS,2016,income,90,109.9008807,0.009943091,0.017132083 AUS,2016,income,91,113.327115,0.01006132,0.01787625 AUS,2016,income,92,117.2869678,0.009933027,0.01826497 AUS,2016,income,93,121.4394061,0.009984393,0.019009422 AUS,2016,income,94,126.5037933,0.010056994,0.019946163 AUS,2016,income,95,133.7253411,0.010013734,0.020994106 AUS,2016,income,96,142.5918642,0.009978695,0.022307768 AUS,2016,income,97,153.5144822,0.009931858,0.023903829 AUS,2016,income,98,170.2017432,0.010084885,0.026910549 AUS,2016,income,99,208.2369816,0.010000861,0.032649976 AUS,2016,income,100,360.2167398,0.010018403,0.056578312 AUS,2018,income,1,2.595366313,0.009842698,3.95E-04 AUS,2018,income,2,9.823911429,0.010133857,0.001540855 AUS,2018,income,3,14.02903825,0.010019847,0.002175663 AUS,2018,income,4,16.20475069,0.00999557,0.00250699 AUS,2018,income,5,18.10915852,0.00998426,0.002798445 AUS,2018,income,6,19.9508763,0.00993849,0.003068916 AUS,2018,income,7,21.28037443,0.009700865,0.003195158 AUS,2018,income,8,22.46745331,0.010256684,0.003566674 AUS,2018,income,9,23.58626711,0.010043957,0.003666627 AUS,2018,income,10,24.56020059,0.009778468,0.00371711 AUS,2018,income,11,25.42979959,0.010202929,0.004015785 AUS,2018,income,12,26.33331407,0.010042599,0.004093118 AUS,2018,income,13,27.40014618,0.010006882,0.004243794 AUS,2018,income,14,28.52270694,0.009951873,0.004393375 AUS,2018,income,15,29.52728239,0.010003639,0.004571767 AUS,2018,income,16,30.26886102,0.009941065,0.004657272 AUS,2018,income,17,31.05298971,0.010123957,0.004865824 AUS,2018,income,18,31.98053166,0.010029435,0.004964377 AUS,2018,income,20,33.22802717,0.009797099,0.00503854 AUS,2018,income,19,32.66549084,0.009992269,0.005051914 AUS,2018,income,21,33.63693313,0.010003789,0.005208151 AUS,2018,income,25,36.01406074,0.009539114,0.005317198 AUS,2018,income,22,34.17025041,0.010130968,0.005357988 AUS,2018,income,23,34.82676969,0.010063973,0.00542482 AUS,2018,income,24,35.36869964,0.010013115,0.005481393 AUS,2018,income,27,37.20731631,0.009821302,0.005655879 AUS,2018,income,33,40.87633985,0.009210976,0.005827474 AUS,2018,income,26,36.50531459,0.01045545,0.005907469 AUS,2018,income,28,37.85771532,0.010182103,0.005966155 AUS,2018,income,29,38.61389827,0.010002608,0.00597805 AUS,2018,income,30,39.23941491,0.009962674,0.006050637 AUS,2018,income,31,39.93717676,0.010022552,0.006195243 AUS,2018,income,32,40.47103984,0.009980693,0.006251838 AUS,2018,income,36,42.40615011,0.009803519,0.006434481 AUS,2018,income,35,41.79732628,0.010157682,0.006571216 AUS,2018,income,39,44.29336043,0.009680314,0.006636372 AUS,2018,income,38,43.63415757,0.010038815,0.006779719 AUS,2018,income,37,43.06505422,0.010175109,0.00678214 AUS,2018,income,34,41.19537868,0.010642366,0.006785617 AUS,2018,income,41,45.31986066,0.009964569,0.006989558 AUS,2018,income,40,44.78770392,0.010220832,0.007085128 AUS,2018,income,42,45.98918996,0.010131453,0.007211575 AUS,2018,income,43,46.75184156,0.009979741,0.007221388 AUS,2018,income,44,47.49359156,0.009980116,0.007336236 AUS,2018,income,45,48.33259569,0.010048654,0.007517106 AUS,2018,income,46,49.07601632,0.009919118,0.007534337 AUS,2018,income,47,49.90985642,0.0100312,0.007748932 AUS,2018,income,48,50.82979576,0.010008184,0.007873654 AUS,2018,income,49,51.65939593,0.009968356,0.007970316 AUS,2018,income,50,52.49251803,0.009898442,0.008042053 AUS,2018,income,52,53.87597193,0.0099824,0.008324013 AUS,2018,income,51,53.27500401,0.010125596,0.008349236 AUS,2018,income,53,54.62220616,0.009877231,0.008350397 AUS,2018,income,54,55.47221646,0.009776907,0.008394207 AUS,2018,income,55,56.23253556,0.010238282,0.008910815 AUS,2018,income,56,57.24371642,0.010085894,0.008936035 AUS,2018,income,58,59.10520774,0.009834502,0.008996649 AUS,2018,income,57,58.16688376,0.010051726,0.009049385 AUS,2018,income,60,60.91533476,0.009875512,0.009310841 AUS,2018,income,59,59.90437715,0.010183559,0.009441931 AUS,2018,income,61,61.75432927,0.009958307,0.009518217 AUS,2018,income,62,62.61595691,0.010139702,0.009826817 AUS,2018,income,63,63.64261438,0.010040373,0.009890097 AUS,2018,income,64,64.68995889,0.00999147,0.01000389 AUS,2018,income,65,65.87401702,0.009953768,0.010148557 AUS,2018,income,68,68.91650916,0.009713594,0.0103611 AUS,2018,income,66,66.8617044,0.01005883,0.010409445 AUS,2018,income,67,67.79991077,0.009982134,0.010475027 AUS,2018,income,70,70.96026521,0.009908804,0.010882762 AUS,2018,income,69,70.000275,0.010239873,0.011094225 AUS,2018,income,71,72.26105558,0.010004988,0.011189831 AUS,2018,income,72,73.60416061,0.010107856,0.011515003 AUS,2018,income,73,74.84108522,0.010028489,0.011616578 AUS,2018,income,74,76.30553539,0.009972862,0.011778189 AUS,2018,income,75,77.63277599,0.009953914,0.011960288 AUS,2018,income,76,78.97379055,0.010069723,0.012308445 AUS,2018,income,77,80.61337965,0.00997618,0.012447268 AUS,2018,income,78,82.35020384,0.010030576,0.012784779 AUS,2018,income,79,83.8521037,0.009943725,0.012905229 AUS,2018,income,80,85.3092945,0.010001952,0.013206379 AUS,2018,income,81,86.82983593,0.009983915,0.013417528 AUS,2018,income,82,88.95395683,0.009973547,0.013731487 AUS,2018,income,83,90.96324283,0.009967333,0.014032905 AUS,2018,income,84,93.16888148,0.010097804,0.01456131 I want the year and percentile attributes on the x-axis and divide the y-axis into three sections: avg_welfare, welfare_share and pop_share. This is the current code I have, but nothing is showing on my browser. What is wrong with the code? <!DOCTYPE html> <html lang="en"> <body> <svg width="1000" height="1000"></svg> <script src="https://d3js.org/d3.v4.js" charset="utf-8"> var margin = {top:100, right:80, bottom:80, left:80}; //Setting attributes of SVG var svg = d3.select("body") .append("svg") //Setting attribute width and height as numbers instead of strings var width = parseInt(svg.attr('width')); var height = parseInt(svg.attr("height")); svg.attr("width", width + margin.left + margin.right); svg.attr("height", height + margin.top + margin.bottom); //Setting attributes of x-axis var xaxis = d3.append("g") .attr("transform", "translate(0, " + height + ")") .scaleBand() //Setting attributes of y-axis var yaxis = d3.append("g") .scaleLinear() //Extracting data d3.csv("data/programmingassignment1data.csv", function(error, data){ if (error) throw error; data.forEach(function(d){ d.year = +d.year d.percentile = +d.percentile d.avg_welfare = +d.avg_welfare d.pop_share = +d.pop_share d.welfare_share = +d.welfare_share }) //Drawing x-axis var x1 = xaxis.domain(data.map(function(d) {return d.year})) .range([margin.left, width]).padding(0.4) .call(d3.axisBottom(x1)) var x2 = xaxis.domain(data.map(function(d) {return d.percentile})) .range([margin.left, width/5]).padding(0.4) .call(d3.axisBottom(x2)) var x3 = xaxis.domain(data.map(function(d) {return d.percentile})) .range([width/5, width*2/5]).padding(0.4) .call(d3.axisBottom(x3)) var x4 = xaxis.domain(data.map(function(d) {return d.percentile})) .range([width*2/5, width*3/5]).padding(0.4) .call(d3.axisBottom(x4)) var x5 = xaxis.domain(data.map(function(d) {return d.percentile})) .range([width*3/5, width*4/5]).padding(0.4) .call(d3.axisBottom(x5)) var x6 = xaxis.domain(data.map(function(d) {return d.percentile})) .range([width*4/5, width]).padding(0.4) .call(d3.axisBottom(x6)) //Drawing y-axis var y1 = yaxis.domain([d3.max(data, function(d) {return d.avg_welfare}), 0]) .range([height, height/3]).padding(0.4) .call(d3.axisLeft(y1)) var y2 = yaxis.domain([d3.max(data, function(d) {return d.welfare_share}), 0]) .range([height/3, height*2/3]).padding(0.4) .call(d3.axisLeft(y2)) var y3 = yaxis.domain([d3.max(data, function(d) {return d.pop_share}), 0]) .range([height*2/3, 0]).padding(0.4) .call(d3.axisLeft(y3)) //Setting scatterplot attributes var g = svg.append("g") .selectAll("dot") .data(data) .enter() .append("circle") //Plotting scatterplots var g1 = g.attr("cx", function(d) {return x1(d.year); }) .attr("cy", function(d) {return y1(d.avg_welfare); }) .attr("r", 5) .style("fill", "green") var g2 = g.attr("cx", function(d) {return x1(d.year); }) .attr("cy", function(d) {return y2(d.welfare_share); }) .attr("r", 5) .style("fill", "blue") var g3 = g.attr("cx", function(d) {return x1(d.year); }) .attr("cy", function(d) {return y3(d.pop_share); }) .attr("r", 5) .style("fill", "yellow") //Adding chart title svg.append("text") .attr("transform", "translate(300,0)") .attr("x", 50) .attr("y", 50) .attr("font-size", "40px") .text("Distribution of wealth from 2014-2018"); //Adding data and axis labels var gxLabels = svg.append("g") .attr("transform", "translate(0, " + (height + margin.top + 40) + ")") .append("text") .attr("y", 20) .attr("x", margin.left + width/2) .attr("text-anchor", "end") .attr("stroke", "black") .text("Year"); var gyLabels = svg.append("g") .append("text") .attr("transform", "rotate(-90)") .attr("y", 30) .attr("dy", "-5.1em") .attr("text-anchor", "end") .attr("stroke", "black"); gyLabels.attr('transform', 'translate(' + margin.left + ', ' + (margin.top + 0 * height / 3) + ')') .text("Average Wealth"); gyLabels.attr('transform', 'translate(' + margin.left + ', ' + (margin.top + 1 * height / 3) + ')') .text("Share of Wealth"); gyLabels.attr('transform', 'translate(' + margin.left + ', ' + (margin.top + 2 * height / 3) + ')') .text("Population Share") }); </script> </body>
Here is a working version that produces a stacked scatter plot. <!DOCTYPE html> <html lang="en"> <body> <!-- CORRECTION: you cannot place your SVG inside the script tag --> <svg width="1000" height="1000"></svg> <script src="https://d3js.org/d3.v4.js" charset="utf-8"> </script> <script> // CORRECTION: Added more margin to fit all axes var margin = {top:100, right:30, bottom:80, left:80} var svg = d3.select("svg") // CORRECTION: you were trying to access width before setting it. Attributes come as strings - convert to number var width = parseInt(svg.attr('width')); svg.attr("width", width + margin.left + margin.right); // CORRECTION: also add height margin var height = parseInt(svg.attr("height")); svg.attr('height', height + margin.top + margin.bottom); var g =svg.append("g") d3.csv("Data/programmingassignment1data.csv", function(error, data){ if (error) throw error; data.forEach(function(d){ d.year = +d.year d.percentile = +d.percentile d.avg_welfare = +d.avg_welfare d.pop_share = +d.pop_share d.welfare_share = +d.welfare_share }); var xAxis1 = d3.scaleBand() .domain(data.map(function(d) {return d.year})) .range([margin.left, width]).padding(0.4); var xAxis2 = d3.scaleBand() .domain(data.map(function(d) {return d.percentile})) // CORRECTION: this need to be the same as the other x-Axis. Range is the area of the viewport .range([margin.left, width]).padding(0.4); var yAxis1 = d3.scaleLinear() .domain([0, d3.max(data, function(d) {return d.avg_welfare})]) .range([margin.top + 0 * height / 3, margin.top + 1 * height / 3]); var yAxis2 = d3.scaleLinear() .domain([0, d3.max(data, function(d) {return d.welfare_share})]) .range([margin.top + 1 * height / 3, margin.top + 2 * height / 3]); var yAxis3 = d3.scaleLinear() .domain([0, d3.max(data, function(d) {return d.pop_share})]) .range([margin.top + 2 * height / 3, margin.top + 3 * height / 3]); g.append("g") .attr("transform", "translate(0, " + (height + margin.top + 0) + ")") .call(d3.axisBottom(xAxis1)) g.append("g") .attr("transform", "translate(0, " + (height + margin.top + 20) + ")") .call(d3.axisBottom(xAxis2)) g.append("g") // CORRECTION: move axis by margin .attr('transform', 'translate(' + margin.left + ' 0)') .call(d3.axisLeft(yAxis1)) g.append("g") // CORRECTION: move axis by margin .attr('transform', 'translate(' + margin.left + ' 0)') .call(d3.axisLeft(yAxis2)) g.append("g") // CORRECTION: move axis by margin .attr('transform', 'translate(' + margin.left + ' 0)') .call(d3.axisLeft(yAxis3)) g.selectAll("dot") .data(data) .enter().append("circle") .attr("cx", function(d) {return xAxis1(d.year); }) .attr("cy", function(d) {return yAxis1(d.avg_welfare); }) .attr("r", 5) .style("fill", "green") g.selectAll("dot") .data(data) .enter().append("circle") .attr("cx", function(d) {return xAxis1(d.year); }) .attr("cy", function(d) {return yAxis2(d.welfare_share); }) .attr("r", 5) .style("fill", "blue") g.selectAll("dot") .data(data) .enter().append("circle") .attr("cx", function(d) {return xAxis1(d.year); }) .attr("cy", function(d) {return yAxis3(d.pop_share); }) .attr("r", 5) .style("fill", "yellow") svg.append("text") .attr("transform", "translate(300,0)") .attr("x", 50) .attr("y", 50) .attr("font-size", "40px") .text("Distribution of wealth from 2014-2018"); g.append("g") .attr("transform", "translate(0, " + (height + margin.top + 40) + ")") // .call(d3.axisBottom(xAxis1)) - CORRECTION: This draws the actual axes. You have done this already .append("text") // CORRECTION: the x/y of the text is added to the existing translation of the group .attr("y", 20) .attr("x", margin.left + width) .attr("text-anchor", "end") .attr("stroke", "black") .text("Year"); g.append("g") // CORRECTION: - transform into view (margins) .attr('transform', 'translate(' + margin.left + ', ' + (margin.top + 0 * height / 3) + ')') // .call(d3.axisLeft(yAxis1)) - CORRECTION: This draws the actual axes. You have done this already .append("text") .attr("transform", "rotate(-90)") // CORRECTION: - moved into view - horizontal placement after rotation .attr("y", 30) .attr("dy", "-5.1em") .attr("text-anchor", "end") .attr("stroke", "black") .text("Average Wealth"); g.append("g") // CORRECTION: - transform into view (margins) .attr('transform', 'translate(' + margin.left + ', ' + (margin.top + 1 * height / 3) + ')') // .call(d3.axisLeft(yAxis2)) - CORRECTION: This draws the actual axes. You have done this already .append("text") .attr("transform", "rotate(-90)") // CORRECTION: - moved into view - horizontal placement after rotation .attr("y", 30) .attr("dy", "-5.1em") .attr("text-anchor", "end") .attr("stroke", "black") .text("Share of Wealth"); g.append("g")// CORRECTION: - transform into view (margins) .attr('transform', 'translate(' + margin.left + ', ' + (margin.top + 2 * height / 3) + ')') // .call(d3.axisLeft(yAxis3)) - CORRECTION: This draws the actual axes. You have done this already .append("text") .attr("transform", "rotate(-90)") // CORRECTION: - moved into view - horizontal placement after rotation .attr("y", 30) .attr("dy", "-5.1em") .attr("text-anchor", "end") .attr("stroke", "black") .text("Population Share") }); </script> </body> There were some errors in the script tags. For further improving the solution I would suggest: Do not call you scale functions (i.e. scaleLinear()) 'axis'. An axis is a way of visualizing a scale. Just call them x1, x2, y1, etc. d3.axisLeft() is the command for drawing the axes for a given scale. Work with SVG groups (g). When you transform a g element, the placement of all children will be relative to its origin. You could create a single SVG g element for all three stacked charts and translate them vertically. Have a look at this example of stacking charts.
D3.js line chart with dates on x axes
I'm working on this line chart with d3.js . I have a problem formatting the dates and as much I change the parseDate field, there is no way I can find to get for example "15 June". If I change .tickformat in the x axis on %d I will just have "01 Oct" and not the exact date. Here is the JS fiddle http://jsfiddle.net/w0d4t1n5/ <script async src="//jsfiddle.net/w0d4t1n5/embed/"></script> Thanks for your help!
If I understand, you want every datapoint's date displayed on the x axis, instead of just a time division. For that, you need to create an ordinal scale and call that in the X axis: fiddle is here: http://jsfiddle.net/z94uzc0L/1/ var margin = { top: 30, right: 100, bottom: 30, left: 50 }, width = 365 - margin.left - margin.right, height = 280 - margin.top - margin.bottom, padding = 1; var parseDate = d3.time.format("%d-%b-%y").parse; // Set the ranges var x = d3.time.scale() .range([10, width - 15]); //ordinal scale var x2 = d3.scale.ordinal().rangePoints([0, width ], .25) var y = d3.scale.linear() .range([height, 0]); var xAxis = d3.svg.axis().scale(x2) .orient("bottom") .tickFormat(d3.time.format("%b %d")) .ticks(4) .tickPadding(2); var yAxis = d3.svg.axis().scale(y) .orient("left"); var valueline = d3.svg.line() .interpolate("basis") .x(function(d) { return x(d.date); }) .y(function(d) { return y(d.trump); }); var valueline2 = d3.svg.line() .interpolate("basis") .x(function(d) { return x(d.date); }) .y(function(d) { return y(d.clinton); }); //florida var chart1 = d3.select("#florida") .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 + ")"); //needed for the grid function make_y_axis() { return d3.svg.axis() .scale(y) .orient("left") } data1 = [{ "date": "15-Jun-16", "trump": 43.4, "clinton": 44 }, { "date": "15-Jul-16", "trump": 43.4, "clinton": 44 }, { "date": "15-Aug-16", "trump": 42, "clinton": 45.6 }, { "date": "15-Sep-16", "trump": 45.1, "clinton": 44.4 }, { "date": "06-Oct-16", "trump": 43.3, "clinton": 46.2 }, { "date": "10-Oct-16", "trump": 49.3, "clinton": 49.2 }]; var color = d3.scale.ordinal().range(["#004ecc", "#cc0000"]); //d3.csv("data.csv", function(error, data) { data1.forEach(function(d) { d.date = parseDate(d.date); d.trump = +d.trump; d.clinton = +d.clinton; }); // Scale the range of the data x.domain(d3.extent(data1, function(d) { return d.date; })); y.domain([36, 50]); //update ordinal scale domain x2.domain(data1.map(function(d) { return d.date; })); //add the grid chart1.append("g") .attr("class", "grid") .call(make_y_axis() .tickSize(-width, 0, 0) .tickFormat("") ) chart1.append("path") .attr("class", "line") .attr("stroke", "red") .attr("d", valueline(data1)); chart1.append("path") .attr("class", "line2") .attr("d", valueline2(data1)); // Add the X Axis chart1.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); // Add the Y Axis chart1.append("g") .attr("class", "y axis") .call(yAxis); chart1.append("text") .attr("transform", "translate(" + (width + 3) + "," + y(data1[0].clinton) + ")") .attr("x", ".1em") .attr("y", "-40") .attr("text-anchor", "start") .style("fill", "red") .style("font-size", "15") .style("font-weight", "bold") .text("Clinton 46.2%"); chart1.append("text") .attr("transform", "translate(" + (width + 3) + "," + y(data1[0].trump) + ")") .attr("x", ".1em") .attr("y", "10") .attr("text-anchor", "start") .style("fill", "steelblue") .style("font-size", "15") .style("font-weight", "bold") .text("Trump 43.3%"); //plus 1: animation var curtain = chart1.append('rect') .attr('x', -1 * width) .attr('y', -1 * height) .attr('height', height) .attr('width', width) .attr('class', 'curtain') .attr('transform', 'rotate(180)') .style('fill', '#ffffff') /* Optionally add a guideline */ var guideline = chart1.append('line') .attr('stroke', '#333') .attr('stroke-width', 0.4) .attr('class', 'guide') .attr('x1', 1) .attr('y1', 1) .attr('x2', 1) .attr('y2', height) var t = chart1.transition() .delay(120) .duration(500) .ease('linear') .each('end', function() { d3.select('line.guide') .transition() .style('opacity', 0) .remove() }); t.select('rect.curtain') .attr('width', 0); t.select('line.guide') .attr('transform', 'translate(' + width + ', 0)') d3.select("#show_guideline").on("change", function(e) { guideline.attr('stroke-width', this.checked ? 1 : 0); curtain.attr("opacity", this.checked ? 0.75 : 1); });
Plot multiple lines and scatter points on the same chart using d3, and use the mouseover function to calculate distance
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.
D3.js Mouseover and Focus + Context issue
I am new to D3.js I've gone through some tutorials and have straight up jumped into my first project. I was hoping to combine the following with slight tweaks according to my needs. Currently I am having two issues Focus+Context via Brushing and X-Value Mouseover The Mouseover is wrongly displayed. It renders to the left of the chart. Could be a very small issue but I cant seem to find it. I cant seem to figure out a way to display the "Safe Value" text outside the chart right next to the line. EDIT 2 - I've figured this out Any help would be much appreciated. Here is the CSS body { font: 10px sans-serif; } svg { font: 10px sans-serif; } .line { fill: none; stroke: steelBlue; stroke-width: 1.5px; /*clip-path: url(#clip);*/ } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .brush .extent { stroke: #fff; fill-opacity: .125; shape-rendering: crispEdges; } .overlay { fill: none; pointer-events: all; } .xy circle { fill: steelblue; stroke: black; } JS var margin = {top: 10, right: 15, bottom: 100, left: 60}, margin2 = {top: 430, right: 15, bottom: 20, left: 60}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom, height2 = 500 - margin2.top - margin2.bottom; var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%SZ").parse, bisectDate = d3.bisector(function(d) { return d.date; }).left, formatValue = d3.format(",.2f"), formatData = function(d) { return formatValue(d) + " %"; }; var x = d3.time.scale().range([0, width]), x2 = d3.time.scale().range([0, width]), y = d3.scale.linear().range([height, 0]), y2 = d3.scale.linear().range([height2, 0]); var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(d3.time.months, 1).tickFormat(d3.time.format("%m/%y")), xAxis2 = d3.svg.axis().scale(x2).orient("bottom").ticks(d3.time.months, 1).tickFormat(d3.time.format("%m/%y")), yAxis = d3.svg.axis().scale(y).orient("left"); var brush = d3.svg.brush() .x(x2) .on("brush", brushed); var line = d3.svg.line() .interpolate("monotone") .x(function(d) { return x(d.date); }) .y(function(d) { return y(d.value); }); var line2 = d3.svg.line() .interpolate("monotone") .x(function(d) { return x2(d.date); }) .y(function(d) { return y2(d.value); }); var svg = d3.select("body").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) svg.append("defs").append("clipPath") .attr("id", "clip") .append("rect") .attr("width", width) .attr("height", height); var focus = svg.append("g") .attr("class", "focus") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var context = svg.append("g") .attr("class", "context") .attr("transform", "translate(" + margin2.left + "," + margin2.top + ")"); d3.csv("data.csv", function(error, data) { if (error) throw error; data.forEach(function(d) { d.date = parseDate(d.date); d.value = +d.value; }); data.sort(function(a, b) { return a.date - b.date; }); x.domain(d3.extent(data.map(function(d) { return d.date; }))); y.domain([0, d3.max(data.map(function(d) { return d.value; }))]); x2.domain(x.domain()); y2.domain(y.domain()); focus.append("path") .datum(data) .attr("class", "line") .attr("d", line); focus.append("line") .attr("x1",x(data[0].date)) .attr("y1",y(83)) .attr("x2",x(data[data.length - 1].date)) .attr("y2",y(83)) .attr("stroke","orangered"); svg.append("text") .attr("transform", "translate(" + (width+3) + "," + y(83) + ")") .attr("dy", ".35em") .attr("text-anchor", "start") .style("fill", "orangered") .text(function(d) { return "Safe Value = 83" }); focus.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); focus.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("x", 0) .attr("y", 0) .style("text-anchor", "middle") .attr("transform", "translate(-50,"+ height/2 + ") rotate(-90)") .text("Dissolved Oxygen (%)"); context.append("path") .datum(data) .attr("class", "line") .attr("d", line2); context.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height2 + ")") .call(xAxis2); context.append("g") .attr("class", "x brush") .call(brush) .selectAll("rect") .attr("y", -6) .attr("height", height2 + 7); var xy = svg.append("g") .attr("class", "xy") .style("display", "none"); xy.append("circle") .attr("r", 4.5); xy.append("text") .attr("x", 9) .attr("dy", ".35em"); svg.append("rect") .attr("class", "overlay") .attr("width", width) .attr("height", height) .style("fill", "none") .on("mouseover", function() { xy.style("display", null); }) .on("mouseout", function() { xy.style("display", "none"); }) .on("mousemove", mousemove); function mousemove() { var x0 = x.invert(d3.mouse(this)[0]), i = bisectDate(data, x0, 1), d0 = data[i - 1], d1 = data[i], d = x0 - d0.date > d1.date - x0 ? d1 : d0; console.log(x0); xy.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")"); xy.select("text").text(formatData(d.value)); } }); function brushed() { x.domain(brush.empty() ? x2.domain() : brush.extent()); focus.select(".line").attr("d", line); focus.select(".x.axis").call(xAxis); } Plunker Code (Please refer to the code at Plunker, since I have updated a few things over there.) Thanks Image1 Image2
For your problem #2, the code for the text is placing it out of the visible area. Just adjust your arguments to translate to something like the following: .attr("transform", "translate(" + (width - 35) + ",30" + ")") or something else that you prefer - note the minus on the x.
Mousmove animation for Tooltips
I'm learning D3 js and tried following example. Somehow I've managed it to a Single line chart by removing non required code. http://bl.ocks.org/gniemetz/4618602 Now, I want to enhance this example a way that once user do brush on the smaller one chart, whatever range comes between the brush, it's line point should animate tool-tip on interval of some seconds. But I'm not able to get the start and end points of the brush. Sorry for the long long code .... var main_margin = {top: 20, right: 80, bottom: 100, left: 40}, mini_margin = {top: 430, right: 80, bottom: 20, left: 40}, main_width = 960 - main_margin.left - main_margin.right, main_height = 500 - main_margin.top - main_margin.bottom, mini_height = 500 - mini_margin.top - mini_margin.bottom, start = 0, end = 100, focus; var formatDate = d3.time.format("%H:%M"), parseDate = formatDate.parse, bisectDate = d3.bisector(function(d) { return d.Uhrzeit; }).left, formatOutput0 = function(d) { return formatDate(d.Uhrzeit) + " - " + d.Durchschn + " ms"; }; var main_x = d3.time.scale() .range([0, main_width]), mini_x = d3.time.scale() .range([0, main_width]); var main_y0 = d3.scale.sqrt() .range([main_height, 0]), mini_y0 = d3.scale.sqrt() .range([mini_height, 0]); var main_xAxis = d3.svg.axis() .scale(main_x) .tickFormat(d3.time.format("%H:%M")) .orient("bottom"), mini_xAxis = d3.svg.axis() .scale(mini_x) .tickFormat(d3.time.format("%H:%M")) .orient("bottom"); var main_yAxisLeft = d3.svg.axis() .scale(main_y0) .orient("left"); var brush = d3.svg.brush() .x(mini_x) .on("brushstart",function(){ console.log(brush.extent()[0]); }) .on("brush",brushMove) .on("brushend", function(){ console.log(brush.extent()[1]); }); var main_line0 = d3.svg.line() .interpolate("cardinal") .x(function(d) { return main_x(d.Uhrzeit); }) .y(function(d) { return main_y0(d.Durchschn); }); var mini_line0 = d3.svg.line() .x(function(d) { return mini_x(d.Uhrzeit); }) .y(function(d) { return mini_y0(d.Durchschn); }); var svg = d3.select("body").append("svg") .attr("width", main_width + main_margin.left + main_margin.right) .attr("height", main_height + main_margin.top + main_margin.bottom); svg.append("defs").append("clipPath") .attr("id", "clip") .append("rect") .attr("width", main_width) .attr("height", main_height); var main = svg.append("g") .attr("transform", "translate(" + main_margin.left + "," + main_margin.top + ")"); var mini = svg.append("g") .attr("transform", "translate(" + mini_margin.left + "," + mini_margin.top + ")"); d3.csv("data.txt", function(error, data) { data.forEach(function(d) { d.Uhrzeit = parseDate(d.Uhrzeit); d.Durchschn = +d.Durchschn; }); data.sort(function(a, b) { return a.Uhrzeit - b.Uhrzeit; }); main_x.domain([data[0].Uhrzeit, data[data.length - 1].Uhrzeit]); main_y0.domain(d3.extent(data, function(d) { return d.Durchschn; })); mini_x.domain(main_x.domain()); mini_y0.domain(main_y0.domain()); main.append("path") .datum(data) .attr("clip-path", "url(#clip)") .attr("class", "line line0") .attr("d", main_line0); main.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + main_height + ")") .call(main_xAxis); main.append("g") .attr("class", "y axis axisLeft") .call(main_yAxisLeft) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Ø AWZ (ms)"); mini.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + mini_height + ")") .call(main_xAxis); mini.append("path") .datum(data) .attr("class", "line") .attr("d", mini_line0); mini.append("g") .attr("class", "x brush") .call(brush) .selectAll("rect") .attr("y", -6) .attr("height", mini_height + 7); focus = main.append("g") .attr("class", "focus") .style("display", "none"); focus.append("line") .attr("class", "x") .attr("y1", main_y0(0) - 6) .attr("y2", main_y0(0) + 6) focus.append("line") .attr("class", "y0") .attr("x1", main_width - 6) // nach links .attr("x2", main_width + 6); // nach rechts focus.append("circle") .attr("class", "y0") .attr("r", 4); focus.append("text") .attr("class", "y0") .attr("dy", "-1em"); main.append("rect") .attr("class", "overlay") .attr("width", main_width) .attr("height", main_height) .on("mouseover", showToolTip) .on("mouseout", hideToolTip) .on("mousemove", mousemove); function mousemove() { var x0 = main_x.invert(d3.mouse(this)[0]), i = bisectDate(data, x0, 1), d0 = data[i - 1], d1 = data[i], d = x0 - d0.Uhrzeit > d1.Uhrzeit - x0 ? i : (i-1); showToolTipForIndex(d); } function showToolTipForIndex(i){ var d = data[i]; focus.select("circle.y0").attr("transform", "translate(" + main_x(d.Uhrzeit) + "," + main_y0(d.Durchschn) + ")"); focus.select("text.y0").attr("transform", "translate(" + main_x(d.Uhrzeit) + "," + main_y0(d.Durchschn) + ")").text(formatOutput0(d)); focus.select(".x").attr("transform", "translate(" + main_x(d.Uhrzeit) + ",0)"); focus.select(".y0").attr("transform", "translate(" + main_width * -1 + ", " + main_y0(d.Durchschn) + ")").attr("x2", main_width + main_x(d.Uhrzeit)); } // set default brush on mini xAxis defaultBrush(data,start,end); // bind event listeners document.getElementById('play').addEventListener('click',function(){ if( !brush.empty() ){ // here I want to get brush's start and end points.. I mean the range } }); }); function showToolTip(){ focus.style("display", null); } function hideToolTip(){ focus.style("display", "none"); } function defaultBrush(data,start,end){ svg.select(".x.brush").call(brush.extent([data[start].Uhrzeit,data[end].Uhrzeit])); main_x.domain([data[start].Uhrzeit,data[end].Uhrzeit]); main.select(".line0").attr("d", main_line0); main.select(".x.axis").call(main_xAxis); } function brushMove() { main_x.domain(brush.empty() ? mini_x.domain() : brush.extent()); main.select(".line0").attr("d", main_line0); main.select(".x.axis").call(main_xAxis); } function brushStart(){ } function brushEnd(){ } });
The start and end points of the selected region are contained in brush.extent(). This function returns an array of two points, start and end. So if you wanted to get start and end x coordinates, you would do something like this. var extent = brush.extent(), start = extent[0][0], end = extent[1][0];