D3 Ordinal Scales with Scatter Plot - d3.js

I'm attempting to use D3 to produce a scatter plot where the x-axis is ordinal. You should be able to see a small exmaple of this at : http://plnkr.co/edit/c7iy6T?p=preview
My first order question is : How would I shift the "clusters" over so they they are situated on top of the ordinal labels.
My second order question is : if I had the json
{x : 1.1, y : 1.9 ,label : foo}
{x : .9, y : 2.2 ,label : foo}
{x : 2.1, y : 1.2 ,label : bar}
{x : 1.9, y : 5.3 ,label : bar}
What would be the most idiomatic way to have that displayed in scatterplot so that the labels would essentially be situated over the integer values 1,2 while the data is plotted as one would with a linear scale scatterplot.
Edit:
My second question concerns the following. I can have M clusters, for cluster m i know that the x coordinate will be "centered" around the integer m. Like above all all the foo values were closer to 1 than any other integer. I want to be able to pass in a structure like above. And have the output be a typical x-y plot but where the integer ticks have been suppressed and only the labels appear.
Lars, answer below does center my values, but it also seems to ignore any other scale and compress the x-values into what appears to be a line. This is visible at : http://plnkr.co/edit/ncANkH?p=preview. Lars solution would be ideal but for the compression problem.

Regarding your second question (if I understand it correctly), you can use the same kind of logic that is generally used to make grouped charts (as per this example). Basically you will create two X scales, one to arrange internally the dots of each scatterplot, and another to arrange the scatterplots themselves on the stage.
The range of the wrapper (ordinal) scale will be the width of the stage, whereas the range of the internal (linear) scale will be x.rangeBand(). You will draw each individual scatterplot and transform each of them individually according to the wrapper scale.
To do this, your data will need to be in a more organized format such that each individual scatterplot has its own object. I've made this Plunk that I think achieves what you want. (It's a bit ugly, but the Plunk site was unbearably slow for me so I gave up on aesthetics.)
There are two things you may want to note about how this was achieved. First, I rearranged your data into this format:
var data = [
{
name: 'baby',
values: []
},
{
name: 'adult',
values: []
},
{
name: 'youth',
values: []
}
]
Second, I bound this top-level data to draw three SVG g groups, then used a key function to bind the second-level data to the circles, like so:
dotGroups.selectAll('.dot')
.data(function(d) { return d.values; })
Hope that helps.

Related

d3 floating grouped bar with ranged values in a timeline

im trying to understand what tools i need to use as im new to d3 and didnt find any thing related...
i need a area chart that is like bars but can float and be on multiple values both on the x and y axis.
in this example the values are days but it might be hours/months etc...
need to know the direction i need to go.. / the right term to search...
There's no significant difference between drawing this chart and a normal bar chart.
And you need to define some scales that will map the values in your data to co-ordinates on your chart.
You need to draw some rect shapes.
So, in the above example you would define a time scale that, given an input date, will map that to a certain x co-ordinate on your chart. You can then use that to determine both the x co-ordinate for where the left-hand-side of a rectangle will be, and to work out how wide the rectangle needs to be.
const xScale = d3.scaleTime()
.domain([d3.min(dateValuesInMyDataset, d => d.date), d3.max(dateValuesInMyDataset, d => d.date)])
.range([0, widthOfMyChart]);
The above xScale if given the earliest date in your dataset would return the value 0, because this is the x co-ordinate representing that date.
Similarly, you would want to construct a linear scale which defines how to map the numerical range of values in your dataset, to the y co-ordinates in your chart. Then you can use the scale to determine the y value and height of all of the rectangles in your chart.
There are lots of good examples of this on ObservableHQ.com that you can browse and see the code for.

D3.js breaking up overlapping shapes

I'm trying to create a chart, where the input is a list of circles (position and radius) (or better ellipses) and the overlaps of the circles become shapes and a mouseover event can be applied. I also wish for the circles to move to the front, and have a mouseover effect, almost exactly like this
http://benfred.github.io/venn.js/examples/intersection_tooltip.html
The size of the overlap does not need to be known.
I've tried using D3.js Venn diagrams by Ben Frederickson. Although I can't understand some of the chart(selection) function, I've made it so that the circles can be inputted, and are drawn fine, including the overlaps, but this still relies on having the 'data' as an input as well and all of the sets (seen in the jsonp file) are still require. I realise that I can just make a script to list all of the possible sets, but this is ideal.
http://www.benfrederickson.com/venn-diagrams-with-d3.js/
I'm struggling to understand how the code creates these overlaps and then assigns them to the set.
Cheers, Ryan
Each intersection area has an SVG path computed for it by the 'venn.intersectionAreaPath' function. It takes a list of circles and returns a path element for the intersection area.
If you already have positions for the circles, you can override the 'layoutFunction' attribute on the venn diagram object like:
var circles = [{'x' : 0, 'y': 100, 'radius' : 80},
{'x' : 0, 'y': 0, 'radius' : 90 },];
var chart = venn.VennDiagram().layoutFunction(function() { return circles; });
d3.select("#venn").datum([{sets: [0]}, {sets:[1]}, {sets:[0,1]}]).call(chart);
This still requires having a list of all possible regions that you wish to draw (like "[{sets: [0]}, {sets:[1]}, {sets:[0,1]}]"), but this way you don't need to specify sizes for the regions.

