Plot the top X values in DCjs (not grouped/value counted) - dc.js

I'd like to plot the top X values of a dimension in a row chart, ideally labeled using one dimension but using the value of another for the size of the bars.
Essentially a presentation of data like the following:
Sally: 1
Fred: 0.7
Bob: 0.5
Francis: 0.4
George: 0.2
Sam: 0.18
Susan: 0.16
Sarah: 0.15
Tom: 0.15
Simon: 0.14
...
rowChart1 = dc.rowChart('#id')
valDim = ndx.dimension(function(d) {return d.data});
valGroup = valDim.group().reduceCount();
rowChart1.dimension(valDim).group(valGroup);
Plots the value counts, rather than the values themselves.
Specifically I'm looking to make a rowChart of the top N data points, where the length of the bars is determined by the value of the data points, not the number of data points with that value.
I.e. Sally would have her own bar, and it would be 100% of the x-axis, while Fred's bar would be 70% and Simon's bar would be 14% of the x-axis.

If I understand your question correctly, the conceptual problem may be the distinction between the crossfilter definition of dimension, which means "a column that you bin and filter on", versus the English/math definition of the word, which might mean "any column of data" or might mean a geometric direction on a chart.
There's always at least one geometric "dimension" on every chart which is not associated with a "crossfilter dimension" because it is aggregated. In a line chart Y is driven by a group reduction/aggregation; in the row chart X is.
I understand you have a column in your data which is a unique key, say name, which you want to map to the row Y axis, and you have a second column x, which you want encode in the row X axis without aggregation. You can use crossfilter's group.reduceSum() and since only one record will land in each bin, the sum of x is just x.
Since name is a unique key, there will be only one x per name.
Let's say you have data like this:
const data = [
{name: 'Sally', x: 1},
{name: 'Fred', x: 0.7},
{name: 'Bob', x: 0.5},
{name: 'Francis', x: 0.4},
{name: 'George', x: 0.2},
{name: 'Sam', x: 0.18},
{name: 'Susan', x: 0.16}
// ...
];
Then the crossfilter initialization might look like this:
const xf = crossfilter(data),
dim = xf.dimension(d => d.name), // bin and filter on this
group = dim.group().reduceSum(d => d.x); // here be values
and chart
const rowChart = dc.rowChart('#row');
rowChart
.dimension(dim)
.group(group)
.render();
Demo fiddle
This might sound really complicated if you just want to plot x against some names, but dc.js and crossfilter are optimized for the case where there will be filtering between charts. No matter what they draw, crossfilter will always filter the rows, sort the rows into buckets, and reduce those buckets.
If you don't use filtering, then these libraries are overkill. But if you do want to filter, it's really nice to have a library with a data model that takes care of it.

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 Plus bar chart how to force fixed max y axis range independent of the max data value

I would like to compare 2 d3Plus bar charts, next to ech other, and for that I need that both charts have the same max y value (let's say 1000 even if max data value of the first chart is 700, and max data value of the second is 550).
Thanx in advance.
Use the "range" property of each chart's y-axis:
.y({range: [0, 1000]})
For reference, here is the documentation for all of the properties for an axis: https://github.com/alexandersimoes/d3plus/wiki/Visualizations#x

DimpleJS. Y axis values in percentages

I am plotting Vertical Grouped Bar Chart from a csv file which contains Discount, Rating and Clicked. The data is csv is like 55,2,1 and 40,5,0 etc. Here the first value(55,40) are the discounts, (2,5) rating and 1 and 0 correspond to clicked and not clicked respectively. On plotting the chart with following code.
var svg2 = dimple.newSvg("#discountContainer", 590, 400);
d3.csv("/svm1000.csv", function (data) {
var myChart2 = new dimple.chart(svg2, data);
myChart2.setBounds(60, 30, 510, 330)
myChart2.addCategoryAxis("x", ["rating", "action"]);
var y = myChart2.addMeasureAxis("y", "discount");
//y.tickFormat = "%";
myChart2.addSeries("action", dimple.plot.bar);
myChart2.addLegend(65, 10, 510, 20, "right");
myChart2.draw();
});
The problem is I want to represent y axis in percentage in multiple of 10, like 0%, 10%, 20% .. 100%. Right now the y axis values are like 0,2k,4k,6k...20k. So how to represent y axis in percentage.
I see this question is old, so this answer may not help you, but for others facing similar requirements this might be helpful.
dimple.js provide method to have percentage series
myChart2.addPctAxis("y", "discount");
but remember you can't create both Value and Percentage in same axis, you might need to have dual axis graph
var x = myChart2.addCategoryAxis("x", ["rating", "action"]);
var y1 = myChart2.addPctAxis("y", "discount");
var y2 = myChart2.addMeasureAxis("y", "amount"); // the field with value ranges 1000...
also you don't able to use grouped bar chart; for axis 1 use bar chart and for axis 2 use line or vice versa like
myChart2.addSeries("action", dimple.plot.bar, [x, y1]);
myChart2.addSeries("action", dimple.plot.line, [x, y2]);

Display different values on axis than those found by the scale function in D3

I have a d3 graph that uses a linear scale for its x axis. It looks something like this:
...
y |
|
+-------------------------------------------
0.0 0.5 1.0 1.5 2.0 2.5 3.0
Time in weeks
Beneath this axis I want to display rows of data aligned to the x axis. Like this:
23 23 22 19
Using this data:
var nums = [23, 23, 22, 19];
var times = [0, 0.5, 1.5, 3];
times are where the nums should fall on the Time in weeks x axis. So the first index of nums falls under 0.0, the second under 0.5, and so on.
The scale function looks something like this:
var x = d3.scale.linear().domain([0,3]).range([0, 600]);
So x(0.5) returns the correct range value for displaying a tick on the new axis. But what I want to display is the corresponding value from the nums array. That is, display the value of nums[times.indexOf(0.5)].
Is there a way to override scale() as used by d3.svg.axis() so that it displays nums values instead of times values while still using times as the input domain?
Edit
Here is a demo
Edit 2
I figured it out thanks to ne8il's answer. The answer was not complete, but it formed the basis for this code:
var x1Axis = d3.svg.axis()
.scale(x1)
.ticks(nums)
.tickValues(times)
.tickFormat(function(x){return nums[times.indexOf(x)];})
Working example
I believe in this case you can do
d3.svg.axis().ticks(times).tickValues(nums);
It will pass each 'time' into your scale function to map it to an x coordinate, and use the corresponding indexed value in 'nums' to output text.
Source is here

D3 Ordinal Scales with Scatter Plot

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.

Resources