mirror of
https://forge.chapril.org/tykayn/osm-commerces
synced 2025-10-04 17:04:53 +02:00
ajout de stats sur le budget des villes
This commit is contained in:
parent
1973f85dd4
commit
cd8369d08c
14 changed files with 901 additions and 186 deletions
|
@ -5,6 +5,7 @@
|
|||
{% block body %}
|
||||
<div class="container mt-4">
|
||||
<h1>Histogramme de fraîcheur des données OSM</h1>
|
||||
<p></p>
|
||||
<h2>Par année</h2>
|
||||
<canvas id="fraicheurHistogrammeAnnee" width="800" height="400" style="max-width:100%; margin: 20px 0;"></canvas>
|
||||
<h2>Par trimestre</h2>
|
||||
|
@ -18,10 +19,30 @@
|
|||
<p>
|
||||
Une ville avec un petit nombre d'habitants par lieu sera très fournie en services divers et variés, sur la gauche de ce graphique de répartition. Survolez pour voir les noms des villes les plus civilisées. À droite du graphique, vous êtes plus proche d'habiter dans un désert.
|
||||
</p>
|
||||
|
||||
<h2>Distribution des villes selon le budget par habitant (par pas de 100€)</h2>
|
||||
<canvas id="distributionBudgetParHabitant" width="800" height="400" style="max-width:100%; margin: 20px 0;"></canvas>
|
||||
<p>
|
||||
Ce graphique montre la répartition des villes selon leur budget annuel par habitant. Les villes avec un budget élevé par habitant sont sur la droite du graphique.
|
||||
</p>
|
||||
|
||||
<h2>Distribution des villes selon l'écart à la moyenne du budget par habitant (par pas de 10%)</h2>
|
||||
<canvas id="distributionEcartBudget" width="800" height="400" style="max-width:100%; margin: 20px 0;"></canvas>
|
||||
<p>
|
||||
Ce graphique montre les villes sous-cartographiées selon l'écart à la moyenne du budget par habitant. Les villes avec un écart négatif (gauche) ont un budget inférieur à la moyenne, celles avec un écart positif (droite) ont un budget supérieur à la moyenne.
|
||||
</p>
|
||||
|
||||
<h2>Distribution des villes selon le budget par lieu (par pas de 5000€)</h2>
|
||||
<canvas id="distributionBudgetParLieu" width="800" height="400" style="max-width:100%; margin: 20px 0;"></canvas>
|
||||
<p>
|
||||
Ce graphique montre la répartition des villes selon leur budget annuel par lieu. Les villes avec un budget élevé par commerce sont sur la droite du graphique.
|
||||
</p>
|
||||
|
||||
<div id="fraicheurMeta" class="mb-3"></div>
|
||||
<a href="{{ path('admin_fraicheur_calculate') }}" class="btn btn-primary">Régénérer les statistiques</a>
|
||||
<a href="{{ path('admin_fraicheur_download') }}" class="btn btn-secondary">Télécharger le JSON des lieux</a>
|
||||
<a href="{{ path('admin_distribution_villes_lieux_par_habitant_download') }}" class="btn btn-secondary">Télécharger le JSON villes/lieux/habitant</a>
|
||||
<a href="{{ path('admin_budget_download') }}" class="btn btn-secondary">Télécharger le JSON budget</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -37,37 +58,40 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
document.getElementById('fraicheurMeta').innerHTML = '<div class="alert alert-danger">'+data.error+'</div>';
|
||||
return;
|
||||
}
|
||||
const ctx = document.getElementById('fraicheurHistogramme').getContext('2d');
|
||||
const labels = Object.keys(data.histogram);
|
||||
const values = Object.values(data.histogram);
|
||||
document.getElementById('fraicheurMeta').innerHTML =
|
||||
'<b>Date de génération :</b> ' + data.generated_at + '<br>' +
|
||||
'<b>Total lieux :</b> ' + data.total;
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Nombre de lieux modifiés ce mois',
|
||||
data: values,
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.7)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: 'Fraîcheur des données OSM (par mois)' }
|
||||
const canvasFraicheur = document.getElementById('fraicheurHistogramme');
|
||||
if (canvasFraicheur) {
|
||||
const ctx = canvasFraicheur.getContext('2d');
|
||||
const labels = Object.keys(data.histogram);
|
||||
const values = Object.values(data.histogram);
|
||||
document.getElementById('fraicheurMeta').innerHTML =
|
||||
'<b>Date de génération :</b> ' + data.generated_at + '<br>' +
|
||||
'<b>Total lieux :</b> ' + data.total;
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Nombre de lieux modifiés ce mois',
|
||||
data: values,
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.7)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de lieux' } },
|
||||
x: { title: { display: true, text: 'Mois' } }
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: 'Fraîcheur des données OSM (par mois)' }
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de lieux' } },
|
||||
x: { title: { display: true, text: 'Mois' } }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Agrégation par trimestre
|
||||
const trimestreAgg = {};
|
||||
|
@ -85,32 +109,35 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
}
|
||||
const trimestreLabels = Object.keys(trimestreAgg).sort();
|
||||
const trimestreValues = trimestreLabels.map(k => trimestreAgg[k]);
|
||||
const ctxTrim = document.getElementById('fraicheurHistogrammeTrimestre').getContext('2d');
|
||||
new Chart(ctxTrim, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: trimestreLabels,
|
||||
datasets: [{
|
||||
label: 'Nombre de lieux modifiés ce trimestre',
|
||||
data: trimestreValues,
|
||||
backgroundColor: 'rgba(255, 159, 64, 0.7)',
|
||||
borderColor: 'rgba(255, 159, 64, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: 'Fraîcheur des données OSM (par trimestre)' }
|
||||
const canvasTrim = document.getElementById('fraicheurHistogrammeTrimestre');
|
||||
if (canvasTrim) {
|
||||
const ctxTrim = canvasTrim.getContext('2d');
|
||||
new Chart(ctxTrim, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: trimestreLabels,
|
||||
datasets: [{
|
||||
label: 'Nombre de lieux modifiés ce trimestre',
|
||||
data: trimestreValues,
|
||||
backgroundColor: 'rgba(255, 159, 64, 0.7)',
|
||||
borderColor: 'rgba(255, 159, 64, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de lieux' } },
|
||||
x: { title: { display: true, text: 'Trimestre' } }
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: 'Fraîcheur des données OSM (par trimestre)' }
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de lieux' } },
|
||||
x: { title: { display: true, text: 'Trimestre' } }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Agrégation par année
|
||||
const anneeAgg = {};
|
||||
|
@ -122,39 +149,43 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
}
|
||||
const anneeLabels = Object.keys(anneeAgg).sort();
|
||||
const anneeValues = anneeLabels.map(k => anneeAgg[k]);
|
||||
const ctxAnnee = document.getElementById('fraicheurHistogrammeAnnee').getContext('2d');
|
||||
new Chart(ctxAnnee, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: anneeLabels,
|
||||
datasets: [{
|
||||
label: 'Nombre de lieux modifiés cette année',
|
||||
data: anneeValues,
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.7)',
|
||||
borderColor: 'rgba(75, 192, 192, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: 'Fraîcheur des données OSM (par année)' }
|
||||
const canvasAnnee = document.getElementById('fraicheurHistogrammeAnnee');
|
||||
if (canvasAnnee) {
|
||||
const ctxAnnee = canvasAnnee.getContext('2d');
|
||||
new Chart(ctxAnnee, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: anneeLabels,
|
||||
datasets: [{
|
||||
label: 'Nombre de lieux modifiés cette année',
|
||||
data: anneeValues,
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.7)',
|
||||
borderColor: 'rgba(75, 192, 192, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de lieux' } },
|
||||
x: { title: { display: true, text: 'Année' } }
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: 'Fraîcheur des données OSM (par année)' }
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de lieux' } },
|
||||
x: { title: { display: true, text: 'Année' } }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Histogramme distribution villes/lieux/habitant
|
||||
fetch('/admin/distribution_villes_lieux_par_habitant_download')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if(data.error){
|
||||
document.getElementById('distributionVillesLieuxParHabitant').insertAdjacentHTML('afterend', '<div class="alert alert-danger">Erreur de chargement des données : '+data.error+'</div>');
|
||||
const canvasVLPH = document.getElementById('distributionVillesLieuxParHabitant');
|
||||
if(canvasVLPH) canvasVLPH.insertAdjacentHTML('afterend', '<div class="alert alert-danger">Erreur de chargement des données : '+data.error+'</div>');
|
||||
return;
|
||||
}
|
||||
// Histogramme habitants par lieu (pas de 10)
|
||||
|
@ -162,99 +193,248 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
.then(r2 => r2.json())
|
||||
.then(villesData => {
|
||||
// Histogramme habitants par lieu
|
||||
if(!data.histogram_10){
|
||||
document.getElementById('distributionHabitantsParLieu').insertAdjacentHTML('afterend', '<div class="alert alert-danger">Erreur : données histogram_10 absentes. Cliquez sur "Régénérer les statistiques".</div>');
|
||||
return;
|
||||
}
|
||||
const ctxHPL = document.getElementById('distributionHabitantsParLieu').getContext('2d');
|
||||
const labelsHPL = Object.keys(data.histogram_10);
|
||||
const valuesHPL = Object.values(data.histogram_10);
|
||||
const villesByBin10 = villesData.villes_by_bin_10 || {};
|
||||
console.log('HPL', labelsHPL, villesByBin10);
|
||||
new Chart(ctxHPL, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labelsHPL,
|
||||
datasets: [{
|
||||
label: "Nombre de villes",
|
||||
data: valuesHPL,
|
||||
backgroundColor: 'rgba(255, 99, 132, 0.7)',
|
||||
borderColor: 'rgba(255, 99, 132, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: "Distribution des villes par habitants/lieu (par pas de 10)" },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
afterBody: function(context) {
|
||||
const bin = context[0].label;
|
||||
const villes = villesByBin10[bin] || [];
|
||||
if(villes.length > 0){
|
||||
return ['Villes :'].concat(villes.map(v => '• ' + v));
|
||||
const canvasHPL = document.getElementById('distributionHabitantsParLieu');
|
||||
if(canvasHPL && data.histogram_10){
|
||||
const ctxHPL = canvasHPL.getContext('2d');
|
||||
const labelsHPL = Object.keys(data.histogram_10);
|
||||
const valuesHPL = Object.values(data.histogram_10);
|
||||
const villesByBin10 = villesData.villes_by_bin_10 || {};
|
||||
new Chart(ctxHPL, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labelsHPL,
|
||||
datasets: [{
|
||||
label: "Nombre de villes",
|
||||
data: valuesHPL,
|
||||
backgroundColor: 'rgba(255, 99, 132, 0.7)',
|
||||
borderColor: 'rgba(255, 99, 132, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: "Distribution des villes par habitants/lieu (par pas de 10)" },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
afterBody: function(context) {
|
||||
const bin = context[0].label;
|
||||
const villes = villesByBin10[bin] || [];
|
||||
if(villes.length > 0){
|
||||
return ['Villes :'].concat(villes.map(v => '• ' + v));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de villes' } },
|
||||
x: { title: { display: true, text: 'Habitants par lieu (arrondi à 10)' } }
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de villes' } },
|
||||
x: { title: { display: true, text: 'Habitants par lieu (arrondi à 10)' } }
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
// Histogramme lieux/habitant (pas de 0.01)
|
||||
if(!data.histogram_001){
|
||||
document.getElementById('distributionVillesLieuxParHabitant').insertAdjacentHTML('afterend', '<div class="alert alert-danger">Erreur : données histogram_001 absentes. Cliquez sur "Régénérer les statistiques".</div>');
|
||||
return;
|
||||
}
|
||||
const ctx = document.getElementById('distributionVillesLieuxParHabitant').getContext('2d');
|
||||
const labels = Object.keys(data.histogram_001);
|
||||
const values = Object.values(data.histogram_001);
|
||||
const villesByBin001 = villesData.villes_by_bin_001 || {};
|
||||
console.log('LPH', labels, villesByBin001);
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: "Nombre de villes",
|
||||
data: values,
|
||||
backgroundColor: 'rgba(153, 102, 255, 0.7)',
|
||||
borderColor: 'rgba(153, 102, 255, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: "Distribution des villes par lieux/habitant (par pas de 0,01)" },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
afterBody: function(context) {
|
||||
const bin = context[0].label;
|
||||
const villes = villesByBin001[bin] || [];
|
||||
if(villes.length > 0){
|
||||
return ['Villes :'].concat(villes.map(v => '• ' + v));
|
||||
const canvasVLPH = document.getElementById('distributionVillesLieuxParHabitant');
|
||||
if(canvasVLPH && data.histogram_001){
|
||||
const ctx = canvasVLPH.getContext('2d');
|
||||
const labels = Object.keys(data.histogram_001);
|
||||
const values = Object.values(data.histogram_001);
|
||||
const villesByBin001 = villesData.villes_by_bin_001 || {};
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: "Nombre de villes",
|
||||
data: values,
|
||||
backgroundColor: 'rgba(153, 102, 255, 0.7)',
|
||||
borderColor: 'rgba(153, 102, 255, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: "Distribution des villes par lieux/habitant (par pas de 0,01)" },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
afterBody: function(context) {
|
||||
const bin = context[0].label;
|
||||
const villes = villesByBin001[bin] || [];
|
||||
if(villes.length > 0){
|
||||
return ['Villes :'].concat(villes.map(v => '• ' + v));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de villes' } },
|
||||
x: { title: { display: true, text: 'Lieux par habitant (arrondi à 0,01)' } }
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de villes' } },
|
||||
x: { title: { display: true, text: 'Lieux par habitant (arrondi à 0,01)' } }
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Histogrammes budgétaires
|
||||
fetch('/admin/budget/download')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if(data.error){
|
||||
const canvasBudget = document.getElementById('distributionBudgetParHabitant');
|
||||
if(canvasBudget) canvasBudget.insertAdjacentHTML('afterend', '<div class="alert alert-danger">Erreur de chargement des données budgétaires : '+data.error+'</div>');
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('/admin/budget/villes')
|
||||
.then(r2 => r2.json())
|
||||
.then(villesData => {
|
||||
// Histogramme budget par habitant
|
||||
const canvasBudget = document.getElementById('distributionBudgetParHabitant');
|
||||
if(canvasBudget && data.histogram_budget_par_habitant){
|
||||
const ctxBudget = canvasBudget.getContext('2d');
|
||||
const labelsBudget = Object.keys(data.histogram_budget_par_habitant);
|
||||
const valuesBudget = Object.values(data.histogram_budget_par_habitant);
|
||||
const villesByBinBudget = villesData.villes_by_bin_budget || {};
|
||||
new Chart(ctxBudget, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labelsBudget,
|
||||
datasets: [{
|
||||
label: "Nombre de villes",
|
||||
data: valuesBudget,
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.7)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: "Distribution des villes par budget par habitant (par pas de 100€)" },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
afterBody: function(context) {
|
||||
const bin = context[0].label;
|
||||
const villes = villesByBinBudget[bin] || [];
|
||||
if(villes.length > 0){
|
||||
return ['Villes :'].concat(villes.map(v => '• ' + v));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de villes' } },
|
||||
x: { title: { display: true, text: 'Budget par habitant (€, arrondi à 100)' } }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Histogramme écart à la moyenne
|
||||
const canvasEcart = document.getElementById('distributionEcartBudget');
|
||||
if(canvasEcart && data.histogram_ecart_moyenne){
|
||||
const ctxEcart = canvasEcart.getContext('2d');
|
||||
const labelsEcart = Object.keys(data.histogram_ecart_moyenne);
|
||||
const valuesEcart = Object.values(data.histogram_ecart_moyenne);
|
||||
const villesByBinEcart = villesData.villes_by_bin_ecart || {};
|
||||
new Chart(ctxEcart, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labelsEcart,
|
||||
datasets: [{
|
||||
label: "Nombre de villes",
|
||||
data: valuesEcart,
|
||||
backgroundColor: 'rgba(255, 206, 86, 0.7)',
|
||||
borderColor: 'rgba(255, 206, 86, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: "Distribution des villes par écart à la moyenne du budget par habitant (par pas de 10%)" },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
afterBody: function(context) {
|
||||
const bin = context[0].label;
|
||||
const villes = villesByBinEcart[bin] || [];
|
||||
if(villes.length > 0){
|
||||
return ['Villes :'].concat(villes.map(v => '• ' + v));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de villes' } },
|
||||
x: { title: { display: true, text: 'Écart à la moyenne (%)' } }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Histogramme budget par lieu
|
||||
const canvasBudgetParLieu = document.getElementById('distributionBudgetParLieu');
|
||||
if(canvasBudgetParLieu && data.histogram_budget_par_lieu){
|
||||
const ctxBudgetParLieu = canvasBudgetParLieu.getContext('2d');
|
||||
const labelsBudgetParLieu = Object.keys(data.histogram_budget_par_lieu);
|
||||
const valuesBudgetParLieu = Object.values(data.histogram_budget_par_lieu);
|
||||
const villesByBinBudgetParLieu = data.villes_by_bin_budget_par_lieu || {};
|
||||
new Chart(ctxBudgetParLieu, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labelsBudgetParLieu,
|
||||
datasets: [{
|
||||
label: "Nombre de villes",
|
||||
data: valuesBudgetParLieu,
|
||||
backgroundColor: 'rgba(255, 99, 71, 0.7)',
|
||||
borderColor: 'rgba(255, 99, 71, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: "Distribution des villes par budget par lieu (par pas de 5000€)" },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
afterBody: function(context) {
|
||||
const bin = context[0].label;
|
||||
const villes = villesByBinBudgetParLieu[bin] || [];
|
||||
if(villes.length > 0){
|
||||
return ['Villes :'].concat(villes.map(v => '• ' + v));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de villes' } },
|
||||
x: { title: { display: true, text: 'Budget par lieu (€, arrondi à 5000)' } }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -80,6 +80,25 @@
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% if stats.budgetAnnuel %}
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-4 col-12">
|
||||
<span class="badge bg-warning text-dark">
|
||||
<i class="bi bi-cash-coin"></i> Budget annuel : {{ stats.budgetAnnuel|number_format(0, '.', ' ') }} €
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md-4 col-12">
|
||||
<span class="badge bg-warning text-dark">
|
||||
<i class="bi bi-cash-stack"></i> Budget par habitant :
|
||||
{% if stats.population > 0 %}
|
||||
{{ (stats.budgetAnnuel / stats.population)|number_format(0, '.', ' ') }} €
|
||||
{% else %}
|
||||
?
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{# Affichage de la fraîcheur des données OSM #}
|
||||
|
|
|
@ -16,13 +16,23 @@
|
|||
<i class="bi bi-envelope-fill"></i>
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{% if commerce.email is defined and commerce.email %}
|
||||
<div style="max-width: 350px; white-space: pre-wrap; word-break: break-all;">{{ commerce.email }}</div>
|
||||
{% else %}
|
||||
<span class="text-muted">-</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right completion-cell"
|
||||
style="background : rgba(0,255,0,{{ commerce.getCompletionPercentage() / 100 }})"
|
||||
data-bs-toggle="popover"
|
||||
data-bs-trigger="hover"
|
||||
data-bs-html="true"
|
||||
data-bs-content="
|
||||
<div class='p-2'>
|
||||
>
|
||||
{{ commerce.getCompletionPercentage() }}
|
||||
|
||||
<div class='p-2'>
|
||||
<h6>Infos manquantes :</h6>
|
||||
<ul class='list-unstyled mb-0'>
|
||||
{% if not commerce.name %}
|
||||
|
@ -45,9 +55,6 @@
|
|||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
"
|
||||
>
|
||||
{{ commerce.getCompletionPercentage() }}
|
||||
</td>
|
||||
<td class="{{ commerce.mainTag ? 'filled' : '' }}">
|
||||
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
Email
|
||||
</th>
|
||||
<th>
|
||||
<i class="bi bi-envelope-paper"></i>
|
||||
Contenu email
|
||||
</th>
|
||||
<th>
|
||||
<i class="bi bi-circle-fill"></i>
|
||||
Completion %
|
||||
</th>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue