dc.js scatter plot where y is count of category and value x - scatter-plot

trying to figure out dc.js scatter plot and getting hung up on structuring the inital data for it I think
var data = [
{ category: 'A', processVersion: 6},
{ category: 'A', processVersion: 6},
{ category: 'A', processVersion: 8},
{ category: 'A', processVersion: 7},
{ category: 'A', processVersion: 6},
{ category: 'A', processVersion: 7},
{ category: 'A', processVersion: 6},
{ category: 'A', processVersion: 7},
{ category: 'B', processVersion: 6},
{ category: 'B', processVersion: 8},
{ category: 'B', processVersion: 8},
{ category: 'B', processVersion: 7},
{ category: 'B', processVersion: 8}
];
var cf = crossfilter(data);
var dim = cf.dimension(function(d){ return [d.category, d.processVersion]; });
var grp = dim.group();
var scatterChart = dc.scatterPlot("#scatter-chart");
scatterChart
.width(500)
.height(300)
.margins({
top: 10,
right: 20,
bottom: 30,
left: 40
})
.dimension(dim)
.group(grp)
.x(d3.scale.linear().domain[0, 10]) // for each process version
.y(d3.scale.linear().domain[0, 10]) // want count of records where categorys are like
.renderHorizontalGridLines(true)
.renderVerticalGridLines(true)
.symbolSize(30)
.highlightedSize(8)
scatterchart.render();
What I want is to have the y as a count of each record that shares a given category per a given service version(x axis). So I have tried getting a count function into the initial dimesion array, or processing the data before hand which seems unnecessary because I am guessing there is a proper way to do that in crossfilter? the group result should have a key = [5, 3, "A"] I think where [0] is the processVersion, [1] is the count, etc.
Appreciate the assistance.

Related

Dart: What is the proper way to sum up items in a list of Maps?

I am trying to figure out what is the best way to sum up all the same item's quantities specifically the data is formed like below:
data = [
{Item Name: Item 2, Quantity: 1},
{Item Name: Item 1, Quantity: 1},
{Item Name: Item 3, Quantity: 1},
{Item Name: Item 2, Quantity: 2},
{Item Name: Item 1, Quantity: 2},
{Item Name: Item 3, Quantity: 2},
];
and what I am trying to achieve is:
totalList = [{Item Name: Item 1, Quantity: 3}, {Item Name: Item 2, Quantity: 3}, {Item Name: Item 3, Quantity: 3}];
I have tried using a tempData variable to hold onto the element and compare the rest however, this seems like it only compares that first one to the rest of the list.
var tempData = {};
var totalList = [];
data.forEach((element) {
if (tempData.isEmpty) {
tempData = element;
totalList.add(tempData);
} else {
if (tempData['Item Name'] == element['Item Name']) {
tempData['Quantity'] = tempData['Quantity'] + element['Quantity'];
totalList.add(tempData);
} else {
tempData = {
'Item Name': element['Item Name'],
'Quantity': element['Quantity']
};
totalList.add(tempData);
}
}
});
The above didnt seem to give me the output I was looking for...
What should I do instead?
Thanks for your help in advance.
Your data structure is not pretty; the 'Item Name' and 'Quantity' labels not very useful in the structure itself, so I would get rid of them and create a simplified Map<String, int> that directly maps names to quantities. Ideally you could just use the simplified structure from then on, but if you really need the explicit labels, you could convert back.
void main(List<String> args) async {
var data = [
{'Item Name': 'Item 2', 'Quantity': 1},
{'Item Name': 'Item 1', 'Quantity': 1},
{'Item Name': 'Item 3', 'Quantity': 1},
{'Item Name': 'Item 2', 'Quantity': 2},
{'Item Name': 'Item 1', 'Quantity': 2},
{'Item Name': 'Item 3', 'Quantity': 2},
];
// Sum everything into a simpler data structure.
var totalCounts = <String, int>{};
for (var map in data) {
var name = map['Item Name'] as String;
var quantity = map['Quantity'] as int;
totalCounts[name] = (totalCounts[name] ?? 0) + quantity;
}
// Reformat back into the original structure.
var totalList = <Map<String, dynamic>>[
for (var entry in totalCounts.entries)
{'Item Name': entry.key, 'Quantity': entry.value},
];
// Optional: Sort.
totalList.sort((a, b) => a['Item Name'].compareTo(b['Item Name']));
print(totalList); // Prints: [{Item Name: Item 1, Quantity: 3}, {Item Name: Item 2, Quantity: 3}, {Item Name: Item 3, Quantity: 3}]
}
In real code, I additionally would add:
const nameLabel = 'Item Name';
const quantityLabel = 'Quantity';
and use those everywhere instead of the string literals to reduce opportunities for making typos.
I have created the following solution which are not that pretty but it works. The concept is to create a Map<String, Map<String, Object>> which keep track of elements we already have visited by using the "Item Name" of each element as key.
void main() {
final data = [
{'Item Name': 'Item 2', 'Quantity': 1},
{'Item Name': 'Item 1', 'Quantity': 1},
{'Item Name': 'Item 3', 'Quantity': 1},
{'Item Name': 'Item 2', 'Quantity': 2},
{'Item Name': 'Item 1', 'Quantity': 2},
{'Item Name': 'Item 3', 'Quantity': 2},
];
final result = [
...data.fold(
<String, Map<String, Object>>{},
(Map<String, Map<String, Object>> sum, element) => sum
..update(
element['Item Name'] as String,
(value) => value
..update('Quantity',
(value) => (value as int) + (element['Quantity'] as int)),
ifAbsent: () => Map.from(element))).values
];
result.sort(
(a, b) => (a['Item Name'] as String).compareTo(b['Item Name'] as String));
print(result); // [{Item Name: Item 1, Quantity: 3}, {Item Name: Item 2, Quantity: 3}, {Item Name: Item 3, Quantity: 3}]
}

