简体   繁体   中英

How to add dots in D3 graph?

My objective is to draw a graph which has line and dots.

I was able to draw line and dots with zoom and brush but the problem is, when i zoom in or zoom out, the dots are not moving according to zoom.

I am relatively new to D3 graph. Below is the code i have used to plot dots:

    g.selectAll(".dot")
      .data(dots)
      .enter()
      .append("circle")
      .attr("class", "dot")
      .attr("r", 3.5)
      .attr("cx", function(d) { return x(new Date(d.date)); })
      .attr("cy", function(d) { return y(d.price); })
      .on("mouseover", function(d){
        return tooltip.style("visibility", "visible").html("Expected value is: "+d.expected_value + "<br/>"  + "value : "+d.close +"<br/>"  + "deviation is: "+d.deviation_expected)
      })
      .on("mousemove", function(){return tooltip.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px");})
      .on("mouseout", function(){return tooltip.style("visibility", "hidden");});

I have created jsfiddle

Please help.

I will describe few basic features you must understand before approaching visualization. As per the fiddle, you have two sets of data that must be plotted across X & Y axis.(Ex: data, dots). Domain for this data sets are different though you need to understand the concept of Domain and range.

d3.scaleLinear() <>

Constructs a new continuous scale with the unit domain [0, 1], the unit range [0, 1], the default interpolator and clamping disabled. Linear scales are a good default choice for continuous quantitative data because they preserve proportional differences. Each range value y can be expressed as a function of the domain value x: y = mx + b.

d3.scaleTime() <>

Constructs a new time scale with the domain [2000-01-01, 2000-01-02], the unit range [0, 1], the default interpolator and clamping disabled.

  • Domain and Range mapping for individual data series
  • Brush and zoom and its invert mapping to the scales
  • Redraw the plots based on new scales.

** Below code snippet is just to explain the brush implementation with out considering the scale for dots. Try it your self to map the logic by reading the documentation Brush Event Example

 var data = [{ "date": "2017-04-22T11:45:00.000Z", "total": 731.6047915220261, "min": 1.8769680261611938, "key_field": "1492861500000", "max": 2.7165653705596924, "price": 1.8769680261611938, "total_count": 315, "mean": 2.3225548937207177, "count": 315 }, { "date": "2017-04-01T05:30:00.000Z", "total": 708.6527144908905, "min": 1.779407262802124, "key_field": "1491024600000", "max": 2.6382412910461426, "price": 1.779407262802124, "total_count": 315, "mean": 2.249691157113938, "count": 315 }, { "date": "2017-03-31T02:45:00.000Z", "total": 700.1026722192764, "min": 1.8156663179397583, "key_field": "1490928300000", "max": 2.587003469467163, "price": 1.8156663179397583, "total_count": 315, "mean": 2.2225481657754806, "count": 315 }, { "date": "2017-03-31T02:30:00.000Z", "total": 699.6637561321259, "min": 1.8294581174850464, "key_field": "1490927400000", "max": 2.57082200050354, "price": 1.8294581174850464, "total_count": 315, "mean": 2.221154781371828, "count": 315 }, { "date": "2017-03-31T02:15:00.000Z", "total": 702.4780179262161, "min": 1.8524492979049683, "key_field": "1490926500000", "max": 2.628413677215576, "price": 1.8524492979049683, "total_count": 315, "mean": 2.2300889457975117, "count": 315 }, { "date": "2017-03-31T02:00:00.000Z", "total": 705.038315653801, "min": 1.8353750705718994, "key_field": "1490925600000", "max": 2.604921340942383, "price": 1.8353750705718994, "total_count": 315, "mean": 2.2382168750914317, "count": 315 }, { "date": "2017-03-31T01:45:00.000Z", "total": 701.7422981262207, "min": 1.8062856197357178, "key_field": "1490924700000", "max": 2.5804450511932373, "price": 1.8062856197357178, "total_count": 315, "mean": 2.2277533273848276, "count": 315 }, { "date": "2017-03-31T01:30:00.000Z", "total": 706.3951338529587, "min": 1.8176854848861694, "key_field": "1490923800000", "max": 2.584993600845337, "price": 1.8176854848861694, "total_count": 315, "mean": 2.242524234453837, "count": 315 }, { "date": "2017-03-31T01:15:00.000Z", "total": 704.2638461589813, "min": 1.7730687856674194, "key_field": "1490922900000", "max": 2.6350574493408203, "price": 1.7730687856674194, "total_count": 315, "mean": 2.235758241774544, "count": 315 }, { "date": "2017-03-31T01:00:00.000Z", "total": 703.4522807598114, "min": 1.8147484064102173, "key_field": "1490922000000", "max": 2.5720791816711426, "price": 1.8147484064102173, "total_count": 315, "mean": 2.233181843681941, "count": 315 }, { "date": "2017-03-31T00:45:00.000Z", "total": 706.2918384075165, "min": 1.7760894298553467, "key_field": "1490921100000", "max": 2.596073627471924, "price": 1.7760894298553467, "total_count": 315, "mean": 2.2421963124048143, "count": 315 }, { "date": "2017-03-31T00:30:00.000Z", "total": 707.0961575508118, "min": 1.7756011486053467, "key_field": "1490920200000", "max": 2.6146974563598633, "price": 1.7756011486053467, "total_count": 315, "mean": 2.2447497065105138, "count": 315 }, { "date": "2017-03-31T00:15:00.000Z", "total": 706.1140650510788, "min": 1.7976468801498413, "key_field": "1490919300000", "max": 2.6084225177764893, "price": 1.7976468801498413, "total_count": 315, "mean": 2.2416319525431074, "count": 315 }, { "date": "2017-03-31T00:00:00.000Z", "total": 707.5575115680695, "min": 1.8497636318206787, "key_field": "1490918400000", "max": 2.5975091457366943, "price": 1.8497636318206787, "total_count": 315, "mean": 2.2462143224383158, "count": 315 }, { "date": "2017-03-30T23:45:00.000Z", "total": 707.9171552658081, "min": 1.8517450094223022, "key_field": "1490917500000", "max": 2.5352094173431396, "price": 1.8517450094223022, "total_count": 315, "mean": 2.247356048462883, "count": 315 }, { "date": "2017-03-30T23:30:00.000Z", "total": 707.09266269207, "min": 1.8389506340026855, "key_field": "1490916600000", "max": 2.593708038330078, "price": 1.8389506340026855, "total_count": 315, "mean": 2.244738611720857, "count": 315 }, { "date": "2017-03-30T23:15:00.000Z", "total": 708.3666490316391, "min": 1.861556053161621, "key_field": "1490915700000", "max": 2.6234216690063477, "price": 1.861556053161621, "total_count": 315, "mean": 2.2487830127988544, "count": 315 } ] var dots = [ { "date": "2017-04-22T11:45:00.000Z", "total": 731.6047915220261, "min": 1.8769680261611938, "key_field": "1492861500000", "max": 2.7165653705596924, "price": 1.8769680261611938, "total_count": 315, "mean": 2.3225548937207177, "count": 315 }, { "date": "2017-03-31T01:45:00.000Z", "total": 701.7422981262207, "min": 1.8062856197357178, "key_field": "1490924700000", "max": 2.5804450511932373, "price": 1.7062856197357178, "total_count": 315, "mean": 2.2277533273848276, "count": 315 }, { "date": "2017-03-31T01:30:00.000Z", "total": 706.3951338529587, "min": 1.8176854848861694, "key_field": "1490923800000", "max": 2.584993600845337, "price": 1.8176854848861694, "total_count": 315, "mean": 2.242524234453837, "count": 315 }, { "date": "2017-03-28T18:00:00.000Z", "total": 728.67049741745, "min": 1.2837289810180664, "key_field": "1490724000000", "max": 2.706052541732788, "price": 1.3837289810180664, "total_count": 315, "mean": 2.3132396743411108, "count": 315 }, { "date": "2017-03-26T20:00:00.000Z", "total": 721.6712145805359, "min": 1.8257900476455688, "key_field": "1490558400000", "max": 2.762291669845581, "price": 1.4257900476455688, "total_count": 315, "mean": 2.291019728827098, "count": 315 }, { "date": "2017-03-28T17:45:00.000Z", "total": 726.2018908262253, "min": 1.8992395401000977, "key_field": "1490723100000", "max": 2.7374281883239746, "price": 1.8992395401000977, "total_count": 315, "mean": 2.305402828019763, "count": 315 }, { "date": "2017-03-28T17:30:00.000Z", "total": 730.83118724823, "min": 1.8232735395431519, "key_field": "1490722200000", "max": 2.696560859680176, "price": 1.3232735395431519, "total_count": 315, "mean": 2.320099007137238, "count": 315 }, { "date": "2017-03-28T17:15:00.000Z", "total": 728.1204907894135, "min": 1.8851990699768066, "key_field": "1490721300000", "max": 2.654668092727661, "price": 1.8851990699768066, "total_count": 315, "mean": 2.3114936215536934, "count": 315 }, { "date": "2017-03-27T02:45:00.000Z", "total": 702.2468013763428, "min": 1.7651863098144531, "key_field": "1490582700000", "max": 2.6390604972839355, "price": 1.373651863098144531, "total_count": 315, "mean": 2.229354925004263, "count": 315 }, { "date": "2017-03-27T02:30:00.000Z", "total": 700.9137979745865, "min": 1.8334004878997803, "key_field": "1490581800000", "max": 2.620957136154175, "price": 1.8334004878997803, "total_count": 315, "mean": 2.2251231681732904, "count": 315 }, { "date": "2017-03-27T02:15:00.000Z", "total": 700.9274371862411, "min": 1.8098258972167969, "key_field": "1490580900000", "max": 2.6065454483032227, "price": 1.8098258972167969, "total_count": 315, "mean": 2.2251664672579086, "count": 315 }, { "date": "2017-03-27T02:00:00.000Z", "total": 703.2963272333145, "min": 1.7948274354934692, "key_field": "1490580000000", "max": 2.549198865890503, "price": 1.7968274354934692, "total_count": 315, "mean": 2.2326867531216332, "count": 315 }, { "date": "2017-03-27T01:45:00.000Z", "total": 700.4703311920166, "min": 1.8429771661758423, "key_field": "1490579100000", "max": 2.518679141998291, "price": 1.348429771661758423, "total_count": 315, "mean": 2.223715337117513, "count": 315 }, { "date": "2017-03-27T01:30:00.000Z", "total": 701.4555011987686, "min": 1.7773451805114746, "key_field": "1490578200000", "max": 2.635554790496826, "price": 1.27773451805114746, "total_count": 315, "mean": 2.2268428609484716, "count": 315 }, { "date": "2017-03-26T20:00:00.000Z", "total": 721.6712145805359, "min": 1.8257900476455688, "key_field": "1490558400000", "max": 2.762291669845581, "price": 1.48257900476455688, "total_count": 315, "mean": 2.291019728827098, "count": 315 }, { "date": "2017-03-26T19:45:00.000Z", "total": 724.9882735013962, "min": 1.80784010887146, "key_field": "1490557500000", "max": 2.6430490016937256, "price": 0.40784010887146, "total_count": 315, "mean": 2.301550074607607, "count": 315 }, ] var svg = d3.select("svg"), margin = {top: 20, right: 20, bottom: 110, left: 40}, margin2 = {top: 430, right: 20, bottom: 30, left: 40}, width = +svg.attr("width") - margin.left - margin.right, height = +svg.attr("height") - margin.top - margin.bottom, height2 = +svg.attr("height") - margin2.top - margin2.bottom; var parseDate = d3.timeParse("%m/%d/%Y %H:%M"); var g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var x = d3.scaleTime().range([0, width]), x2 = d3.scaleTime().range([0, width]), y = d3.scaleLinear().range([height, 0]), y2 = d3.scaleLinear().range([height2, 0]), dotXScale = d3.scaleTime().range([0, width]), dotYScale = d3.scaleLinear().range([height, 0]); var xAxis = d3.axisBottom(x), xAxis2 = d3.axisBottom(x2), yAxis = d3.axisLeft(y); var brush = d3.brushX() .extent([[0, 0], [width, height2]]) .on("brush end", brushed); var zoom = d3.zoom() .scaleExtent([1, Infinity]) .translateExtent([[0, 0], [width, height]]) .extent([[0, 0], [width, height]]) .on("zoom", zoomed); var line = d3.line() .x(function (d) { return x(new Date(d.date)); }) .y(function (d) { return y(d.price); }); var line2 = d3.line() .x(function (d) { return x2(new Date(d.date)); }) .y(function (d) { return y2(d.price); }); var clip = svg.append("defs").append("svg:clipPath") .attr("id", "clip") .append("svg:rect") .attr("width", width) .attr("height", height) .attr("x", 0) .attr("y", 0); var Line_chart = svg.append("g") .attr("class", "focus") .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .attr("clip-path", "url(#clip)"); 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 + ")"); x.domain(d3.extent(data, function(d) { return new Date(d.date); })); dotXScale.domain(d3.extent(dots, function(d) { return new Date(d.date); })); y.domain([0, d3.max(data, function (d) { return d.price; })]); dotYScale.domain([0, d3.max(dots, function (d) { return d.price; })]); x2.domain(x.domain()); y2.domain(y.domain()); focus.append("g") .attr("class", "axis axis--x") .attr("transform", "translate(0," + height + ")") .call(xAxis); focus.append("g") .attr("class", "axis axis--y") .call(yAxis); Line_chart.append("path") .datum(data) .attr("class", "line") .attr("d", line); context.append("path") .datum(data) .attr("class", "line") .attr("d", line2); context.append("g") .attr("class", "axis axis--x") .attr("transform", "translate(0," + height2 + ")") .call(xAxis2); context.append("g") .attr("class", "brush") .call(brush) .call(brush.move, x.range()); svg.append("rect") .attr("class", "zoom") .attr("width", width) .attr("height", height) .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .call(zoom); var tooltip = d3.select("body") .append("div") .style("position", "absolute") .style("z-index", "10") .style("visibility", "hidden") .text("a simple tooltip"); g.selectAll(".dot") .data(dots) .enter() .append("circle") .attr("class", "dot") .attr("r", 3.5) .attr("cx", function(d) { //console.log('---',x(new Date(d.date))) return dotXScale(new Date(d.date)); }) .attr("cy", function(d) { //console.log(y(d.price)); return dotYScale(d.price); }) .on("mouseover", function(d){ console.log(d); return tooltip.style("visibility", "visible").html("Expected value is: "+d.expected_value + "<br/>" + "value : "+d.close +"<br/>" + "deviation is: "+d.deviation_expected) }) .on("mousemove", function(){return tooltip.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px");}) .on("mouseout", function(){return tooltip.style("visibility", "hidden");}); function brushed() { if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom var s = d3.event.selection || x2.range(); x.domain(s.map(x2.invert, x2)); dotXScale.domain(s.map(x2.invert), x2); Line_chart.select(".line").attr("d", line); focus.select(".axis--x").call(xAxis); svg.select(".zoom").call(zoom.transform, d3.zoomIdentity .scale(width / (s[1] - s[0])) .translate(-s[0], 0)); g.selectAll(".dot").transition(1000) .attr("cx", function (d) { return dotXScale(new Date(d.date)) }) .attr("cy", function (d) { //console.log(y(d.price)); return dotYScale(d.price) }); } function zoomed() { if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush var t = d3.event.transform; x.domain(t.rescaleX(x2).domain()); Line_chart.select(".line").attr("d", line); focus.select(".axis--x").call(xAxis); context.select(".brush").call(brush.move, x.range().map(t.invertX, t)); } function type(d) { d.date = new Date(d.date); d.price = +d.price; return d; } 
 .line { fill: none; stroke: steelblue; stroke-width: 2px; } .heading { padding-top: 30px; } .buttonWidth { height: 34px; width: 50px; } .actiontable { width: 36rem; } .line { fill: none; stroke: steelblue; stroke-width: 1.5px; } .zoom { cursor: move; fill: none; pointer-events: all; } .area { fill: none; stroke: #a2dced; stroke-width: 2; clip-path: url(#clip); } .zoom { cursor: move; fill: none; pointer-events: all; } rect.selection { fill:green; } 
 <script src="https://d3js.org/d3.v4.min.js"></script> <svg width="960" height="500"></svg> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM