infos de fraicheur de données

This commit is contained in:
Tykayn 2025-06-24 00:29:15 +02:00 committed by tykayn
parent 4eb95d5b95
commit b41bbc9696
6 changed files with 573 additions and 0 deletions

View file

@ -0,0 +1,260 @@
{% extends 'base.html.twig' %}
{% block title %}Histogramme de fraîcheur OSM{% endblock %}
{% block body %}
<div class="container mt-4">
<h1>Histogramme de fraîcheur des données OSM</h1>
<h2>Par année</h2>
<canvas id="fraicheurHistogrammeAnnee" width="800" height="400" style="max-width:100%; margin: 20px 0;"></canvas>
<h2>Par trimestre</h2>
<canvas id="fraicheurHistogrammeTrimestre" width="800" height="400" style="max-width:100%; margin: 20px 0;"></canvas>
<h2>Par mois</h2>
<canvas id="fraicheurHistogramme" width="800" height="400" style="max-width:100%; margin: 20px 0;"></canvas>
<h2>Distribution des villes selon le nombre d'habitants par lieu (par pas de 10)</h2>
<canvas id="distributionHabitantsParLieu" width="800" height="400" style="max-width:100%; margin: 20px 0;"></canvas>
<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>
</div>
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
fetch('/admin/fraicheur/download')
.then(r => r.json())
.then(data => {
if(data.error){
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)' }
},
scales: {
y: { beginAtZero: true, title: { display: true, text: 'Nombre de lieux' } },
x: { title: { display: true, text: 'Mois' } }
}
}
});
// Agrégation par trimestre
const trimestreAgg = {};
for(const key in data.histogram){
// key = YYYY-MM
const [year, month] = key.split('-');
const m = parseInt(month, 10);
let trimestre = 1;
if(m >= 4 && m <= 6) trimestre = 2;
else if(m >= 7 && m <= 9) trimestre = 3;
else if(m >= 10 && m <= 12) trimestre = 4;
const trimestreKey = `${year}-T${trimestre}`;
if(!trimestreAgg[trimestreKey]) trimestreAgg[trimestreKey] = 0;
trimestreAgg[trimestreKey] += data.histogram[key];
}
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)' }
},
scales: {
y: { beginAtZero: true, title: { display: true, text: 'Nombre de lieux' } },
x: { title: { display: true, text: 'Trimestre' } }
}
}
});
// Agrégation par année
const anneeAgg = {};
for(const key in data.histogram){
// key = YYYY-MM
const [year] = key.split('-');
if(!anneeAgg[year]) anneeAgg[year] = 0;
anneeAgg[year] += data.histogram[key];
}
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)' }
},
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>');
return;
}
// Histogramme habitants par lieu (pas de 10)
fetch('/admin/distribution_villes_lieux_par_habitant_villes')
.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));
}
return [];
}
}
}
},
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));
}
return [];
}
}
}
},
scales: {
y: { beginAtZero: true, title: { display: true, text: 'Nombre de villes' } },
x: { title: { display: true, text: 'Lieux par habitant (arrondi à 0,01)' } }
}
}
});
});
});
});
});
</script>
{% endblock %}

View file

@ -513,6 +513,7 @@
x: { title: { display: true, text: 'Trimestre' } }
}
}
});
} else if (modifCanvas) {
modifCanvas.parentNode.innerHTML = '<div class="alert alert-info">Aucune donnée de modification disponible pour cette ville.</div>';

View file

@ -100,6 +100,13 @@
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<p class="mb-2">
<a href="https://osm-commerces.cipherbliss.com/api/v1/stats_geojson" target="_blank">Documentation de l'API (GeoJSON)</a>
</p>
</div>
</div>
</div>
</footer>

View file

@ -35,6 +35,12 @@
<i class="bi bi-clock-fill"></i>
{{ 'display.latest_changes'|trans }}</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ path('admin_fraicheur_histogramme') }}">
<i class="bi bi-clock-history"></i>
Fraîcheur de la donnée
</a>
</li>
</ul>
</div>
</div>