Related
I need to show the total sales of my data to both sellers and cities. However, the values shown in the totals must be dynamic.
P.S. My table allows the user to select the rows, this is because the values are rendered according to each selection made. (This dynamism between the tables is already working perfectly).
The initial state of the Total is rendered with the general sum of all sellers and cities, below I show the tables with their respective totals, however, as shown in the image, the values are static and not dynamic.
I need it to be diahanic because if I select for example the seller João Luis and Miguel, the value to be shown in the total must be the sum of these two sellers.
I asked a question a while ago about How to add row in datatable - DC.js, a friend (#Gordon) who is helping me a lot in doubts with DC.js and Crossfilter told me to use crossfilter.add(). Unfortunately I couldn't do it the way suggested, so I'm here again with practically the same question (sorry for my stupidity).
var composite = dc.compositeChart('#composite');
var vendedorTable = dc.dataTable("#vendedores");
var citiesTable = dc.dataTable("#cities");
function remove_empty_bins(source_group) {
return {
top: function(N) {
return source_group.all().filter(function(d) {
return d.value.totalAno > 1e-3 ||
d.value.totalHomologo > 1e-3;
}).slice(0, N);
}
};
}
var adjustX = 10,
adjustY = 40;
var url = 'https://gist.githubusercontent.com/bernalvinicius/3cece295bc37de1697e7f83418e7fcc9/raw/a5820379ec6eae76ee792495cc5dd1685c977a73/vendedores.json';
d3.json(url).then(function(data) {
data.forEach(d =>
Object.assign(d, {
mes: d.Month,
atual: d.Vendas_Ano,
passado: d.Vendas_Ant
})
);
var cf = crossfilter(data);
vendedorDim = cf.dimension(function(d) {
return d.vendnm;
});
var vendedorGroup = vendedorDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);
citiesDim = cf.dimension(function(d) {
return d.zona;
});
var citiesGroup = citiesDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);
var dim = cf.dimension(dc.pluck('mes')),
grp1 = dim.group().reduceSum(dc.pluck('atual')),
grp2 = dim.group().reduceSum(dc.pluck('passado'));
var minMonth = dim.bottom(1)[0].mes;
var maxMonth = dim.top(1)[0].mes;
var all = cf.groupAll();
dc.dataCount(".dc-data-count")
.dimension(cf)
.group(all);
function reduceAdd(p, v) {
p.totalAno += +v.Vendas_Ano;
p.totalHomologo += +v.Vendas_Ant;
return p;
}
function reduceRemove(p, v) {
p.totalAno -= v.Vendas_Ano;
p.totalHomologo -= v.Vendas_Ant;
return p;
}
function reduceInitial() {
return {
totalAno: 0,
totalHomologo: 0,
};
}
// Fake Dimension
rank = function(p) {
return ""
};
// Chart by months
composite
.width(window.innerWidth - adjustX)
.height(300)
.x(d3.scaleLinear().domain([1, 12]))
.yAxisLabel("")
.xAxisLabel("Month")
.legend(dc.legend().x(500).y(0).itemHeight(13).gap(5))
.renderHorizontalGridLines(true)
.compose([
dc.lineChart(composite)
.dimension(dim)
.colors('steelblue')
.group(grp1, "Currently Year"),
dc.lineChart(composite)
.dimension(dim)
.colors('darkorange')
.group(grp2, "Last Year")
])
.brushOn(true);
composite.brush().extent([-0.5, data.length + 1.5])
composite.extendBrush = function(brushSelection) {
if (brushSelection) {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
const point = Math.round((brushSelection[0] + brushSelection[1]) / 2);
return [
point - 0.5,
point + 0.5
];
}
};
// Sales Table
vendedorTable.width(500)
.height(480)
.dimension(remove_empty_bins(vendedorGroup))
.group(rank)
.columns([function(d) {
return d.key;
},
function(d) {
return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
},
function(d) {
return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
])
.sortBy(function(d) {
return d.value.totalAno
})
.order(d3.descending)
// Cities Table
citiesTable
.width(500)
.height(480)
.dimension(remove_empty_bins(citiesGroup))
.group(rank)
.columns([function(d) {
return d.key;
},
function(d) {
return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
},
function(d) {
return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
])
.controlsUseVisibility(true)
.sortBy(function(d) {
return d.value.totalAno
})
.order(d3.descending)
// Sales click events
vendedorTable.on('pretransition', function(table) {
table.selectAll('td.dc-table-column')
.on('click', function(d) {
let filters = table.filters().slice();
if (filters.indexOf(d.key) === -1)
filters.push(d.key);
else
filters = filters.filter(k => k != d.key);
if (filters.length === 0)
vendedorDim.filter(null);
else
vendedorDim.filterFunction(function(d) {
return filters.indexOf(d) !== -1;
})
table.replaceFilter([filters]);
citiesTable.filter(null);
citiesDim.filter(null);
composite.filter(null);
dc.redrawAll();
});
let filters = table.filters();
table.selectAll('tr.dc-table-row')
.classed('sel-rows', d => filters.indexOf(d.key) !== -1);
});
// Cities click events
citiesTable.on('pretransition', function(table) {
table.selectAll('td.dc-table-column')
.on('click', function(d) {
let filters = table.filters().slice();
if (filters.indexOf(d.key) === -1)
filters.push(d.key);
else
filters = filters.filter(k => k != d.key);
if (filters.length === 0)
citiesDim.filter(null);
else
citiesDim.filterFunction(function(d) {
return filters.indexOf(d) !== -1;
})
table.replaceFilter([filters]);
vendedorTable.filter(null);
vendedorDim.filter(null);
composite.filter(null);
dc.redrawAll();
});
let filters = table.filters();
table.selectAll('tr.dc-table-row')
.classed('sel-rows', d => filters.indexOf(d.key) !== -1);
});
dc.renderAll();
// reset functions
$('#reset').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
composite.filter(null);
dc.redrawAll();
});
$('#resetTable').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
composite.filter(null);
dc.redrawAll();
});
$('#resetTable2').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
composite.filter(null);
dc.redrawAll();
});
/****************************************************************************/
// Functions to handle responsive
apply_resizing(composite, adjustX, adjustY, function(composite) {
composite.legend().x(window.innerWidth - 200);
});
var find_query = function() {
var _map = window.location.search.substr(1).split('&').map(function(a) {
return a.split('=');
}).reduce(function(p, v) {
if (v.length > 1)
p[v[0]] = decodeURIComponent(v[1].replace(/\+/g, " "));
else
p[v[0]] = true;
return p;
}, {});
return function(field) {
return _map[field] || null;
};
}();
var resizeMode = find_query('resize') || 'widhei';
function apply_resizing(composite, adjustX, adjustY, onresize) {
if (resizeMode === 'viewbox') {
composite
.width(300)
.height(200)
.useViewBoxResizing(true);
d3.select(composite.anchor()).classed('fullsize', false);
} else {
adjustX = adjustX || 0;
adjustY = adjustY || adjustX || 0;
composite
.width(window.innerWidth - adjustX)
.height(300);
window.onresize = function() {
if (onresize) {
onresize(composite);
}
composite
.width(window.innerWidth - adjustX)
.height(300);
if (composite.rescale) {
composite.rescale();
}
composite.redraw();
};
}
}
});
#composite {
padding: 10px;
}
.dc-table-group {
visibility: collapse;
}
tr.dc-table-row.sel-rows {
background-color: lightblue;
}
.brush .custom-brush-handle {
display: none;
}
<head>
<!-- favicon -->
<link rel="shortcut icon" href="https://img.icons8.com/nolan/64/puzzle.png">
<!-- bootstrap.css -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- bootstrap-theme.css -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- dc.css -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dc/2.1.8/dc.css">
<!-- jquery.js -->
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
<!-- bootstrap.js -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<!-- d3.v5.js -->
<script src="https://d3js.org/d3.v5.js"></script>
<!-- crossfilter.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
<!-- dc.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/dc/3.1.8/dc.js"></script>
<title>Chart</title>
</head>
<body>
<div id="composite"></div>
<div class="container-fluid">
<div class="row content">
<div class="col-md-12">
<div class="col-md-6">
<table class="table" id="totaisVendedores">
<thead>
<tr>
<th>Total Sales</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
</table>
</div>
<div class="col-md-6">
<table class="table" id="totaisCities">
<thead>
<tr>
<th>Total City</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
</table>
</div>
<div class="col-md-6">
<table class="table" id="vendedores">
<thead>
<tr>
<th>Sales</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
</table>
</div>
<div class="col-md-6">
<table class="table" id="cities">
<thead>
<tr>
<th>City</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</body>
Sorry, I completely misread your last question. It was nice of you to accept the answer, but you really didn't have to do that. :)
In order to add totals, you can add a tfoot section to your table
<tfoot>
<tr>
<th>TOTAL</th>
<th id="total-current-year"></th>
<th id="total-last-year"></th>
</tr>
</tfoot>
and drive it with a NumberDisplay widget.
const totalCYDisplay = dc.numberDisplay('#total-current-year')
.group(totalAll)
.valueAccessor(d => d.totalAno)
The default formatting is .2s but numberDisplay accepts any d3-format instance.
If you don't like the animation, you can set .transitionDuration(0)
var composite = dc.compositeChart('#composite');
var vendedorTable = dc.dataTable("#vendedores");
var citiesTable = dc.dataTable("#cities");
function remove_empty_bins(source_group) {
return {
top: function(N) {
return source_group.all().filter(function(d) {
return d.value.totalAno > 1e-3 ||
d.value.totalHomologo > 1e-3;
}).slice(0, N);
}
};
}
var adjustX = 10,
adjustY = 40;
var url = 'https://gist.githubusercontent.com/bernalvinicius/3cece295bc37de1697e7f83418e7fcc9/raw/a5820379ec6eae76ee792495cc5dd1685c977a73/vendedores.json';
d3.json(url).then(function(data) {
data.forEach(d =>
Object.assign(d, {
mes: d.Month,
atual: d.Vendas_Ano,
passado: d.Vendas_Ant
})
);
var cf = crossfilter(data);
vendedorDim = cf.dimension(function(d) {
return d.vendnm;
});
var vendedorGroup = vendedorDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);
citiesDim = cf.dimension(function(d) {
return d.zona;
});
var citiesGroup = citiesDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);
const totalAll = cf.groupAll()
.reduce(reduceAdd, reduceRemove, reduceInitial);
debugger;
var dim = cf.dimension(dc.pluck('mes')),
grp1 = dim.group().reduceSum(dc.pluck('atual')),
grp2 = dim.group().reduceSum(dc.pluck('passado'));
var minMonth = dim.bottom(1)[0].mes;
var maxMonth = dim.top(1)[0].mes;
var all = cf.groupAll();
dc.dataCount(".dc-data-count")
.dimension(cf)
.group(all);
function reduceAdd(p, v) {
p.totalAno += +v.Vendas_Ano;
p.totalHomologo += +v.Vendas_Ant;
return p;
}
function reduceRemove(p, v) {
p.totalAno -= v.Vendas_Ano;
p.totalHomologo -= v.Vendas_Ant;
return p;
}
function reduceInitial() {
return {
totalAno: 0,
totalHomologo: 0,
};
}
// Fake Dimension
rank = function(p) {
return ""
};
// Chart by months
composite
.width(window.innerWidth - adjustX)
.height(300)
.x(d3.scaleLinear().domain([1, 12]))
.yAxisLabel("")
.xAxisLabel("Month")
.legend(dc.legend().x(500).y(0).itemHeight(13).gap(5))
.renderHorizontalGridLines(true)
.compose([
dc.lineChart(composite)
.dimension(dim)
.colors('steelblue')
.group(grp1, "Currently Year"),
dc.lineChart(composite)
.dimension(dim)
.colors('darkorange')
.group(grp2, "Last Year")
])
.brushOn(true);
composite.brush().extent([-0.5, data.length + 1.5])
composite.extendBrush = function(brushSelection) {
if (brushSelection) {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
const point = Math.round((brushSelection[0] + brushSelection[1]) / 2);
return [
point - 0.5,
point + 0.5
];
}
};
// Sales Table
vendedorTable.width(500)
.height(480)
.dimension(remove_empty_bins(vendedorGroup))
.group(rank)
.columns([function(d) {
return d.key;
},
function(d) {
return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
},
function(d) {
return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
])
.sortBy(function(d) {
return d.value.totalAno
})
.order(d3.descending)
// vendedors totals
const totalCYDisplay = dc.numberDisplay('#total-current-year')
.group(totalAll)
.valueAccessor(d => d.totalAno)
const totalLYDisplay = dc.numberDisplay('#total-last-year')
.group(totalAll)
.valueAccessor(d => d.totalHomologo)
// Cities Table
citiesTable
.width(500)
.height(480)
.dimension(remove_empty_bins(citiesGroup))
.group(rank)
.columns([function(d) {
return d.key;
},
function(d) {
return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
},
function(d) {
return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
])
.controlsUseVisibility(true)
.sortBy(function(d) {
return d.value.totalAno
})
.order(d3.descending)
// Sales click events
vendedorTable.on('pretransition', function(table) {
table.selectAll('td.dc-table-column')
.on('click', function(d) {
let filters = table.filters().slice();
if (filters.indexOf(d.key) === -1)
filters.push(d.key);
else
filters = filters.filter(k => k != d.key);
if (filters.length === 0)
vendedorDim.filter(null);
else
vendedorDim.filterFunction(function(d) {
return filters.indexOf(d) !== -1;
})
table.replaceFilter([filters]);
citiesTable.filter(null);
citiesDim.filter(null);
composite.filter(null);
dc.redrawAll();
});
let filters = table.filters();
table.selectAll('tr.dc-table-row')
.classed('sel-rows', d => filters.indexOf(d.key) !== -1);
});
// Cities click events
citiesTable.on('pretransition', function(table) {
table.selectAll('td.dc-table-column')
.on('click', function(d) {
let filters = table.filters().slice();
if (filters.indexOf(d.key) === -1)
filters.push(d.key);
else
filters = filters.filter(k => k != d.key);
if (filters.length === 0)
citiesDim.filter(null);
else
citiesDim.filterFunction(function(d) {
return filters.indexOf(d) !== -1;
})
table.replaceFilter([filters]);
vendedorTable.filter(null);
vendedorDim.filter(null);
composite.filter(null);
dc.redrawAll();
});
let filters = table.filters();
table.selectAll('tr.dc-table-row')
.classed('sel-rows', d => filters.indexOf(d.key) !== -1);
});
dc.renderAll();
// reset functions
$('#reset').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
composite.filter(null);
dc.redrawAll();
});
$('#resetTable').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
composite.filter(null);
dc.redrawAll();
});
$('#resetTable2').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
composite.filter(null);
dc.redrawAll();
});
/****************************************************************************/
// Functions to handle responsive
apply_resizing(composite, adjustX, adjustY, function(composite) {
composite.legend().x(window.innerWidth - 200);
});
var find_query = function() {
var _map = window.location.search.substr(1).split('&').map(function(a) {
return a.split('=');
}).reduce(function(p, v) {
if (v.length > 1)
p[v[0]] = decodeURIComponent(v[1].replace(/\+/g, " "));
else
p[v[0]] = true;
return p;
}, {});
return function(field) {
return _map[field] || null;
};
}();
var resizeMode = find_query('resize') || 'widhei';
function apply_resizing(composite, adjustX, adjustY, onresize) {
if (resizeMode === 'viewbox') {
composite
.width(300)
.height(200)
.useViewBoxResizing(true);
d3.select(composite.anchor()).classed('fullsize', false);
} else {
adjustX = adjustX || 0;
adjustY = adjustY || adjustX || 0;
composite
.width(window.innerWidth - adjustX)
.height(300);
window.onresize = function() {
if (onresize) {
onresize(composite);
}
composite
.width(window.innerWidth - adjustX)
.height(300);
if (composite.rescale) {
composite.rescale();
}
composite.redraw();
};
}
}
});
#composite {
padding: 10px;
}
.dc-table-group {
visibility: collapse;
}
tr.dc-table-row.sel-rows {
background-color: lightblue;
}
.brush .custom-brush-handle {
display: none;
}
<head>
<!-- favicon -->
<link rel="shortcut icon" href="https://img.icons8.com/nolan/64/puzzle.png">
<!-- bootstrap.css -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- bootstrap-theme.css -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- dc.css -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dc/2.1.8/dc.css">
<!-- jquery.js -->
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
<!-- bootstrap.js -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<!-- d3.v5.js -->
<script src="https://d3js.org/d3.v5.js"></script>
<!-- crossfilter.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
<!-- dc.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/dc/3.1.8/dc.js"></script>
<title>Chart</title>
</head>
<body>
<div id="composite"></div>
<div class="container-fluid">
<div class="row content">
<div class="col-md-12">
<div class="col-md-6">
<table class="table" id="totaisVendedores">
<thead>
<tr>
<th>Total Sales</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
</table>
</div>
<div class="col-md-6">
<table class="table" id="totaisCities">
<thead>
<tr>
<th>Total City</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
</table>
</div>
<div class="col-md-6">
<table class="table" id="vendedores">
<thead>
<tr>
<th>Sales</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
<tfoot>
<tr>
<th>TOTAL</th>
<th id="total-current-year"></th>
<th id="total-last-year"></th>
</tr>
</tfoot>
</table>
</div>
<div class="col-md-6">
<table class="table" id="cities">
<thead>
<tr>
<th>City</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</body>
I created two tables that relate. When I select one or more items from Table A, Table B is resized according to that selection and vice versa.
However, I need to lock the selection of the two tables at the same time. For example, if I click on the sellers Miguel andSede, in Table B the values and cities corresponding to these two sellers will be rendered. And if in Table B I click on the cities of Faro andLoulé, automatically the sellers Miguel andSede should be deselected.
What happens at the moment is that I can make selections in both tables at the same time, as shown in the image below:
I need to create a rule where if I have a selection in Table A and click on Table B. The line selected in Table A has no background color and vice versa.
When I make a selection, some lines are empty, but they still appear, as shown in the image below:
How can I prevent these lines from appearing if there is no selection?
I apologize for asking two questions at the same time, as it is the same code I have found better to use here.
Here's my code, thanks in advance.
var vendedorTable = dc.dataTable("#Vendedores");
var citiesTable = dc.dataTable("#cities");
var url = 'https://gist.githubusercontent.com/bernalvinicius/3cece295bc37de1697e7f83418e7fcc9/raw/a5820379ec6eae76ee792495cc5dd1685c977a73/vendedores.json';
d3.json(url).then(function(data) {
data.forEach(function(d) {
var myCrossfilter = crossfilter(data);
var all = myCrossfilter.groupAll();
dc.dataCount(".dc-data-count")
.dimension(myCrossfilter)
.group(all);
vendedorDim = myCrossfilter.dimension(function(d) {
return d.vendnm;
});
var vendedorGroup = vendedorDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);
citiesDim = myCrossfilter.dimension(function(d) {
return d.zona;
});
var citiesGroup = citiesDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);
function reduceAdd(p, v) {
p.totalAno += +v.Vendas_Ano;
p.totalHomologo += +v.Vendas_Ant;
return p;
}
function reduceRemove(p, v) {
p.totalAno -= v.Vendas_Ano;
p.totalHomologo -= v.Vendas_Ant;
return p;
}
function reduceInitial() {
return {
totalAno: 0,
totalHomologo: 0,
};
}
//Fake Dimension
rank = function(p) {
return ""
};
function checkRows(d) {
if (d.value.totalAno <= 0 || isNaN(d.value.totalAno) || d.value.totalHomologo <= 0 || isNaN(d.value.totalHomologo)) {
return 0;
}
return d;
}
//vendedorTable
vendedorTable.width(500)
.height(480)
.dimension(vendedorGroup)
.group(rank)
.columns([function(d) {
d = checkRows(d);
while (d != 0) {
return d.key;
}
},
function(d) {
d = checkRows(d);
while (d != 0) {
return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
},
function(d) {
d = checkRows(d);
while (d != 0) {
return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
}
])
.sortBy(function(d) {
return d.value.totalAno
})
.order(d3.descending)
//CityTable
citiesTable.width(500)
.height(480)
.dimension(citiesGroup)
.group(rank)
.columns([function(d) {
d = checkRows(d);
while (d != 0) {
return d.key;
}
},
function(d) {
d = checkRows(d);
while (d != 0) {
return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
},
function(d) {
d = checkRows(d);
while (d != 0) {
return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
}
])
.sortBy(function(d) {
return d.value.totalAno
})
.order(d3.descending)
vendedorTable.on('pretransition', function(table) {
table.selectAll('td.dc-table-column')
.on('click', function(d) {
let filters = table.filters().slice();
if (filters.indexOf(d.key) === -1)
filters.push(d.key);
else
filters = filters.filter(k => k != d.key);
if (filters.length === 0)
vendedorDim.filter(null);
else
vendedorDim.filterFunction(function(d) {
return filters.indexOf(d) !== -1;
})
table.replaceFilter([filters]);
dc.redrawAll();
});
let filters = table.filters();
table.selectAll('tr.dc-table-row')
.classed('sel-rows', d => filters.indexOf(d.key) !== -1);
});
citiesTable.on('pretransition', function(table) {
table.selectAll('td.dc-table-column')
.on('click', function(d) {
let filters = table.filters().slice();
if (filters.indexOf(d.key) === -1)
filters.push(d.key);
else
filters = filters.filter(k => k != d.key);
if (filters.length === 0)
citiesDim.filter(null);
else
citiesDim.filterFunction(function(d) {
return filters.indexOf(d) !== -1;
})
table.replaceFilter([filters]);
dc.redrawAll();
});
let filters = table.filters();
table.selectAll('tr.dc-table-row')
.classed('sel-rows', d => filters.indexOf(d.key) !== -1);
});
dc.renderAll();
});
$('#reset').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
dc.redrawAll();
});
$('#resetTable').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
dc.redrawAll();
});
$('#resetTable2').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
dc.redrawAll();
});
});
<head>
<style>
.dc-table-group {
visibility: collapse;
}
tr.dc-table-row.sel-rows {
background-color: lightblue;
}
</style>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dc/2.1.8/dc.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
<script src="https://d3js.org/d3.v5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dc/3.1.8/dc.js"></script>
<title>Vendedores</title>
</head>
<body>
<div class="container-fluid">
<div class="row content">
<div class="col-md-10" style="padding-left: 20px;">
<div class="row marginClass">
<h4 class="pull-left" id="Introduction"><small>Dados fictícios da empresa | Exemplo de Pesquisa
Detalhada |
</small></h4>
<h6 class="dc-data-count" style="float: left;margin-left:5px;">
<span>
<span class="filter-count"></span> selecionado dentre
<span class="total-count"></span> registros |
<a id="reset"> Reset All </a>
</span>
</h6>
</div>
<div class="col-md-6">
<br>
<a id="resetTable"> Reset</a>
<table class="table" id="Vendedores">
<thead>
<tr>
<th>Sales</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
</table>
</div>
<div class="col-md-6">
<br>
<a id="resetTable2"> Reset</a>
<table class="table" id="cities">
<thead>
<tr>
<th>City</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</body>
I'm not sure that I understand the first question.
As for the second question, currently you are filtering out the data inside of the formatting functions for the table:
.columns([function(d) {
d = checkRows(d);
while (d != 0) {
return d.key;
}
},
function(d) {
d = checkRows(d);
while (d != 0) {
return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
},
function(d) {
d = checkRows(d);
while (d != 0) {
return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
}
])
That works, but it's a weird way to go about it for two reasons:
while(...) means "repeat until false". if(...) would be more idiomatic here.
More importantly, this still prints the rows, but if the values are zero or NaN, it prints undefined (the default return value for a function in JavaScript) and this shows up as an empty cell.
It would be better to filter the data before it gets to the table. You can do this using a fake group. Specifically, you can create an object which supports the .top(N) function that the table will use to pull data, but skips any rows where either of these values is close to zero:
function remove_empty_bins(source_group) {
return {
top: function (N) {
return source_group.all().filter(function(d) {
return d.value.totalAno > 1e-3 &&
d.value.totalHomologo > 1e-3; // does it have a value?
}).slice(0, N);
}
};
}
Apply this function to each of your groups:
vendedorTable.width(500)
.height(480)
.dimension(remove_empty_bins(vendedorGroup))
citiesTable.width(500)
.height(480)
.dimension(remove_empty_bins(citiesGroup))
And now your formatting functions can stick to formatting!
.columns([function(d) {
return d.key;
},
function(d) {
return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
},
function(d) {
return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
])
var vendedorTable = dc.dataTable("#Vendedores");
var citiesTable = dc.dataTable("#cities");
function remove_empty_bins(source_group) {
return {
top: function (N) {
return source_group.all().filter(function(d) {
return d.value.totalAno > 1e-3 &&
d.value.totalHomologo > 1e-3; // does it have a value?
}).slice(0, N);
}
};
}
var url = 'https://gist.githubusercontent.com/bernalvinicius/3cece295bc37de1697e7f83418e7fcc9/raw/a5820379ec6eae76ee792495cc5dd1685c977a73/vendedores.json';
d3.json(url).then(function(data) {
data.forEach(function(d) {
var myCrossfilter = crossfilter(data);
var all = myCrossfilter.groupAll();
dc.dataCount(".dc-data-count")
.dimension(myCrossfilter)
.group(all);
vendedorDim = myCrossfilter.dimension(function(d) {
return d.vendnm;
});
var vendedorGroup = vendedorDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);
citiesDim = myCrossfilter.dimension(function(d) {
return d.zona;
});
var citiesGroup = citiesDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);
function reduceAdd(p, v) {
p.totalAno += +v.Vendas_Ano;
p.totalHomologo += +v.Vendas_Ant;
return p;
}
function reduceRemove(p, v) {
p.totalAno -= v.Vendas_Ano;
p.totalHomologo -= v.Vendas_Ant;
return p;
}
function reduceInitial() {
return {
totalAno: 0,
totalHomologo: 0,
};
}
//Fake Dimension
rank = function(p) {
return ""
};
function checkRows(d) {
if (d.value.totalAno <= 0 || isNaN(d.value.totalAno) || d.value.totalHomologo <= 0 || isNaN(d.value.totalHomologo)) {
return 0;
}
return d;
}
//vendedorTable
vendedorTable.width(500)
.height(480)
.dimension(remove_empty_bins(vendedorGroup))
.group(rank)
.columns([function(d) {
return d.key;
},
function(d) {
return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
},
function(d) {
return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
])
.sortBy(function(d) {
return d.value.totalAno
})
.order(d3.descending)
//CityTable
citiesTable.width(500)
.height(480)
.dimension(remove_empty_bins(citiesGroup))
.group(rank)
.columns([function(d) {
d = checkRows(d);
while (d != 0) {
return d.key;
}
},
function(d) {
d = checkRows(d);
while (d != 0) {
return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
},
function(d) {
d = checkRows(d);
while (d != 0) {
return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
}
])
.sortBy(function(d) {
return d.value.totalAno
})
.order(d3.descending)
vendedorTable.on('pretransition', function(table) {
table.selectAll('td.dc-table-column')
.on('click', function(d) {
let filters = table.filters().slice();
if (filters.indexOf(d.key) === -1)
filters.push(d.key);
else
filters = filters.filter(k => k != d.key);
if (filters.length === 0)
vendedorDim.filter(null);
else
vendedorDim.filterFunction(function(d) {
return filters.indexOf(d) !== -1;
})
table.replaceFilter([filters]);
dc.redrawAll();
});
let filters = table.filters();
table.selectAll('tr.dc-table-row')
.classed('sel-rows', d => filters.indexOf(d.key) !== -1);
});
citiesTable.on('pretransition', function(table) {
table.selectAll('td.dc-table-column')
.on('click', function(d) {
let filters = table.filters().slice();
if (filters.indexOf(d.key) === -1)
filters.push(d.key);
else
filters = filters.filter(k => k != d.key);
if (filters.length === 0)
citiesDim.filter(null);
else
citiesDim.filterFunction(function(d) {
return filters.indexOf(d) !== -1;
})
table.replaceFilter([filters]);
dc.redrawAll();
});
let filters = table.filters();
table.selectAll('tr.dc-table-row')
.classed('sel-rows', d => filters.indexOf(d.key) !== -1);
});
dc.renderAll();
});
$('#reset').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
dc.redrawAll();
});
$('#resetTable').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
dc.redrawAll();
});
$('#resetTable2').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null);
citiesTable.filter(null);
citiesDim.filter(null);
dc.redrawAll();
});
});
<head>
<style>
.dc-table-group {
visibility: collapse;
}
tr.dc-table-row.sel-rows {
background-color: lightblue;
}
</style>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dc/2.1.8/dc.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
<script src="https://d3js.org/d3.v5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dc/3.1.8/dc.js"></script>
<title>Vendedores</title>
</head>
<body>
<div class="container-fluid">
<div class="row content">
<div class="col-md-10" style="padding-left: 20px;">
<div class="row marginClass">
<h4 class="pull-left" id="Introduction"><small>Dados fictícios da empresa | Exemplo de Pesquisa
Detalhada |
</small></h4>
<h6 class="dc-data-count" style="float: left;margin-left:5px;">
<span>
<span class="filter-count"></span> selecionado dentre
<span class="total-count"></span> registros |
<a id="reset"> Reset All </a>
</span>
</h6>
</div>
<div class="col-md-6">
<br>
<a id="resetTable"> Reset</a>
<table class="table" id="Vendedores">
<thead>
<tr>
<th>Sales</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
</table>
</div>
<div class="col-md-6">
<br>
<a id="resetTable2"> Reset</a>
<table class="table" id="cities">
<thead>
<tr>
<th>City</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</body>
In my application, I have two charts and one table. The charts names are sellerChart and dateUnitPriceChart and table name is datatable.For sellerChart, I create dimension like this and then draw a chart :
var sellerDimension = data.dimension(function (d) {
return d.slr_Name;
});
var sellerGroup = sellerDimension.group().reduceSum(function (d) {
return d.fdl_Num;
});
As you see is use reduceSum and this is what I want but for another chart, I want to use average but currently, it uses reduceSum like this
var dateDimension = data.dimension(function (d) {
return d.fct_Date;
});
var unitPriceGroup = dateDimension.group().reduceSum(function
(d) {
return d.fdl_UniyPrice;
});
for showing average I try to use reductio like this :
var unitPriceGroup = dateDimension.group()
var reducer = reductio()
.count(true)
.sum(function (d) {
return d.fdl_UniyPrice;
})
.avg(true);
reducer(unitPriceGroup);
Now I have averaged in reducer but the chart show only X and Y axis without any information, so my question is how to show average based on the average of fdl_UniyPrice.
I create a JS Fiddle, my codes start from line 43 and my data start on line 42
While looking at your data and based on your explanation, avg calculation can be achieved using custom reduce function. By using the dateDimension to create grouping function to get the average. So regardless of the slr_Name and mrq_Requester_dep_title, It will create group for each date with sum up the fdl_UniyPrice.
var dateDimension = data.dimension(function (d) {
return d.fct_Date;
});
var unitPriceGroup = dateDimension.group().reduce(
//return d.fdl_UniyPrice;
//add
function (p, v) {
++p.count;
p.total += v.fdl_UniyPrice;
if (p.count == 0) {
p.average = 0;
} else {
p.average = p.total / p.count;
}
return p;
},
// remove
function (p, v) {
--p.count;
p.total -= v.fdl_UniyPrice;
if (p.count == 0) {
p.average = 0;
} else {
p.average = p.total / p.count;
}
return p;
},
// initial
function () {
return {
count: 0,
total: 0,
average: 0
};
}
);
var myData = [{"slr_Name":"handStore","fct_Date":"10/31/2016","fdl_UniyPrice":40000,"fdl_TotalPrice":2400000,"ShamsiDate":"1395/08/10","mrq_No":"335","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"boss office","fdl_Num":60},{"slr_Name":"Sh Store","fct_Date":"12/12/2016","fdl_UniyPrice":50000,"fdl_TotalPrice":60000,"ShamsiDate":"1395/09/22","mrq_No":"357","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"Start Up","fdl_Num":1.2},{"slr_Name":"handStore","fct_Date":"12/18/2016","fdl_UniyPrice":44000,"fdl_TotalPrice":96800,"ShamsiDate":"1395/09/28","mrq_No":"344","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"Select Office","fdl_Num":2.2},{"slr_Name":"handStore","fct_Date":"12/18/2016","fdl_UniyPrice":40000,"fdl_TotalPrice":1240000,"ShamsiDate":"1395/09/28","mrq_No":"326","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"U Office","fdl_Num":31},{"slr_Name":"handStore","fct_Date":"12/20/2016","fdl_UniyPrice":42000,"fdl_TotalPrice":2142000,"ShamsiDate":"1395/09/30","mrq_No":"340","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"MH","fdl_Num":51},{"slr_Name":"N Brothers","fct_Date":"12/21/2016","fdl_UniyPrice":38000,"fdl_TotalPrice":1140000,"ShamsiDate":"1395/10/01","mrq_No":"440","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"Start Up","fdl_Num":30},{"slr_Name":"N Brothers","fct_Date":"12/21/2016","fdl_UniyPrice":38000,"fdl_TotalPrice":2432000,"ShamsiDate":"1395/10/01","mrq_No":"423","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"U Office","fdl_Num":64},{"slr_Name":"N Brothers","fct_Date":"12/26/2016","fdl_UniyPrice":38000,"fdl_TotalPrice":1710000,"ShamsiDate":"1395/10/06","mrq_No":"420","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"Managements","fdl_Num":45},{"slr_Name":"handStore","fct_Date":"12/27/2016","fdl_UniyPrice":44000,"fdl_TotalPrice":1320000,"ShamsiDate":"1395/10/07","mrq_No":"345","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"Finance","fdl_Num":30},{"slr_Name":"handStore","fct_Date":"12/27/2016","fdl_UniyPrice":40000,"fdl_TotalPrice":280000,"ShamsiDate":"1395/10/07","mrq_No":"337","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"Manage and create","fdl_Num":7},{"slr_Name":"Store 2","fct_Date":"12/28/2016","fdl_UniyPrice":38000,"fdl_TotalPrice":874000,"ShamsiDate":"1395/10/08","mrq_No":"424","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"Start Up","fdl_Num":23},{"slr_Name":"handStore","fct_Date":"1/8/2017","fdl_UniyPrice":44000,"fdl_TotalPrice":264000,"ShamsiDate":"1395/10/19","mrq_No":"425","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"human resource","fdl_Num":6},{"slr_Name":"handStore","fct_Date":"2/21/2017","fdl_UniyPrice":47000,"fdl_TotalPrice":117500,"ShamsiDate":"1395/12/03","mrq_No":"553","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"Doctors","fdl_Num":2.5},{"slr_Name":"handStore","fct_Date":"3/3/2017","fdl_UniyPrice":55000,"fdl_TotalPrice":3300000,"ShamsiDate":"1395/12/13","mrq_No":"577","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"Human2","fdl_Num":60},{"slr_Name":"handStore","fct_Date":"3/26/2017","fdl_UniyPrice":70000,"fdl_TotalPrice":252000,"ShamsiDate":"1396/01/06","mrq_No":"1","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"boss office","fdl_Num":3.6},{"slr_Name":"B Store","fct_Date":"5/2/2017","fdl_UniyPrice":68000,"fdl_TotalPrice":89760,"ShamsiDate":"1396/02/12","mrq_No":"324","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"boss office","fdl_Num":1.32},{"slr_Name":"Y Store","fct_Date":"5/7/2017","fdl_UniyPrice":40000,"fdl_TotalPrice":1360000,"ShamsiDate":"1396/02/17","mrq_No":"303","drq_SaleSplName":"AZ","mrq_Requester_dep_title":"D & F Manage","fdl_Num":34},{"slr_Name":"handStore","fct_Date":"5/9/2017","fdl_UniyPrice":53600,"fdl_TotalPrice":268000,"ShamsiDate":"1396/02/19","mrq_No":"866","drq_SaleSplName":"AZ","mrq_Requester_dep_title":"manage office","fdl_Num":5},{"slr_Name":"Y Store","fct_Date":"5/14/2017","fdl_UniyPrice":70000,"fdl_TotalPrice":1062600,"ShamsiDate":"1396/02/24","mrq_No":"445","drq_SaleSplName":"ES Ja","mrq_Requester_dep_title":"Wom","fdl_Num":15.18},{"slr_Name":"handStore","fct_Date":"5/24/2017","fdl_UniyPrice":50000,"fdl_TotalPrice":300000,"ShamsiDate":"1396/03/03","mrq_No":"866","drq_SaleSplName":"AZ","mrq_Requester_dep_title":"manage office","fdl_Num":6},{"slr_Name":"Y Store","fct_Date":"5/29/2017","fdl_UniyPrice":50000,"fdl_TotalPrice":920000,"ShamsiDate":"1396/03/08","mrq_No":"866","drq_SaleSplName":"AZ","mrq_Requester_dep_title":"manage office","fdl_Num":18.4},{"slr_Name":"Y Store","fct_Date":"8/19/2017","fdl_UniyPrice":37000,"fdl_TotalPrice":370000,"ShamsiDate":"1396/05/28","mrq_No":"2496","drq_SaleSplName":"AZ","mrq_Requester_dep_title":"D & F Manage","fdl_Num":10},{"slr_Name":"Sh Store","fct_Date":"9/4/2017","fdl_UniyPrice":65000,"fdl_TotalPrice":195000,"ShamsiDate":"1396/06/13","mrq_No":"2885","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"D Center","fdl_Num":3},{"slr_Name":"Y Store","fct_Date":"10/9/2017","fdl_UniyPrice":40000,"fdl_TotalPrice":800000,"ShamsiDate":"1396/07/17","mrq_No":"3753","drq_SaleSplName":"AZ","mrq_Requester_dep_title":"D & F Manage","fdl_Num":20},{"slr_Name":"handStore","fct_Date":"10/19/2017","fdl_UniyPrice":40000,"fdl_TotalPrice":520000,"ShamsiDate":"1396/07/27","mrq_No":"4068","drq_SaleSplName":"F P","mrq_Requester_dep_title":"MH","fdl_Num":13},{"slr_Name":"Seasson Store","fct_Date":"10/21/2017","fdl_UniyPrice":35000,"fdl_TotalPrice":4060000,"ShamsiDate":"1396/07/29","mrq_No":"4068","drq_SaleSplName":"F P","mrq_Requester_dep_title":"MH","fdl_Num":116},{"slr_Name":"Seasson Store","fct_Date":"10/21/2017","fdl_UniyPrice":29000,"fdl_TotalPrice":2610000,"ShamsiDate":"1396/07/29","mrq_No":"3898","drq_SaleSplName":"F P","mrq_Requester_dep_title":"MH","fdl_Num":90},{"slr_Name":"Seasson Store","fct_Date":"10/22/2017","fdl_UniyPrice":30000,"fdl_TotalPrice":180000,"ShamsiDate":"1396/07/30","mrq_No":"4068","drq_SaleSplName":"F P","mrq_Requester_dep_title":"MH","fdl_Num":6},{"slr_Name":"Aba Store","fct_Date":"10/23/2017","fdl_UniyPrice":30000,"fdl_TotalPrice":300000,"ShamsiDate":"1396/08/01","mrq_No":"1","drq_SaleSplName":"","mrq_Requester_dep_title":"Store","fdl_Num":10},{"slr_Name":"Aba Store","fct_Date":"4/8/2018","fdl_UniyPrice":32000,"fdl_TotalPrice":224000,"ShamsiDate":"1397/01/19","mrq_No":"4142","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"EST","fdl_Num":7},{"slr_Name":"Hob Store","fct_Date":"5/12/2018","fdl_UniyPrice":32000,"fdl_TotalPrice":96000,"ShamsiDate":"1397/02/22","mrq_No":"2","drq_SaleSplName":"MBA","mrq_Requester_dep_title":"Center Off","fdl_Num":3}];
//var parseDate = d3.timeFormat("%m %d %Y").parse;
myData.forEach(function (d) {
var parseDate = d3.timeParse("%m/%d/%Y")
d.fct_Date = parseDate(d.fct_Date);
/* var newD = new Date(d.fct_Date);
var jdate3 = new JDate(newD); */
formatYear = d3.timeFormat("%Y");
d.year = formatYear(d.fct_Date);
});
var data = crossfilter(myData);
var sellers = [];
for (var d in myData) {
if (sellers.indexOf(myData[d].slr_Name) == -1) {
sellers.push(myData[d].slr_Name);
}
}
// var colorScale = d3.scale.ordinal().range(['#DB0A5B', '#F62459', '#F1A9A0', '#2C3E50', '#26A65B', '#E87E04', '#D35400']);
var sellerDimension = data.dimension(function (d) {
return d.slr_Name;
});
var sellerGroup = sellerDimension.group().reduceSum(function (d) {
return d.fdl_Num;
});
var sellerChart = dc.barChart('#sellerChart');
sellerChart
.height(300)
.width(700)
.dimension(sellerDimension)
.group(sellerGroup)
.x(d3.scaleBand())
.xUnits(dc.units.ordinal)
.xAxisLabel('Sellers')
.yAxisLabel('Count')
.elasticX(true)
.elasticY(true)
.xAxis().ticks(3);
sellerChart.title(function (d) {
return d.key + ' : ' + d.value;
});
// sellerChart.xAxis().tickValues([]);
// sellerChart.colors(d3.scale.ordinal().range(colorScale));
/**************************************************/
/* Data Unit Price Chart
/**************************************************/
var dateDimension = data.dimension(function (d) {
return d.fct_Date;
});
var unitPriceGroup = dateDimension.group().reduce(
//return d.fdl_UniyPrice;
//add
function (p, v) {
++p.count;
p.total += v.fdl_UniyPrice;
if (p.count == 0) {
p.average = 0;
} else {
p.average = p.total / p.count;
}
return p;
},
// remove
function (p, v) {
--p.count;
p.total -= v.fdl_UniyPrice;
if (p.count == 0) {
p.average = 0;
} else {
p.average = p.total / p.count;
}
return p;
},
// initial
function () {
return {
count: 0,
total: 0,
average: 0
};
}
);
var formatTime = d3.timeFormat("%B %d, %Y");
var minDate = formatTime(dateDimension.bottom(1)[0].fct_Date);
var maxDate = formatTime(dateDimension.top(1)[0].fct_Date);
var dateUnitPriceChart = dc.lineChart('#dateunitprice');
dateUnitPriceChart
.height(250)
.width(700)
.curve(d3.curveStepAfter)
.renderArea(true)
.dimension(dateDimension)
.group(unitPriceGroup)
.brushOn(true)
.elasticX(true)
.elasticY(true)
.valueAccessor(function (d) {
return d.value.average;
})
.x(d3.scaleTime());
/* dateUnitPriceChart.xAxis().tickFormat(function (val) {
console.log(val);
var newD = new Date(val);
var jdate3 = new JDate(newD);
if (jdate3.getMonth() === 1) {
return jdate3.format('YYYY'); //return a year in number like 1396
}
return jdate3.format('MMMM'); //return month like azar
}); */
dateUnitPriceChart.margins().left = 70;
/** Create Data Table */
var datatable = dc.dataTable('#data-table');
datatable
.dimension(sellerDimension)
.group(function (d) {
return d.year;
})
.size(10000)
// dynamic columns creation using an array of closures
.columns([
function (d) {
return d.mrq_No
},
function (d) {
return d.mrq_Requester_dep_title
},
function (d) {
return d.drq_SaleSplName
},
function (d) {
return d.slr_Name
},
function (d) {
//return d.fct_Date.getFullYear() + ' ' + d.fct_Date.getMonth() + ' ' + d.fct_Date.getDate();
return d.ShamsiDate;
},
function (d) {
return d.fdl_UniyPrice.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); ;
},
function (d) {
return d.fdl_Num;
}
])
.showGroups(false)
.sortBy(function (d) {
return d.slr_Name;
})
.order(d3.ascending);
datatable.title(function (d) {
return d.key + ' : ' + d.value;
});
datatable.ordering(function (d) {
return d.ShamsiDate
})
/***********************/
dc.renderAll();
<link href="https://dc-js.github.io/dc.js/css/dc.css" rel="stylesheet"/>
<script src="https://dc-js.github.io/dc.js/js/crossfilter.js"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://dc-js.github.io/dc.js/js/dc.js"></script>
</script>
<div style="margin-top: -50px;">
<div class="divForms" style="border: solid; border-color: gray; border-radius: 5px; border-width: 1px; text-align:center; padding-left:20px;">
<div style="margin-bottom: 20px; width: 100%;">
<div style="text-align: right; padding-right: 20px; float: right; width: 44%;">
<a id="lnk_Reset" href="javascript:dc.filterAll(); dc.renderAll();">Reset</a>
</div>
<div style="text-align: center; float: right;">
<span>کالا : </span>
<b>
<asp:Label ID="lbl_Good" runat="server" Text=""></asp:Label></b>
</div>
</div>
<div id="sellerChart" style="direction: ltr !important"></div>
<div id="dateunitprice" style="direction: ltr !important"></div>
<table class="table table-condensed table-striped table-bordered table-hover no-margin" border="1" id="data-table" style="width: 100%; border-collapse: collapse; margin-left:5px;">
<thead>
<tr class="HeaderStyle" style="color: #6484E5;">
<th class="text-center" scope="col">Num Request</th>
<th class="text-center" scope="col">Unit Requested</th>
<th class="text-center" scope="col">User</th>
<th class="text-center" scope="col">Seller</th>
<th class="text-center" scope="col">Date</th>
<th class="text-center" scope="col">Unit Price</th>
<th class="text-center" scope="col">Count</th>
</tr>
</thead>
</table>
</div>
</div>
Build with latest version of dc and d3
Bar chart replaced with line chart (Get narrow line for each date)
Puzzling problem:
My d3 chart, which has a day selector (right arrow) works in a stand-alone file. By "works" I mean when you click on the right arrow it advances through the data array and the chart bars update.
However, inside a jquery mobile multipage document, it won't work in Firefox. In jqm multipage it does work in Chrome (linux and windows) and IE.
Briefly, you click on the "chart page," then click on the right arrow to view the data for each day.
Don't worry about the arrow code, I have to fix it. What worries me is that this doesn't work in Firefox.
Here is the fiddle. Try it in those browsers.
html:
<!-- Start of first page: #one -->
<div data-role='page' id='one'>
<div data-role='header'>
<h1>Multi-page</h1>
</div>
<!-- /header -->
<div data-role='content'>
<h2>One</h2>
<p>I have an <code>id</code> of 'one' on my page container. I'm first in the source order so I'm shown when the page loads.</p>
<h3>Show internal pages:</h3>
<p><a href='#snapshot-chart-page' data-role='button'>Chart page</a></p>
</div>
<!-- /content -->
<div data-role='footer' data-theme='d'>
<h4>Page Footer</h4>
</div>
<!-- /footer -->
</div>
<!-- /page one -->
<div data-role='page' id='snapshot-chart-page' data-ajax='false'>
<div data-role='header' style='background:#82ca46;'>
<a href='#nav-panel' data-icon='bars' data-iconpos='notext' class='ui-nodisc-icon' style='background-color: transparent;'>Menu</a>
<div align='center' style='vertical-align:top;'>
<h1>Page title
</h1></div>
<a href='#add-form' data-icon='calendar' data-iconpos='notext' class='ui-nodisc-icon' style='background-color: transparent;'>Add</a>
</div>
<!-- /header -->
<div role='main' class='ui-content'>
<div style='width:100%; margin: 0;padding: 0; overflow: auto;'>
<form style='display: inline-block;
position: relative;
vertical-align: middle;
margin-right: 6px;'>
<input type='button' data-role='button' data-icon='arrow-l' data-iconpos='notext' class='ui-nodisc-icon previous-next-period left-previous select-custom-14' style='background-color: transparent;' field='quantity'>
<input type='text' name='quantity' value='0' class='qty' />
<input type='button' data-role='button' data-icon='arrow-r' data-iconpos='notext' class='ui-nodisc-icon previous-next-period right-next select-custom-14' style='background-color: transparent;' field='quantity'>
</form>
<table data-role='table' data-transition='fade' class='ghg-tables'>
<caption class='barchart_title tabletitle'></caption>
<thead>
</thead>
</table>
<div class='chart-here'></div>
</div>
</div>
<!-- /main -->
</div>
<!-- /snapshot-chart-page -->
js:
(function() {
var margin = {
top: 20,
right: 20,
bottom: 40,
left: 80
},
width = 340 - margin.left - margin.right,
height = 250 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1, 1);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient('bottom');
var svg = d3.select('.chart-here').append('svg')
.attr('viewBox', '0 0 340 250')
.attr('preserveAspectRatio', 'xMinYMin meet')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left / 1.5 + ',' + margin.top / 1.5 + ')');
var yAxis = d3.svg.axis()
.scale(y)
.orient('left')
.ticks(5)
.outerTickSize(0)
.tickFormat(d3.format(',.3s'));
var barchart_i = 0;
var arr1 = [{
"period": "day",
"allcars_title": "Mileage by car, on Tuesday, March 01 2016. Total: 454.95M mi.",
"car": [{
"Chevvy": 33733000
}, {
"Ford": 32633000
}, {
"Honda": 119182000
}, {
"Tesla": 614000
}, {
"Audi": 268292000
}, {
"Hummer": 493000
}]
}, {
"period": "day",
"allcars_title": "Mileage by car, on Wednesday, March 02 2016. Total: 457.26M mi.",
"car": [{
"Chevvy": 23052000
}, {
"Ford": 44630000
}, {
"Honda": 121635000
}, {
"Tesla": 2599000
}, {
"Audi": 264247000
}, {
"Hummer": 1100000
}]
}, {
"period": "day",
"allcars_title": "Mileage by car, on Thursday, March 03 2016. Total: 452.96M mi.",
"car": [{
"Chevvy": 8577000
}, {
"Ford": 54172000
}, {
"Honda": 121661000
}, {
"Tesla": 1975000
}, {
"Audi": 265483000
}, {
"Hummer": 1089000
}]
}];
var period_grain = arr1[0].period;
var allcars_hour = arr1[barchart_i];
var car = allcars_hour.car;
var allcars_dash_title = allcars_hour.allcars_title;
jQuery('.barchart_title').text(allcars_dash_title);
var newobj = [];
for (var allcars_hourx1 = 0; allcars_hourx1 < car.length; allcars_hourx1++) {
var xx = car[allcars_hourx1];
for (var value in xx) {
var chartvar = newobj.push({
car: value,
miles: xx[value]
});
var data = newobj;
data = data.sort(function(a, b) {
return b.miles - a.miles;
});
}
}
x.domain(data.map(function(d) {
return d.car;
}));
if (period_grain == 'hour') {
var staticMax = 13000000;
}
if (period_grain == 'day') {
var staticMax = 300000000;
}
if (period_grain == 'month') {
var staticMax = 2000000;
}
if (period_grain == 'year') {
var staticMax = 35000000;
}
y.domain([0, d3.max(data, function(d) {
return d.miles > staticMax ? d.miles : staticMax;
})]);
svg.append('g')
.attr('class', 'y axis')
.call(yAxis)
.append('text')
.attr('y', 6)
.attr('dy', '.71em')
.style('text-anchor', 'start');
var changeHour = function() {
var dataJoin = svg.selectAll('.bar')
.data(data, function(d) {
return d.car;
});
svg.selectAll('.y.axis')
.call(yAxis);
xtext = svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(-20,' + height + ')') /*move tick text so it aligns with rects*/
.call(xAxis)
/* possible new elements, fired first time, set non-data dependent attributes*/
dataJoin
.enter()
.append('rect')
.attr('class', 'bar')
.attr('transform', 'translate(-20)') /*move rects closer to Y axis*/
/* changes to existing elements (now including the newly appended elements from above) which depend on data values (d)*/
dataJoin
.attr('x', function(d) {
return x(d.car);
})
.attr('width', x.rangeBand() * 1)
.attr('y', function(d) {
return y(d.miles);
})
.attr('height', function(d) {
return height - y(d.miles);
})
.style('fill', function(d) {
if (d.car == 'Audi' || d.car == 'Chevvy' || d.car == 'Honda' || d.car == 'Hummer') {
return 'green';
} else {
return '#404040';
}
})
xtext.selectAll('text')
.attr('transform', function(d) {
return 'translate(' + this.getBBox().height * 50 + ',' + this.getBBox().height + ')rotate(0)';
});
dataJoin.exit().remove();
}
changeHour();
//function to allow user to click arrows to view next/previous period_grain
// This button will increment the value
$('.right-next').click(function(e) {
// Stop acting like a button
e.preventDefault();
// Get the field name
fieldName = $(this).attr('field');
// Get its current value
barchart_i = parseInt($('input[name=' + fieldName + ']').val());
// If is not undefined
if (!isNaN(barchart_i)) {
// Increment
$('input[name=' + fieldName + ']').val(barchart_i + 1);
} else {
// Otherwise set to 0
$('input[name=' + fieldName + ']').val(0);
}
incrementHour();
});
// This button will decrement the value till 0
$('.left-previous').click(function(e) {
// Stop acting like a button
e.preventDefault();
// Get the field name
fieldName = $(this).attr('field');
// Get its current value
barchart_i = parseInt($('input[name=' + fieldName + ']').val());
// If it isn't undefined or if it is greater than 0
if (!isNaN(barchart_i) && barchart_i > 0) {
// Decrement one
$('input[name=' + fieldName + ']').val(barchart_i - 1);
} else {
// Otherwise set to 0
$('input[name=' + fieldName + ']').val(0);
}
incrementHour();
});
incrementHour = function() {
allcars_hour = arr1[barchart_i];
var car = allcars_hour.car;
var allcars_dash_title = allcars_hour.allcars_title;
var newobj = [];
for (var allcars_hourx1 = 0; allcars_hourx1 < car.length; allcars_hourx1++) {
var xx = car[allcars_hourx1];
for (var value in xx) {
var chartvar = newobj.push({
car: value,
miles: xx[value]
});
}
}
data = newobj;
console.log('data is ' + data);
data = data.sort(function(a, b) {
return b.miles - a.miles;
});
x.domain(data.map(function(d) {
return d.car;
}));
y.domain([0, d3.max(data, function(d) {
return d.miles > staticMax ? d.miles : staticMax;
})]);
jQuery('.barchart_title').text(allcars_dash_title);
changeHour();
};
})();
This is bizarre. I have researched this extensively, and cannot find anything that relates to it.
Has anybody else encountered this? If so, are there any ideas how to fix it?
Trying to develop a data visualization app with d3.js
Using a local json file named "yelp_test_set_business.json"
When I attempt to use d3.json to load this data, nothing is being passed to the callback function, which, in tern, also triggers an error within crossfilter.js library.
here is my entire file:
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<script src='javascript/d3.js' type='text/javascript'></script>
<script src='javascript/crossfilter.js' type='text/javascript'></script>
<script src='javascript/dc.js' type='text/javascript'></script>
<script src='javascript/jquery-1.12.1.min.js' type='text/javascript'></script>
<script type='text/javascript'>
/********************************************************
* *
* dj.js example using Yelp Kaggle Test Dataset *
* Eol 9th May 2013 *
* *
********************************************************/
/********************************************************
* *
* Step0: Load data from json file *
* *
********************************************************/
d3.json("data/yelp_test_set_business.json", function (yelp_data) {
/********************************************************
* *
* Step1: Create the dc.js chart objects & ling to div *
* *
********************************************************/
var bubbleChart = dc.bubbleChart("#dc-bubble-graph");
var pieChart = dc.pieChart("#dc-pie-graph");
var volumeChart = dc.barChart("#dc-volume-chart");
var lineChart = dc.lineChart("#dc-line-chart");
var dataTable = dc.dataTable("#dc-table-graph");
var rowChart = dc.rowChart("#dc-row-graph");
/********************************************************
* *
* Step2: Run data through crossfilter *
* *
********************************************************/
var ndx = crossfilter(yelp_data);
/********************************************************
* *
* Step3: Create Dimension that we'll need *
* *
********************************************************/
// for volumechart
var cityDimension = ndx.dimension(function (d) { return d.city; });
var cityGroup = cityDimension.group();
var cityDimensionGroup = cityDimension.group().reduce(
//add
function(p,v){
++p.count;
p.review_sum += v.review_count;
p.star_sum += v.stars;
p.review_avg = p.review_sum / p.count;
p.star_avg = p.star_sum / p.count;
return p;
},
//remove
function(p,v){
--p.count;
p.review_sum -= v.review_count;
p.star_sum -= v.stars;
p.review_avg = p.review_sum / p.count;
p.star_avg = p.star_sum / p.count;
return p;
},
//init
function(p,v){
return {count:0, review_sum: 0, star_sum: 0, review_avg: 0, star_avg: 0};
}
);
// for pieChart
var startValue = ndx.dimension(function (d) {
return d.stars*1.0;
});
var startValueGroup = startValue.group();
// For datatable
var businessDimension = ndx.dimension(function (d) { return d.business_id; });
/********************************************************
* *
* Step4: Create the Visualisations *
* *
********************************************************/
bubbleChart.width(650)
.height(300)
.dimension(cityDimension)
.group(cityDimensionGroup)
.transitionDuration(1500)
.colors(["#a60000","#ff0000", "#ff4040","#ff7373","#67e667","#39e639","#00cc00"])
.colorDomain([-12000, 12000])
.x(d3.scale.linear().domain([0, 5.5]))
.y(d3.scale.linear().domain([0, 5.5]))
.r(d3.scale.linear().domain([0, 2500]))
.keyAccessor(function (p) {
return p.value.star_avg;
})
.valueAccessor(function (p) {
return p.value.review_avg;
})
.radiusValueAccessor(function (p) {
return p.value.count;
})
.transitionDuration(1500)
.elasticY(true)
.yAxisPadding(1)
.xAxisPadding(1)
.label(function (p) {
return p.key;
})
.renderLabel(true)
.renderlet(function (chart) {
rowChart.filter(chart.filter());
})
.on("postRedraw", function (chart) {
dc.events.trigger(function () {
rowChart.filter(chart.filter());
});
});
;
pieChart.width(200)
.height(200)
.transitionDuration(1500)
.dimension(startValue)
.group(startValueGroup)
.radius(90)
.minAngleForLabel(0)
.label(function(d) { return d.data.key; })
.on("filtered", function (chart) {
dc.events.trigger(function () {
if(chart.filter()) {
console.log(chart.filter());
volumeChart.filter([chart.filter()-.25,chart.filter()-(-0.25)]);
}
else volumeChart.filterAll();
});
});
volumeChart.width(230)
.height(200)
.dimension(startValue)
.group(startValueGroup)
.transitionDuration(1500)
.centerBar(true)
.gap(17)
.x(d3.scale.linear().domain([0.5, 5.5]))
.elasticY(true)
.on("filtered", function (chart) {
dc.events.trigger(function () {
if(chart.filter()) {
console.log(chart.filter());
lineChart.filter(chart.filter());
}
else
{lineChart.filterAll()}
});
})
.xAxis().tickFormat(function(v) {return v;});
console.log(startValueGroup.top(1)[0].value);
lineChart.width(230)
.height(200)
.dimension(startValue)
.group(startValueGroup)
.x(d3.scale.linear().domain([0.5, 5.5]))
.valueAccessor(function(d) {
return d.value;
})
.renderHorizontalGridLines(true)
.elasticY(true)
.xAxis().tickFormat(function(v) {return v;}); ;
rowChart.width(340)
.height(850)
.dimension(cityDimension)
.group(cityGroup)
.renderLabel(true)
.colors(["#a60000","#ff0000", "#ff4040","#ff7373","#67e667","#39e639","#00cc00"])
.colorDomain([0, 0])
.renderlet(function (chart) {
bubbleChart.filter(chart.filter());
})
.on("filtered", function (chart) {
dc.events.trigger(function () {
bubbleChart.filter(chart.filter());
});
});
dataTable.width(800).height(800)
.dimension(businessDimension)
.group(function(d) { return "List of all Selected Businesses"
})
.size(100)
.columns([
function(d) { return d.name; },
function(d) { return d.city; },
function(d) { return d.stars; },
function(d) { return d.review_count; },
function(d) { return 'Map"}
])
.sortBy(function(d){ return d.stars; })
// (optional) sort order, :default ascending
.order(d3.ascending);
/********************************************************
* *
* Step6: Render the Charts *
* *
********************************************************/
dc.renderAll();
});
</script>
<link href='stylesheets/bootstrap.min.css' rel='stylesheet' type='text/css'>
<!--<link href='stylesheets/dc.css' rel='stylesheet' type='text/css'>-->
<!--<script src='simple_vis.js' type='text/javascript'></script>-->
</head>
<body>
<div class='container' id='main-container'>
<div class='content'>
<div class='container' style='font: 10px sans-serif;'>
<h3>Visualisation of Kaggle Yelp Test Business Data set (using dc.js)</h3>
<h4>Demo for the Dublin Data Visualisation Meetup Group</h4>
<div class='row-fluid'>
<div class='remaining-graphs span8'>
<div class='row-fluid'>
<div class='bubble-graph span12' id='dc-bubble-graph'>
<h4>Average Rating (x-axis), Average Number of Reviews (y-axis), Number of Business' (Size)</h4>
</div>
</div>
<div class='row-fluid'>
<div class='pie-graph span4' id='dc-pie-graph'>
<h4>Average Rating in Stars (Pie)</h4>
</div>
<div class='pie-graph span4' id='dc-volume-chart'>
<h4>Average Rating in Stars / Number of Reviews (Bar)</h4>
</div>
<div class='pie-graph span4' id='dc-line-chart'>
<h4>Average Rating in Stars / Number of Reviews (Line)</h4>
</div>
</div>
<!-- /other little graphs go here -->
<div class='row-fluid'>
<div class='span12 table-graph'>
<h4>Data Table for Filtered Businesses</h4>
<table class='table table-hover dc-data-table' id='dc-table-graph'>
<thead>
<tr class='header'>
<th>Name</th>
<th>City</th>
<th>Review Score (in Stars)</th>
<th>Total Reviews</th>
<th>Location</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
<div class='remaining-graphs span4'>
<div class='row-fluid'>
<div class='row-graph span12' id='dc-row-graph' style='color:black;'>
<h4>Reviews Per City</h4>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
The following call:
d3.json("data/yelp_test_set_business.json", function (yelp_data) { ...}
returns nothing in yelp_data
Does anyone know why this is hapenning?
Instead of doing like this to load your JSON:
d3.json("data/yelp_test_set_business.json", function (yelp_data) {
It should have been:
d3.json("data/yelp_test_set_business.json", function (error, yelp_data) {
Read this
Most of the time, this error is related to the fact that you just open the html file in your browser, which then tries to open the json file using the file:/// protocol, resulting in a cross origin violation.
D3 doc on requests.
One way to fix it is just by using a web server to serve the .html and the .json.
If you have python installed, just go to the folder where you file is located and run python -m SimpleHTTPServer, then navigate with your browser to http://localhost:8080. This way both the .html and .json will be served from the same origin (namely localhost:8080), and you will be able to load file via d3.json, d3.csv, etc...