I have been trying to append a set of SVGs inside SVG. So, in inside SVG, I want to create a function to make plot. However, this doesn't work in the way I expected as the inside SVGs don't have the dimension according to my specification. So, I'd like to know what went wrong.
svg_g_g = svg_g.append("g")
.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d) {
return "translate(" + xScale(d.key) + "," + lift + ")"
})
.append("svg")
.attr("width", function(d) { return xScale(d.key) })
.attr("height", height)
.append("line")
.style("stroke", "black")
.attr("x1", function(d) { return xScale(d.key) })
.attr("y1", height-100)
.attr("x2", function(d) { return xScale(d.key) + 50 } )
.attr("y2", height-100);
This is the output.
While if I bind data to g (without appending svg), the result looks more promising.
svg_g_g = svg_g.append("g");
svg_g_g.selectAll("line")
.data(data)
.enter()
.append("line")
.style("stroke", "black")
.attr("x1", function(d) { return xScale(d.key) })
.attr("y1", height-100)
.attr("x2", function(d) { return xScale(d.key) + 50 } )
.attr("y2", height-100);
and this is the result. (notice: the lines were shown in this case)
Any help will be appreciated.
edit: what I intended to do was I wanted to create a box-plot, I used "iris" dataset here as I can compared it against other data visualisation libraries. The current state I tried to create a SVG with an equal size for each category which I would use to contain box-plot. In other words, after I can create internal SVGs successfully, I will call a function to make the plot from there. Kinda same idea Mike did here.
Related
In a previous question a user helped me with a problem that consisted in not knowing how to put images where the circles are. this time my problem is that I can not drag the nodes. This gif illustrates my problem (first I show how the nodes should move normally, then I illustrate my problem.).
Why does this happen?
var link = g.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke", function(d) {
console.log(d);
return colorLink(d.group);
})
.attr("marker-end", "url(#arrow)");
var node = g.selectAll("g.node")
.data(graph.nodes)
//.filter(function(d){ return d.type=="circle"; })
var NodeCircleEnter= node.enter().append("g")
.attr("class","node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
NodeCircleEnter
.append("circle")
.attr("r", 20)
.attr("fill", function(d) {
return colorNode(d.group);
})
.style("stroke", function(d) {
return colorNode(d.group);
})
// Append images
var images = NodeCircleEnter.append("svg:image")
.attr("xlink:href", function(d) {console.log(d); return d.image;})
.attr("x", function(d) { return -25;})
.attr("y", function(d) { return -25;})
.attr("height", 50)
.attr("width", 50);
This is my full code:
https://plnkr.co/edit/9uH13N3or3G9VTgQlMm9?p=preview
Your event handlers need to be applied to the elements themselves rather than the canvas as a whole.
In this code (only existing in your Plunker project, but not in your question):
var drag_handler = d3.drag()
.on("start", drag_start)
.on("drag", drag_drag)
.on("end", drag_end);
drag_handler(node);
Your variable node is the drawing. You actually want a collection of elements to affect which you get from functions like .enter(). Your variable NodeCircleEnter contains that collection so the particular line should be:
drag_handler(NodeCircleEnter);
This still leaves an issue where dragging on the labels themselves doesn't work. This is because the labels aren't children of the elements you set the handlers on.
I found no direct answer for this, please forgive me if this has been covered differently in another topic.
I draw a bar chart which appears with a transition. I also want to add a tooltip which displays the value of data on mousehover.
Using the code below I have managed to obtain either the tooltip or the transition, but never the 2 together, which is my objective.
chart.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("fill", function(d) {return colorscale(colorize(d.age));})
.attr("x", function(d) {return xscale(d.name);})
.attr("y", height - 3)
.attr("height", 3)
.attr("width", xscale.rangeBand())
.append("title")
.text(function(d){return d.age;})
.transition()
.duration(1600)
.attr("y", function (d) {return yscale(d.age);})
.attr("height", function (d) {return height - yscale(d.age);}) ;
If I remove
.append("title")
.text(function(d){return d.age;})
Then my transition works fine. If I but those 2 lines back I can see my tooltip but I lose my transition.
Any suggestion would be appreciated!
You can see the result here
Thank you
You need to add the transition to the rect and not the title element:
var sel = chart.selectAll(".bar")
.data(data)
.enter()
.append("rect");
sel.append("title")
.text(function(d){return d.age;});
sel.transition()
.duration(1600)
.attr("y", function (d) {return yscale(d.age);})
.attr("height", function (d) {return height - yscale(d.age);}) ;
Here's the code I am running http://jsfiddle.net/a7as6/14/
I know that I can use this code to change node to image:
node.append("svg:image")
.attr("class", "circle")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", "-8px")
.attr("y", "-8px")
.attr("width", "16px")
.attr("height", "16px");
But when I use it and my nodes are still not images. Any idea why?
And I am wondering how to change each nodes with different images?
Thx.
You've got the right idea for appending the images, but you need to operate on node.enter() as in:
node.enter().append("image")
.attr("class", function (d) {
return "node " + d.id;
})
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("width", "16px")
.attr("height", "16px");
You then need to get your tick function to place the images, as in:
function tick() {
node.attr("x", function (d) {
return d.x;
})
.attr("y", function (d) {
return d.y;
})
And here's the working fiddle. Not that you'll need to move the images around so they look right, you can use the dx and dy properties to bump them.
I've brought some of my code to match D3 standards. But now I'm having issues with my update function working. I'm trying to follow the General Update Pattern.
When I run the function, I get an error in the console: "TypeError: gbars.enter(...).attr is not a function"
function updateBars()
{
xScale.domain(d3.range(dataset.length)).rangeRoundBands([0, w], 0.05);
yScale.domain([0, d3.max(dataset, function(d) { return (d.local > d.global) ? d.local : d.global;})]);
var gbars = svg.selectAll("rect.global")
.data(dataset);
gbars.enter()
.attr("x", w)
.attr("y", function(d) {return h - yScale(d.global); })
.attr("width", xScale.rangeBand())
.attr("height", function(d) {return yScale(d.global);});
gbars.transition()
.duration(500)
.attr("x", function(d, i) {
return xScale(i);
})
.attr("y", function(d) {
return h - yScale(d.global);
})
.attr("width", xScale.rangeBand())
.attr("height", function(d) {
return yScale(d.global);
});
gbars.exit()
.transition()
.duration(500)
.attr("x", -xScale.rangeBand())
.remove();
}
I understand, I probably have a lot of errors with the update function in general, but it's hard to troubleshoot when hung-up at the beginning.
My goal for the update will be to remove/add series from the chart. They can choose to display Global, Local, or both (default). I'd actually prefer that when they hover over the legend it shows only that series. On mouseout, it would go back to default.
Working Fiddle here.
You need to say what you want to do for new nodes. Yes it's almost always append but you still have to tell it:
gbars.enter()
.append("rect")
.attr("class", "global")
.attr("x", w)
Other than that error, your structure for general update pattern looks correct on the surface.
I've used arc.Centroid to try to plot my circles on the arcs with labels. However, the labels do not stay with it?
force.on("tick", function() {
text.attr("x", function(d) { return d.x + 6; })
.attr("y", function(d) { return d.y + 4; });
node.attr("transform", function(d,i) {
return "translate(" + arc[i].centroid(d) + ")"; })
});
I have attempted to put centroid & arc[i] instead of the x & y. How can I put my circles with text? http://jsfiddle.net/xwZjN/20/
Also say if I were to have more json data, would I be able to restrict the plots only going into each section e.g. each section being a category?
Any help would be great. I think the solution may be similar to this - http://jsfiddle.net/nrabinowitz/GQDUS/
It seems that the force layout is not the right choice for your application. Try to group your symbol and text in a g element and place them at the calculated coordinates. See updated fiddle without force layout: http://jsfiddle.net/xwZjN/26/
var node = svg.selectAll("g.node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d,i) {
return "translate(" + arc[i].centroid() + ")";
});
node.append("path")
.attr("d", d3.svg.symbol().type(function(d) { return d.type; }))
// change (0,0) for exact symbol placement
.attr("transform", "translate(0,0)")
.style("fill", "blue" );
node.append("text")
.text(function(d) { return d.Name; })
// shift text in nice position
.attr("x", 10)
.attr("y", 5);