How to allow Duplicate Tick Labels in Plotly?

I observed that while providing duplicate ticklabels (with an aim to mention the class of categorical variable), plotly creates a unique set and displays only the non-repeated tick labels. Is there a way to by-pass this feature and allow duplicate tick-labels?
var data = [
{
z: [[1, 20, 30, 50, 1], [20, 1, 60, 80, 30], [30, 60, 1, -10, 20]],
x: ['Healthy', 'Healthy', 'Moderate', 'Diseased', 'Diseased'],
y: ['Morning', 'Afternoon', 'Evening'],
type: 'heatmap'
}
];
Plotly.newPlot('myDiv', data);
Following is the jsfiddle depicting the issue:
https://jsfiddle.net/mam8sgwx/
Set the layout with ticktext:
var layout = {
xaxis: {
tickmode: "array",
ticktext: ['Healthy', 'Healthy', 'Moderate', 'Diseased', 'Diseased'],
tickvals: [0, 1, 2, 3, 4]
}
}
Here is the demo:
var data = [{
z: [
[1, 20, 30, 50, 1],
[20, 1, 60, 80, 30],
[30, 60, 1, -10, 20]
],
y: ['Morning', 'Afternoon', 'Evening'],
type: 'heatmap'
}];
var layout = {
xaxis: {
tickmode: "array",
ticktext: ['Healthy', 'Healthy', 'Moderate', 'Diseased', 'Diseased'],
tickvals: [0, 1, 2, 3, 4]
}
}
Plotly.newPlot('myDiv', data, layout);
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<body>
<div id="myDiv"></div>

Trying to create a grouped and stacked bar chart but having some trouble

I'm trying to create a grouped and stacked bar chart but having a little trouble understanding how to do this with c3js. This tutorial is great and shows me a nicely grouped chart.
http://blog.trifork.com/2014/07/29/creating-charts-with-c3-js/
I'm looking for something similar but to have those stacked 2 data sets per bar. My data looks like:
columns: [
['x', 'data1', 'data2'],
['Jan', {data1: 20, data2: 80}, {data1: 80, data2: 20}, {data1: 20, data2: 80}]
['Feb', {data1: 20, data2: 80}, {data1: 80, data2: 20}, {data1: 20, data2: 80}]
['Mar', {data1: 20, data2: 80}, {data1: 80, data2: 20}, {data1: 20, data2: 80}]
]
I would like the chart to have groups of Jan, Feb, Mar. Then have 3 stacked bars labeled within each group. Any ideas if this is possible and how might it be possible, if at all.
Thanks!
Are you wanting something like this? -->
http://jsfiddle.net/3r39gknt/1/
If so, the data1 and data2 fields will need renamed per the example. If not, draw/scan a picture/sketch of what you'd expect - groups in c3 are the data elements involved in each stack, but I've interpreted rightly or wrongly your use of month 'groups' as being different points on the x-axis.
var chart = c3.generate({
data: {
columns: [ // randomish data
['data1', 30, 200, 200],
['data2', 130, 100, 100],
['data3', 230, 220, 200],
['data4', 230, 220, 200],
['data5', 230, 200, 210],
['data6', 230, 190, 200]
],
type: 'bar',
groups: [
['data1', 'data2'],
['data3', 'data4'],
['data5', 'data6'],
],
order: null,
colors: {
data1: '#f00',
data2: '#00f',
data3: '#f33',
data4: '#33f',
data5: '#f66',
data6: '#66f'
}
},
bar: {
width: {
ratio: 0.5 // this makes bar width 50% of length between ticks
}
},
axis: {
x: {
type: 'category',
categories: ['january', 'february', 'march']
}
}
});

