How to use scatter chart with complex data? - javascript

I trying to implement scatter chart by example.
In example we can see creating dimension:
runDimension = ndx.dimension(function(d) {return [+d.Expt, +d.Run]; });
Example's data:
Expt Run Speed
1 1 850
1 2 740
1 3 900
I want to use same chart, but I have my data in next format:
[
{
"Timestamp":"2016-12-15T17:29:53Z",
"idgame":"euro",
"users":{
"Jo": {
"energy":200,
"jump_height":0.5
},
"Bob": {
"energy":220,
"jump_height":0.35
}
}
},
{
"Timestamp":"2016-12-15T17:29:55Z",
"idgame":"euro",
"users":{
"Jo": {
"energy":120,
"jump_height":0.15
},
"Bob": {
"energy":240,
"jump_height":0.75
}
}
}
]
I need to build next chart, where x-axis is timestamp and y-axis is jump_height:
My data is allready in crossfilter, so I can't change it.
How can I create good dimension with current format?

I'm still not convinced this is worth the effort, versus biting the bullet and flattening your data and fixing up the other charts. If your data isn't flat you will be fighting crossfilter and dc.js every step of the way.
That said, as usual, it's possible!
We can't use the series chart, because that requires all the data to be present in one group. But since you want to produce multiple symbols from each row of data, an ordinary crossfilter group can't produce the data you need.
Maybe we could use a fake group, but that would be complicated. Instead, let's produce a dimension and group for each user, and then sew them together using a composite chart.
First, we need to parse those timestamps:
data.forEach(function(d) {
d.Timestamp = new Date(d.Timestamp);
});
Next, we'll retrieve a list of all users, by pulling the user keys from each event (timestamp), concatenating them, and then using a d3.set to unique them:
// retrieve all users from all events
var users = data.reduce(function(p, event) {
return p.concat(Object.keys(event.users));
}, []);
users = d3.set(users).values();
In the rest of the code, we'll assume there are the same users for each event. It's possible for them to be different, but it adds extra complexity, and this answer is complicated enough. Just ping me me if you need that feature!
We'll create the chart, crossfilter, and a scale which will assign symbols to users:
var chart = dc.compositeChart("#test");
var ndx = crossfilter(data);
var symbolScale = d3.scale.ordinal().range(d3.svg.symbolTypes);
Now we can create the composite chart. (We'll add the scatter subcharts in the next step.)
chart
.width(768)
.height(480)
.x(d3.time.scale())
.xUnits(d3.time.seconds)
.elasticX(true)
.elasticY(true)
.brushOn(false)
.clipPadding(10)
.shareTitle(false) // allow default scatter title to work
.shareColors(true) // but use different colors for subcharts
.legend(dc.legend().x(350).y(350).itemHeight(13)
.gap(5).horizontal(1).legendWidth(140).itemWidth(70));
We set up the X axis with a time scale, with a resolution of seconds. Both axes have elastic. We need to share colors so that each subchart will be assigned its own color. (The legend is perhaps overspecified - I copied this from another example.)
Finally we get to the meat of it. For each user, we'll create a subchart, and we'll tell the composite chart to compose all of them:
chart.compose(users.map(function(user) {
var userDimension = ndx.dimension(function(d) {
return [d.Timestamp, d.users[user].jump_height];
})
var jumpGroup = userDimension.group();
console.log(user, jumpGroup.all());
var scatter = dc.scatterPlot(chart)
.symbol(symbolScale(user))
.dimension(userDimension)
.group(jumpGroup)
.colorAccessor(function() { return user; })
.symbolSize(8)
.highlightedSize(10);
return scatter;
}))
We're creating a new dimension for each chart. This is because the dc.js scatter plot expects the keys to include both X and Y coordinates, and we can only access the Y coordinate (jump_height) once we know the user. Once we get past that, the group is simple.
The chart will assign the symbol and color based on the user key. These both work the same; an ordinal scale will assign a new value from the range for each new value it encounters in the domain. The only difference is that we're using the default color scale, whereas we had to specify our own symbol scale.
Here's a fiddle: https://jsfiddle.net/gordonwoodhull/3m4mv3xf/19/

Related

Chart JS - Points and Tooltips Only at Specific Data Values

I am currently using chart.js to plot spectral data from a EMI receiver. There are over 16000 (x,y) data indexes within each dataset and therefore I have made it so only the lines show without any points.
I now have a list of a few certain (x,y) value pairs that I would like to put points/markers on and add tooltips for. Is there a way to add tooltips and/or points or markers to only certain (x,y) value pairs within each dataset?
Any help would be appreciated. I will update with any photos/code if needed as I currently do not have an attempt at a solution for this.
EDIT1:
As you can see, it is very difficult to select the maximum point of the peaks due to how many data points make up the chart. I want to select only the local maximums and display tooltips for those points.
options.elements.point has a prop called radius. Radius can take either a number or an array of numbers. A single number will determine the radius for all of the points in your chart but the array will be able to determine each element's radius. This way you are able to selectively determine each point's radius with full control.
A solution for your example might look like this:
const options = {
elements: {
radius: allPoints.map(point => {
const maxPoint = Math.max(allPoints)
// return radius 0 for every point that is not the max and radius 1 (or bigger if needed) for the maximum point
return point == maxPoint ? 1 : 0
})
}
}

D3 Dimple - group small data series in "others" category

I have a pie chart made in dimple, however the there is large amount of extremely small sections that makes the graph unappealing. Is there a d3 or dimple function that will allow me to group this uninteresting data in a single category?
without seeing your code and data it is hard to provide a concrete example that matches exactly what you are doing. this can be done before using d3 or dimple by filtering and reducing your values in a few lines of code. Say your items have a label and a value and are in an array called "all_items". You will need to set a threshold value.
const threshold = 100;
big_items = all_items.filter(item => item.value > threshold);
small_items = all_items.filter(item => item.value <= threshold);
collected_value = {
label: `other - ${small_items.length} items`,
value: small_items.reduce((accumulator, item) => accumulator + item.value, 0)
}
big_items.push(collected_value);
then you can create your chart using the big_items array. This doesn't automatically decide what threshold to use and do the work, which you might be looking for.

How to plot different line patterns for different lines in DC.js series chart?

This is the image of the chart that I have generated : Current Series Chart
I have applied the dashStyle function to the linechart object which has applied the same pattern to all the lines. I need to plot a series chart with each line having a different pattern(dashed, dotted, plane line etc). There are a lot of attributes in the "c" object in the chart function. I am not sure which attribute corresponds to data values. The data attribute of the "c" object has something like "_dc/dc.baseMixin/_chart.data()" I am new to javascript and dc js and do not entirely understand what is going on under the hood.
Is there a way to plot different patterns for different lines in line chart?
Here's my current code which was implemented after referring to this example : http://dc-js.github.io/dc.js/examples/range-series.html
focusChart
.width(920)
.height(380)
.chart(function(c) { console.log(c);return dc.lineChart(c).dashStyle([2,3]).interpolate('cardinal').evadeDomainFilter(true); })
.x(d3.scale.linear().domain([1995,2017]))
.brushOn(false)
.yAxisLabel("Topic Weight")
.xAxisLabel("Year")
.elasticY(true)
.dimension(series1Dimension)
.group(series1Group)
.colorAccessor(function(d){
return d.key.split(",")[0].slice(5);
})
.colors(TopicColorScale)
focusChart.seriesAccessor(function(d) {return " " + d.key[0];})
.keyAccessor(function(d) {return +d.key[1];})
.valueAccessor(function(d) {return +d.value;})
.legend(dc.legend().x(400).itemHeight(13).gap(1).horizontal(10).legendWidth(540).itemWidth(210));
focusChart.yAxis().tickFormat(function(d) {return d3.format('d')(d);});
focusChart.xAxis().tickFormat(function(d) {return d3.format('d')(d);});
focusChart.margins().left += 20;
Any help would be much appreciated!
The line
.chart(function(c) { console.log(c);return dc.lineChart(c).dashStyle([2,3]).interpolate('cardinal').evadeDomainFilter(true); })
provides the function that generates subcharts. The parameters to this function appear to be undocumented, but a quick look at the source reveals
var subChart = _charts[sub.key] || _chartFunction.call(_chart, _chart, chartGroup, sub.key, i);
that the function takes the following parameters:
the composite chart
the chart group where the composite chart is registered
the key for the subchart
the index for the subchart
It's that third argument that you want. It's the key returned by your seriesAccessor, and you can use whatever method you want to set the dashStyle based on that key.

dimple.js plots the wrong values

We are trying to develop a chart which plots a weather file with its corresponding relative humidity and temperature values. So far the chart generates itself correctly, and plots the current weather data based on your location, but it does not plot typical yearly weather data for the current location.
The correct array is written to console, but when handed to dimple to plot, the data that ends up on the chart is not the same as the data logged in console. it is usually significantly higher.
We are having trouble with the code starting on line 171.
See below link:
http://jsfiddle.net/jamesrowse/bnq419qx/1/
This could be a problem with a conflict between d3.csv and dimple, or dimple being handed such a large number of points to plot.
It is just the function starting from line 171 ending on line 193 that is giving us issues:
d3.csv("http://psychrometric.s3-website-us-east-1.amazonaws.com/HourlyWeatherFiles/GBR_London.Gatwick.037760_IWEC.csv", function (data) {
// console.log(data);
var hourlydata = [];
for (var i = 0; i < data.length; i++) {
//console.log(data[i]);
var rh = parseFloat(data[i].rh);
var dbt = parseFloat(data[i].dbt);
hourlydata.push({
"Relative Humidity": rh,
"Dry-Bulb Temperature": dbt,
"Moisture Content": psy.convert(rh, dbt, "rh", "w")
});
}
console.log("*********************************");
console.log(hourlydata);
var hourlySeries = myChart.addSeries("Relative Humidity", dimple.plot.bubble, [xAxis, yAxis]);
hourlySeries.data = hourlydata;
hourlySeries.radius= 3;
drawChart();
});
Any help would be appreciated
It is aggregating your series. It appears the default aggregation is to sum all records whenever the x-axis values match before displaying. You can override that behavior by defining an aggregation on your series as described here: https://github.com/PMSI-AlignAlytics/dimple/wiki/dimple.series#aggregate
Another thing you might want to explore is the 'stacked' option, though that doesn't appear to help for reasons I can't understand at the moment: https://github.com/PMSI-AlignAlytics/dimple/wiki/dimple.series#stacked

dc.js bar chart with ordinal x axis scale doesn't render correctly

I've recently discovered dc.js and have been trying to implement a simple bar chart using the bar chart example provided on d3.js's website: http://bl.ocks.org/mbostock/3885304.
However, as part of dc.js implementation, a crossfilter dimension and group is required.
So using a simple TSV file with "letters" and "frequencies", I've changed the code a bit to look as follows:
d3.tsv('testdata.tsv', function(error, data) {
var cf = crossfilter(data);
var dimension = cf.dimension(function(d){
return d.letter;
}
var group = dimension.group().reduce(
function(p,v){
p.frequency += v.frequency
},
function(p,v){
p.frequency -= v.frequency
},
function(){
return { frequency: 0 };
});
I'm a little confused about what I should be setting the valueAccessor to (on my bar chart), because when I set the valueAccessor to return "frequency", and I set my xAxis scale to ordinal with a domain of all "letters" in the data set, I get a rendered bar graph with almost all x-axis values ("A - Y") at the ZERO point and one x-axis value (i.e. "Z") at the end of the x-axis line.
I've tried setting the ranges, but it doesn't seem to do the trick. Any ideas on what I'm misunderstanding would be greatly appreciated!
Turns out I had to set the .xUnits property to dc.units.ordinal() in order to get the x-axis spaced out correctly!

Categories