Question

I have the multi series line chart code with slight modifications to support my data set. This is what I wish to do, and no solution I have looked at seems to function properly for me. I wish to overlay some element (circle, rectange, hidden, whichever) over each point on the line such that I could then attach a mouseover element on that point to display a box with data containing the d.time, d.jobID and how much that differs from an average. If possible, I would like the solution to only do this to the main line (the varying line) rather than the two lines drawn to represent the average. Here, I have a picture of the graph as-is for visual inspection. If that doesn't work, I have also attached it.

I have posted a bit the code below:

d3.tsv("values.tsv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "time" && key !==   "jobID"; }));

data.forEach(function(d) {
  d.time = parseDate(d.time);
  d.jobID = parseInt(d.jobID);
});

var points = color.domain().map(function(name) {
return {
  name: name,
  values: data.map(function(d) {
    return {time: d.time, jobID: d.jobID, value: parseFloat(d[name],10)};
  })
};
});

....

svg.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis);

svg.append("g")
  .attr("class", "y axis")
  .call(yAxis)
.append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 7)
  .attr("dy", ".71em")
  .style("text-anchor", "end")
  .text("mbps");

var point = svg.selectAll(".point")
  .data(points)
.enter().append("g")
  .attr("class", "point");

point.append("path")
  .attr("class", "line")
  .attr("d", function(d) { return line(d.values); })
  .style("stroke", function(d) { return color(d.name); });

point.append("text")
  .datum(function(d) { return {name: d.name, jobID: d.jobID, value: d.values[d.values.length - 1]}; })
  .attr("transform", function(d) { return "translate(" + x(d.value.time) + "," + y(d.value.value) + ")"; })
  .attr("x", 6)
  .attr("dy", ".7em")
  .text(function(d) { return d.name; });
});

I have already tried the following code just to see if it worked with my implementation:

point.append("svg:circle")
     .attr("stroke", "black")
     .attr("fill", function(d, i) { return "black" })
     .attr("cx", function(d, i) { return x(d.time) })
     .attr("cy", function(d, i) { return y(d.value) })
     .attr("r", function(d, i) { return 3 });

D3.JS seems like a pretty awesome piece of work, and I'm fortunate to have it.

EDIT: jsfiddle

Was it helpful?

Solution

The trick is to pass the data again to a selection and then operate on the result of that. Have a look at Mike's tutorial for some background and examples.

I've changed your jsfiddle to add circles here. Attaching svg:title elements or doing something else to show more information should be straightforward. Note that I modified your code to create the data points slightly to include the name with each element. This way, only one additional level of selections is necessary (treat all the points the same and add them in a single pass). The cleaner way to solve this from a code design point of view would be to have 2 additional levels -- first have a selection for the points for an individual line (and add an svg:g element to group them) and then add the points within this group. This would make the code quite a bit more complex and difficult to understand though.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top