Time axis: Remove scale points with no data

I have a dataset which I am plotting. I've modelled it as a network, and have used a force-directed layout to display it, except that I have constrained the layout such that on the x-axis, the nodes are arranged according to time.
An example of what I've done so far is here on my own website: http://www.ericmajinglong.com/force/force.html
As you can see, I have one time axis. The axis scale is derived from the data. However, you'll notice a big gap in the middle.
I understand the concept of scales, where I have a domain and a range, and a scale basically maps the domain to the range. I have a few questions, however.
I was wondering if it might be possible, without creating two horizontal time axes, to exclude empty months?
Instead of an linear scale, would I have to go to an ordinal scale?
Would there be any disadvantages to going to an ordinal scale instead of a time scale?
Code is not posted here for brevity, but I have it at: http://www.ericmajinglong.com/force/force.js
You can probably use an ordinal scale, but in that case you should make sure that the domain is sorted, and add some mark between the two intervals so the user of the visualization understand that there is a a period not shown. Another option is to create a custom scale that automatically shorten gaps in the data, but will still to add special markers to indicate missing time periods.
If you use an ordinal scale instead of a time scale, you will need to format the axis manually.
EDIT: Add a small example of how a custom scale may be implemented
I would implement a custom scale as a closure with accessors.
function customScale() {
// Scale attributes
var domain = [0, 1], // Default domain
range = [0, 1]; // Default range
function scale(x) {
var y = 0;
// Compute the output value...
return y;
}
// Domain and Range Accessors
scale.domain = function(value) {
if (!arguments.length) { return domain; }
domain = value;
return scale;
};
// range accessor...
return scale;
}
And then configure and use the scale
var scale = customScale()
.domain([0, 10])
.range([2, 3]);
console.log(scale(5));
Using a custom scale will probably implies to create custom axis as well.

generating vertices for voronoi diagram in d3js

In the two examples in d3js website:
Easy Version
More complicated
I find some of their code hard to understand. The D3 reference API did not offer in depth explanation. In the easy version, the vertices were generated using Math.random() like so:
var vertices = d3.range(100).map(function(d) {
return [Math.random() * width, Math.random() * height];
});
Width and height are the document size. This ensure all vertices are within the scope of the SVG element ( svg tag has width and height attribute set to these values too).
However in the more complicated version, it uses an algorithm to generate the vertices:
var vertices = d3.range(numVertices).map(function(d) { return {x: d.x, y: d.y}; })
voronoiVertices = vertices.map(function(o){return [o.x, o.y, o]})
path = path.data(d3.geom.voronoi(voronoiVertices))
When examining the variable vertices in console. I found out that it is a two dimensional array. Each sub-array has a length of 3, first and second element are numbers, and the last element is an object which contains a lot more properties like x, y and index and so on.
The resulting Voronoi diagram are very different. Why is that? They are both generated using d3.geom.voronoi() and (from what I can hopefully understand) the only differences lies in the object that is passed into it. In the easy example it was simply a two dimensional array with 2 numbers in each sub-array. I cannot seem to see how the two lines in the complicated example works to create such a complex object and append it to the end of each sub-array.
How is it ensured that the veritices are within the bound of the parent SVG element too?
I am really stuck, thank you so much for any help.

D3's scale not working properly

Well, I'm starting with D3 and I'm trying to create a vertical bar chart.
I really don't know what's happening but some things are not working as expected for me (maybe because I'm just a noob on the matter).
I'm using line scales, works pretty well with axes, but it's miscalculating the height of the bars, for instance the higher values are not displayed (because of the low value of the result).
I've used the d3.max to determine the range. I really don't get what's happening.
var yScaleLeft = d3.scale.linear()
.domain([0, d3.max(stats)])
.range([realHeight, 0]);
.attr("height", function(d) {
return yScaleLeft(d);
});
Here is the code: http://jsfiddle.net/aKhhb/ Look at * Scales * and // Stats bars
(Just forget about the x-alignement of the bars, I will see that later, I want to set its height properly)
Thanks a lot! Y saludos desde Chile :)
The issue is that your input and output ranges are mirrored -- that is, the largest input value maps to the smallest output value. That is fine, but you need to take it into account when calculating the y and height attributes. Essentially, you had the calculations for both reversed.
Fixed fiddle here. I've also fixed the x axis by adding your margin and half of the bar width to the computed x positions. Oh and you don't need parseInt() when doing calculations, only when you actually want to parse an integer from a string.

Resources