const log = console.log;
var dataTable = dc.dataTable("#dc-table-graph");
var pieChart = dc.pieChart("#pie-chart");
// const barChart = dc.barChart("#bar-chart");
// var focus = dc.barChart('#focus');
const chart_11 = dc.compositeChart("#focus");
// var range = dc.barChart('#range');
var dim = {}, // Stores all crossfilter dimensions
groups = {}, // Stores all crossfilter groups
cf;
// index a group key -> i and i -> key
function ordinal_to_linear_group(group, sort) {
var _ord2int, _int2ord;
return {
all: function() {
var ret = group.all();
if(sort) // NEW
ret = ret.slice().sort(sort);
_ord2int = {};
_int2ord = [];
ret.forEach(function(d, i) {
_ord2int[d.key] = i;
_int2ord[i] = d.key;
});
return ret;
},
ord2int: function(o) {
if(!_ord2int)
this.all();
return _ord2int[o];
},
int2ord: function(i) {
if(!_int2ord)
this.all();
return _int2ord[i];
}
};
}
function update(row) {
draw_charts(row);
}
d3.csv("info.csv").then(function(data) {
// console.log("data:",data);
data.forEach(d => {
d.date = new Date(d.date);
});
draw_charts(data);
});
function draw_charts(data)
{
// Programmatically insert header labels for table
var tableHeader = d3.select(".table-header")
.selectAll("th");
tableHeader = tableHeader.data(
[
{label: "pid", field_name: "pid", sort_state: "ascending"},
{label: "cid", field_name: "cid", sort_state: "ascending"},
{label: "date", field_name: "date", sort_state: "ascending"},
{label: "types", field_name: "types", sort_state: "ascending"},
{label: "probability", field_name: "probability", sort_state: "descending"} // Note Max Conf row starts off as descending
]
);
// enter() into virtual selection and create new
header elements for each table column
tableHeader = tableHeader.enter()
.append("th")
.text(function (d) { return d.label; }) // Accessor function for header titles
.on("click", tableHeaderCallback);
function tableHeaderCallback(d) {
// Highlight column header being sorted and show bootstrap glyphicon
var activeClass = "info";
d3.selectAll("#dc-table-graph th") // Disable all highlighting and icons
.classed(activeClass, false)
.selectAll("span")
.style("visibility", "hidden") // Hide glyphicon
var activeSpan = d3.select(this) // Enable active highlight and icon for active column for sorting
.classed(activeClass, true) // Set bootstrap "info" class on active header for highlight
.select("span")
.style("visibility", "visible");
// Toggle sort order state to user desired state
d.sort_state = d.sort_state === "ascending" ? "descending" : "ascending";
var isAscendingOrder = d.sort_state === "ascending";
dataTable
.order(isAscendingOrder ? d3.ascending : d3.descending)
.sortBy(function(datum) { return datum[d.field_name]; });
// Reset glyph icon for all other headers and update this headers icon
activeSpan.node().className = ''; // Remove all glyphicon classes
// Toggle glyphicon based on ascending/descending sort_state
activeSpan.classed(
isAscendingOrder ? "glyphicon glyphicon-sort-by-attributes" :
"glyphicon glyphicon-sort-by-attributes-alt", true);
updateTable();
dataTable.redraw();
}
// Initialize sort state and sort icon on one of the header columns
// Highlight "Max Conf" cell on page load
// This can be done programmatically for user specified column
tableHeader.filter(function(d) {
return d.label === "pid"; })
.classed("info", true);
var tableSpans = tableHeader
.append("span") // For Sort glyphicon on active table headers
.classed("glyphicon glyphicon-sort-by-attributes-alt", true)
.style("visibility", "hidden")
.filter(function(d) { return d.label === "pid"; })
.style("visibility", "visible");
cf = crossfilter(data); // Main crossfilter objects
let barTypeDimension = cf.dimension(function(d) { return d.cid});
let barTypeGroup = barTypeDimension.group();
var reducer_time_est_max = reductio().max(function(d) {
return parseFloat(d.probability)
});
let pieTypeDimension = cf.dimension(function(d) { return d.pid ? d.pid: ""});
let pieTypeGroup = pieTypeDimension.group();
var reducer_prob = reductio().max(function(d) {
return parseFloat(d.probability) || 1e-5;
});
var pred_prob_max_pie = reducer_prob(pieTypeGroup);
pieChart
.height(400)
.dimension(pieTypeDimension)
.group(pred_prob_max_pie )
.valueAccessor(function(p) {
return parseFloat(p.value.max) || 0.0;
})
// .data(function (d) {
// return d.order(function (d) {
// // console.log("------>",d.max);
// return +d.max || 0;
// }).top(10)
// })
.ordering(d => -(d.value.max || 0))
.othersGrouper(null)
.slicesCap(10)
.innerRadius(100)
.externalLabels(30)
.externalRadiusPadding(50)
.drawPaths(true)
.legend(dc.legend());
// example of formatting the legend via svg
// http://stackoverflow.com/questions/38430632/how-can-we-add-legends-value-beside-of-legend-with-proper-alignment
pieChart.on('pretransition', function(chart) {
chart.selectAll('.dc-legend-item text')
.text('')
.append('tspan')
.text(function(d) { return d.name; })
.append('tspan')
.attr('x', 100)
.attr('text-anchor', 'end')
.text(function(d) {
return d.data.max; });
});
// dc.override(pieChart, 'legendables', function() {
// var legendables = this._legendables();
// return legendables.filter(function(l) {
// return l.data.max > 0;
// });
// });
function static_copy_group(group) {
var all = group.all().map(kv => ({key: kv.key, value: kv.value}));
return {
all: function() {
return all;
}
}
}
function any_filters() {
return [chart_11]
.some(chart => chart.filters().length);
}
var chart_11_grp_copy = static_copy_group(reducer_time_est_max(barTypeGroup));
var group1 = ordinal_to_linear_group(chart_11_grp_copy, (a,b) => d3.descending(a.value.max, b.value.max));
var group = ordinal_to_linear_group(reducer_time_est_max(barTypeGroup), (a,b) => d3.descending(a.value.max, b.value.max));
var c1 = dc.barChart(chart_11)
.group(chart_11_grp_copy)
.colors('#ccc') // match dc.css rect.deselected
// .xUnits(dc.units.integers)
.keyAccessor(kv => group.ord2int(kv.key))
.valueAccessor(function(p) {
return parseFloat(p.value.max) || 0;
})
// .brushOn(false)
.controlsUseVisibility(true);
var c2 = dc.barChart(chart_11)
.group(barTypeGroup)
.colors('red')
// .xUnits(dc.units.integers)
.keyAccessor(kv => group.ord2int(kv.key))
.valueAccessor(function(p) {
return parseFloat(p.value.max) || 0;
})
// .addFilterHandler(function(filters, filter) {return [filter];})
.controlsUseVisibility(true)
.brushOn(false);
var linear_domain = [-0.5, 100 - 0.5];
chart_11
.width(850).height(350)
.margins({left: 60, top: 20, right: 10, bottom: 100})
.x(d3.scaleLinear().domain(linear_domain))
.xUnits(dc.units.integers)
// .x(d3.scaleOrdinal())
// .xUnits(dc.units.ordinal)
// .keyAccessor(kv => group.ord2int(kv.key))
// .valueAccessor(function(p) {
// console.log("PPPPPPPP:,",p);
// return parseFloat(p.value.max) || 0;
// })
// .centerBar(true)
.yAxisLabel('counts')
.elasticY(true)
.brushOn(false)
.dimension(barTypeDimension)
// .mouseZoomable(true)
.zoomScale([4,8])
// .group(barTypeGroup_mod)
.title(kv => kv.key)
// .elasticX(true)
.transitionDuration(0)
.compose([ c1,c2 ]);
chart_11.xAxis()
.tickFormat(function(d) { return group.int2ord(d); });
// equivalent of javascript: link, don't know why those didn't work
d3.select('#reset-focus').on('click', () => {
chart_11.filterAll();
dc.redrawAll();
})
d3.select('#reset-all').on('click', () => {
dc.filterAll();
dc.redrawAll();
})
// unfortunately we have to recreate click-selection, since a focus chart
// ordinarily filters to the visible area (and we don't want a brush either)
var chart_11Filter = [];
chart_11.filterAll = function() {
chart_11Filter = [];
chart_11.filter(null);
};
chart_11.fadeDeselectedArea = function (brushSelection) {
var _chart = this;
var bars = c2.selectAll('rect.bar');
log("bars:::::::::", _chart.chartGroup());
if (chart_11Filter.length) {
bars.classed(dc.constants.SELECTED_CLASS, function (d) {
return chart_11Filter.includes(d.data.key);
});
bars.classed(dc.constants.DESELECTED_CLASS, function (d) {
return !chart_11Filter.includes(d.data.key);
});
} else {
bars.classed(dc.constants.SELECTED_CLASS, false);
bars.classed(dc.constants.DESELECTED_CLASS, false);
}
};
c2.on('pretransition.click-handler', function(chart) {
chart.selectAll('.sub._1 rect.bar').on('click.ordinal-select', function(d) {
var i = chart_11Filter.indexOf(d.data.key);
if(i >= 0)
chart_11Filter.splice(i, 1);
else
chart_11Filter.push(d.data.key);
if(chart_11Filter.length)
chart.dimension().filterFunction(function(k) {
return chart_11Filter.includes(k);
});
else chart.dimension().filter(null);
chart.redrawGroup();
});
});
chart_11.on('preRedraw', function(chart) {
var domain = chart.x().domain(),
min = Math.ceil(domain[0]), max = Math.floor(domain[1]);
chart.xAxis().tickValues(d3.range(min, max+1));
});
// c1.filter(null);
// Setup different dimensions for plots
dim.tableMaxConfidence = cf.dimension(function (d) {
return d.Project_id;
});
// ##############################
// Generate the dc.js dataTable
// ##############################
// Create generating functions for each columns
var columnFunctions = [
function(d) { return d.pid; },
function(d) { return d.cid; },
function(d) { return d.date; },
function(d) { return d.types; },
function(d) { return d.probability; },
];
// extra dimensions for filtering
const cidDimension = cf.dimension(d => d.cid),
dateDimension = cf.dimension(d => d.date);
var color = d3.scaleSequential() //d3.scaleLinear()
.domain([0, 0.9])
.interpolator(d3.interpolateBlues);
// Pagination implementation inspired by:
// https://github.com/dc-js/dc.js/blob/master/web/examples/table-pagination.html
dataTable.width(960).height(800)
.dimension(dim.tableMaxConfidence)
.group(function(d) { return "Dummy"}) // Must pass in. Ignored since .showGroups(false)
.size(Infinity)
.columns(columnFunctions)
.showGroups(false)
.sortBy(function(d){ return d.pid; }) // Initially sort by max_conf column
.order(d3.descending)
.on('pretransition', function (table) {
table.selectAll('td.dc-table-column._0')
.on('click',function(d){
console.log(d);
table.filter(d.pid)
dc.redrawAll();
})
table.selectAll('td.dc-table-column._1')
.on('click',function(d){
console.log("select:",d);
cidDimension.filter(d.cid)
dc.redrawAll();
})
table.selectAll('td.dc-table-column._2')
.on('click',function(d){
dateDimension.filter(d.date)
dc.redrawAll();
})
table.selectAll('td.dc-table-column._4')
.style("background-color", function(d){
return color(d.probability)});
});
updateTable();
dc.renderAll();
dataTable.redraw();
}
// Data Table Pagination
var tableOffset = 0, tablePageSize = 10;
function updateTable() {
// Ensure Prev/Next bounds are correct, especially after filters applied to dc charts
var totFilteredRecs = cf.groupAll().value();
// // Adjust values of start and end record numbers for edge cases
var end = tableOffset + tablePageSize > totFilteredRecs ? totFilteredRecs : tableOffset + tablePageSize;
tableOffset = tableOffset >= totFilteredRecs ? Math.floor((totFilteredRecs - 1) / tablePageSize) * tablePageSize : tableOffset;
tableOffset = tableOffset < 0 ? 0 : tableOffset; // In case of zero entries
dataTable.redraw();
}
|