Ful length row Handsontable

I'm looking for a excel like table for my app then at my search I saw this Handsontable but one also of my requirements is groupings on the table.
Is it possible at Handsontable a ful length row like this?
I'm not sure what you mean by 'full length row' but a couple of options that may help you are:
Rendering custom html
This allows you to manipulate both the headers and cells. Example:
var $container = $("#example2");
$container.handsontable({
colHeaders: function (col) {
switch (col) {
case 0: //First column header
return "<b>Bold</b> and <em>Beautiful</em>";
case 1: //Second column header
var txt = "Some <input type='checkbox' class='checker' ";
txt += isChecked ? 'checked="checked"' : '';
txt += "> checkbox";
return txt;
}
}
});
or
Column stretching
This lets you stretch a column to fill the row to a 'full length row'. Example option to stretch the last column:
stretchH: 'last'
I think what your looking at is merging cells. It exists two different ways to merge cells with HandsonTable.
You can either directly specify the merges you want in the options:
hot = new Handsontable(container, {
data: myData,
rowHeaders: true,
colHeaders: true,
contextMenu: true,
mergeCells: [
{row: 0, col: 0, rowspan: 1, colspan: 4}, // for description
{row: 3, col: 4, rowspan: 2, colspan: 2}, // any other merges
{row: 5, col: 6, rowspan: 3, colspan: 3}
]
});
or create an array with all the merges and give it later to the table:
var mergeArr = new Array();
var descriptionMerge = {
row : 0,
col : 0,
rowspan : 1,
colspan : 4
}
mergeArr.push(descritpionMerge);
hot = new Handsontable(container, {
data: myData,
rowHeaders: true,
colHeaders: true,
contextMenu: true,
mergeCells: mergeArr
});
row: starting row of the merge.
col: starting col of the merge.
rowspan: number of rows that will be merged from the starting row.
colspan: number of cols that will be merged from the starting col.
In your case, you want a full length row, so you need to merge cells in this way :
{row: yourStartingRow, col: yourStartingCol, rowspan: 1, colspan: lengthOfYourTable}
HandsonTable documentation: http://docs.handsontable.com/0.15.1/demo-merge-cells.html
Bonus: If you want to center the text in your merged cells, just use the className : "htMiddle" option.
http://docs.handsontable.com/0.17.0/demo-alignment.html
If you want to group headers, you can used the nested headers to do this:
The code uses the "NestedHeaders" tag like so:
var example1 = document.getElementById('example1');
var hot = new Handsontable(example1, {
data: Handsontable.helper.createSpreadsheetData(5,10),
colHeaders: true,
rowHeaders: true,
nestedHeaders: [
['A', {label: 'B', colspan: 8}, 'C'],
['D', {label: 'E', colspan: 4}, {label: 'F', colspan: 4}, 'G'],
['H', {label: 'I', colspan: 2}, {label: 'J', colspan: 2}, {label: 'K', colspan: 2}, {label: 'L', colspan: 2}, 'M'],
['N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W']
]
});
See more on the handsontable documentation

Merge two hashes of hashes, without overlap

I have two hashes of hashes that look basically like:
sales = {
"2013-03-15": {sales: 5},
"2013-03-14": {sales: 3},
"2013-03-12": {sales: 8},
... }
and
views = {
"2013-03-15": {views: 30},
"2013-03-14": {views: 23},
"2013-03-13": {views: 35},
... }
How can I merge them into a single hash that looks like:
data = {
"2013-03-15": {views: 30, sales: 5},
"2013-03-14": {views: 23, sales: 3},
"2013-03-13": {views: 35, sales: 0}, # or just {views: 35}
... }
Basically, I need to keep the keys and all the data intact.
data = views.merge sales Seems to override all the views data, leaving me with basically just the sales hash.
Edit: I can also convert the sales or views hashes into simple hashes (not hashes of hashes), but I still don't know a good way to proceed.
This:
sales.merge(views) { |k, o, n| o.merge(n) }
Runnable example:
views = {
"2013-03-15" => {:views=> 30},
"2013-03-14" => {:views=> 23},
"2013-03-13" => {:views=> 35},
}
sales = {
"2013-03-15" => {:sales=> 5},
"2013-03-14" => {:sales=> 3},
"2013-03-12" => {:sales=> 8},
}
puts sales.merge(views) { |k, o, n| o.merge(n) }
=> {"2013-03-15"=>{:sales=>5, :views=>30}, "2013-03-14"=>{:sales=>3, :views=>23}, "2013-03-12"=>{:sales=>8}, "2013-03-13"=>{:views=>35}}

Resources