simple multi line chart with D3 - d3.js

http://jsfiddle.net/ytvka/4/
I know this one has been asked before but I've not been able to use those examples to figure out what I'm doing wrong.
I want to create a simple 6 point, 3 series chart with data that looks like:
data = [
{"key":"D78","date":"2013-09-23T17:26:21.258Z","value":1.25},
{"key":"D78","date":"2013-09-23T17:28:21.258Z","value":2.25},
{"key":"R71","date":"2013-09-23T17:26:21.258Z","value":2.45},
{"key":"R71","date":"2013-09-23T17:28:21.258Z","value":2.85},
{"key":"X44","date":"2013-09-23T17:26:21.258Z","value":3.87},
{"key":"X44","date":"2013-09-23T17:28:21.258Z","value":3.87}
]
Nothing exciting there. What I'd ideally like to do is make a 3-series line chart out of this data.
svg = d3.select(selector).append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom).append("g")
x = d3.time.scale().range([ 0, width ])
y = d3.scale.linear().range([ height, 0 ])
format = d3.time.format("%Y-%m-%dT%H:%M:%S.%LZ")
valueLine = d3.svg.line().interpolate("basis")
.x((d) ->
console.log format.parse(d.date)
x(format.parse(d.date))
)
.y((d) ->
console.log d.value
y d.value
)
svg.append("path").attr("class", "line")
.attr "d", valueLine(u.where(data, key: "X44"))
Which generates SVG: <path class="line" d="M137998238125800,-287L137998250125800,-287"></path>
This code just pulls out one of the series using lodash. Problem is: nothing on the screen. It runs through and grabs the value but there's no lines. I'm finding that existing examples are either complex and not well explained (http://bl.ocks.org/mbostock/3884955) or missing key parts (http://www.d3noob.org/2013/01/adding-more-than-one-line-to-graph-in.html).
What's wrong with my code?
How can I add in the other series (R71, D78)?
Is there a good tutorial of this out there that has complete code and walks through all the steps?

Your first point is at (137998238125800,-287) pixel coordinate, which is far away from the visible screen area. You don't use the selectAll/enter pattern which is at the core of D3. So you should start with this fundamental tutorial, then probably the code example you mention will make more sense:
var city = svg.selectAll(".city")
.data(cities)
.enter().append("g")
.attr("class", "city");
city.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });

Related

Putting tspan inside rectangle D3JS SVG

i'm working in projet of data visualization using D3JS.
i have to put some information inside a rectangle, and i did that using wrap function to split the content, no i'm looking to put each line (tspan) inside a rectangle. and i don't know how to do that, any help is appreciated for me.enter image description here
the small rectangles will contain informations. does any one have an example how to that. thakns
there!
Actually, what you need to do is set right position for groups.
var data = [0,1,2,3,4]; // example data
var selection = svg.selectAll('g').data(data).enter();
// set position for rects and texts using transform-translate
var groups = selection.append('g')
.attr('transform', function(d, i) { return 'translate(0,' + i * 35 + ')' });
groups.append('rect')
.attr('width', 100)
.attr('height', 30)
.attr('fill', 'white')
.attr('stroke', 'black'); // all rects
groups.append('text')
.text((d) => d)
.attr('font-size', '10px')
.attr('y', 15); // all texts
And an additional link for you, maybe it would be helpful.

Infographic conditional fill on custom SVG shapes

I want to create a kind of infographic where I can represent percentages intuitively using a kind of fill logic.
Example
For the sake of simplicity let's just assume intervals of 25%. For the task of 75% of households, there would be four houses in total and 3 of them would be filled in. The remaining house would remain fill:'none'.
I had something in mind like:
It would be in SVG form.
The only way I can think of to achieve this is pre-draw the houses as a collective image and link the file like:
var fileMap = { 50:'fifty.svg', 75:'seventy-five.svg'};
But this doesn't seem to be very modular, and it doesn't utilize d3 hardly.
Question: Is it possible/feasible to create a simple 25% interval conditional fill using d3 compatible logic? What would my .data() call expect? It has to be an array, maybe a binary:
var data = [1,1,1,0] //75%;
Maybe there's a better way altogether, but that's the best I have got.
"I want to create a kind of infographic where I can represent percentages intuitively using a kind of fill logic"... The technical name for this is pictogram.
For creating a pictogram you don't need anything special, you can use a common enter selection. So, given your data...
var data = [1,1,1,0]
... we will create one house for each array element...
var house = svg.selectAll(null)
.data(data)
.enter()
.append("path")
... and fill them according to the datum:
.style("fill", function(d){
return d ? "blue" : "white"
})
Here is a basic demo:
var d = "m787.67 1599.58l148.83 157.74 124.02-131.45v630.95h396.87 198.44 396.87v-630.95l124.02 131.45 148.83-157.74-768.94-814.97-768.94 814.97m1066.6-709.82v78.868l198.44 210.32v-289.18h-198.44z";
var svg = d3.select("svg");
var data = [1, 1, 1, 0];
var house = svg.selectAll(null)
.data(data)
.enter()
.append("path")
.attr("d", d)
.attr("transform", function(_, i) {
return "translate(" + (i * 70) + ",100) matrix(.04 0 0 .03-4.159-50.852)"
})
.style("stroke", "black")
.style("stroke-width", "50px")
.style("fill", function(d) {
return d ? "blue" : "white"
})
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>

How can i bring gridlines to the front?

In d3 graphs, how can i bring gridlines to the front or back of the bars. Which parameter is responsible for the same?
Sample working fiddle
The code for ticks is:-
var yAxisGrid = yAxis.ticks(numberOfTicks)
.tickSize(w, 0)
.tickFormat("")
.orient("right");
There is nothing similar to the z index (http://www.w3schools.com/cssref/pr_pos_z-index.asp) in SVG.
So, your question:
Which parameter is responsible for the same?
Has the answer: none.
That being said, this is the rule: who's painted later remains on top (just like a real painter using ink in a canvas).
So, just move the code for the circles to be before the code for the gridline.
//create the circles
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
/)...
//draw axes here
svg.append("g")
.attr("class", "axis") //assign "axis" class
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
//...
This is your updated fiddle (I made the circles larger): http://jsfiddle.net/e4L7sn37/

How to limit the text of polygons in Voronoi diagram with D3.js?

I've see the Example of D3.js-Voronoi Tessellation.But I want to put some text in each of polygons instead of a circle,Here is my js code:
var width = 600, height = 400;
var vertices = d3.range(20).map(function(d){
return [Math.random() * width, Math.random() * height]
});
var voronoi = d3.geom.voronoi();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
path = svg.append("g").selectAll("path");
svg.selectAll("info")
.data(vertices.slice(1))
.enter().append("text")
.attr("transform", function(d) {
return "translate(" + d + ")";
})
.text("someText")
.attr("shape-rendering","crispEdges")
.style("text-anchor","middle");
redraw();
function redraw(){
path = path
.data(voronoi(vertices), polygon);
path.exit().remove();
path.enter().append("path")
.attr("class", function(d, i) {return "q" + (i % 9) + "-9";})
.attr("d", polygon);
path.order();
}
function polygon(d){
return "M" + d.join("L") + "Z";
}
I have a JSFiddle for that basic example here:
my voronoi code
now, I want each of the polygons' text in the center of the polygon, and don't cross with the polygon's border. If the polygon have not enough space to contain the all text, just contain the first part of it!
Let me know if there is anything I can do to solve this issue, thank you!
PS:I'm so sorry to my English, yes, it's so poor! :)
Have a look at this example http://bl.ocks.org/mbostock/6909318 , you probably want to place the text at the polygon centroid and not the seed (point) used to determine the voronoi tessellation.
That should fix the majority of your layout issues.
Automatically scaling the text to fit is a little bit harder, if you are willing to scale and rotate the text you can use a technique similar to the following to determine the length of the line at that point:
https://mathoverflow.net/questions/116418/find-longest-segment-through-centroid-of-2d-convex-polygon
Then you need to determine the angle of the line. I have a plugin that should help with that:
http://bl.ocks.org/stephen101/7640188/3ffe0c5dbb040f785b91687640a893bae07e36c3
Lastly you need to scale and rotate the text to fit. To determine the width of the text use getBBox() on the text element:
var text = svg.append("svg:text")
.attr("x", 480)
.attr("y", 250)
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.style("font", "300 128px Helvetica Neue")
.text("Hello, getBBox!");
var bbox = text.node().getBBox();
Then you use the angle you calculated earlier to scale and rotate your text:
text.attr("transform", "rotate(40) scale(7)")
I would love to give a complete example but this is quite a bit of work to get it right.
There are other options to achieve the same effect but none of them are simple (ie you could anneal the layout similar to the way d3 does the Sankey layout)

D3: How to access an attribute of a previous item

I am using D3 to plot a rectangle for each object in an array, the height of the rectangle being dependant on the 'Size' property of the object. These rectangles are stacked on top of each other. I currently set the y position by summing the 'Size' of each subsequent rect that gets plotted - but this seems wrong - and I was wondering if there was a better way to do this, such as accessing the 'y' attribute of the previous item (and how?) or another way...
This is what the essence of my code looks like. There is a link to the fiddle below.
var cumY = 0;
var blocks1 = sampleSVG.selectAll("rect")
.data(fpp)
.enter()
.append("rect")
.sort(SortBySize)
.style("stroke", "gray")
.style("opacity", blockOpacity)
.style("fill", function (d) {return d.Colour})
.attr("width", 80)
.attr("height", function (d) {return d.Size})
.attr("x", 5)
.attr("y", function (d, i) {
var thisY = cumY;
cumY += d.Size;
// perhaps I could just return something like d.Size + previousItem.GetAttribute("y") ???
return thisY;
});
http://jsfiddle.net/ninjaPixel/bvER3/
This is tricky do! You're right that keeping track of the cumulative height 'seems wrong' - it works now but it isn't very idiomatic d3 and will get pretty messy once you start trying to do something more complicated.
I would try using d3's built in stack-layout which was created solve this problem. You might want to start working off of this example and posting an updated fiddle if you get stuck. Good luck!

Resources