J'ai créé cet article parce que je n'avais pas de code simple pour télécharger des données csv, les représenter graphiquement, les afficher sur une carte et les afficher. L'image terminée est présentée ci-dessous.
Fig.1 Page Web terminée
La moitié supérieure de la figure 1 a été créée à l'aide du graphique linéaire de amchart.js. La plage d'affichage peut être librement sélectionnée pour l'axe x et l'axe y. L'axe des x est l'axe du temps. La moitié inférieure de la figure 2 utilise GoogleMapAPI pour saisir et afficher les données de latitude / longitude.
・ API Google Map ・ Django ・ Amchart.js
L'environnement et la version sont les suivants.
macOS Catalina version 10.15.4
Python 3.7.0
─root─app─templates─app─base.html
│ | └import.html
│ ├migrations-・ ・ ・
│ ├forms.py
│ ├views.py
│ ・ ・ ・ ・
|
|
├project─settings.py
| ├urls.py
|・ ・ ・
|
├static─js─mychart.js
| | └googlemap.js
| └media-temp.csv (<-Un fichier qui complète temporairement le fichier csv importé)
└manage.py
Il suit la structure de répertoire de base de Django.
app/views.py
import csv
from django.http import HttpResponse
from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.views import generic
from .forms import CSVUploadForm
from .models import Post
class PostIndex(generic.ListView):
model = Post
class PostImport(generic.FormView):
template_name = 'app/import.html'
success_url = reverse_lazy('app:index')
form_class = CSVUploadForm
def form_valid(self, form):
form.save()
return redirect('app:index')
def post_export(request):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="posts.csv"'
#L'objet HttpResponse est un objet de type fichier, donc csv.Vous pouvez le transmettre à l'écrivain tel quel.
writer = csv.writer(response)
for post in Post.objects.all():
writer.writerow([post.pk, post.title])
return response
forms.py est le code source le plus conçu.
app/forms.py
import csv
import io
from django import forms
from django.core.validators import FileExtensionValidator
from .models import Post
import codecs
class CSVUploadForm(forms.Form):
file = forms.FileField(
label='Fichier CSV',
help_text='* Veuillez télécharger le fichier avec l'extension csv.',
validators=[FileExtensionValidator(allowed_extensions=['csv'])]
)
def clean_file(self):
file = self.cleaned_data['file']
print("file:",file)
# csv.Convertir en fichier en mode texte avec TextIOWrapper pour passer au lecteur
csv_file = io.TextIOWrapper(file, encoding='utf-8')
print("csv_file",csv_file)
reader = csv.reader(csv_file)
print("reader",reader)
self.csv_file = reader
for row in reader:
#print("reader row", row)
#print("line_num", reader.line_num)
if reader.line_num == 1:
with open("static/media/temp.csv", mode="w", encoding="utf-8") as f:
print("row in x before", row)
row = ",".join(row)
row = row + "\n"
print("row in x after", row)
f.write(row)
print("option=x")
else:
with open("static/media/temp.csv", mode="a", encoding="utf-8") as f:
#print("row in a before", row)
#print(type(row))
row = ",".join(row)
row = row + "\n"
#print("row in a after", row)
#print(type(row))
f.write(row)
#print("option=a")
#Liste pour stocker l'instance de modèle non enregistrée créée à partir de chaque ligne
self._instances = []
try:
for row in reader:
post = Post(pk=row[0], title=row[1])
self._instances.append(post)
except UnicodeDecodeError:
raise forms.ValidationError('Vérifiez le codage du fichier et le fichier CSV correct.')
return file
def save(self):
Post.objects.bulk_create(self._instances, ignore_conflicts=True)
Post.objects.bulk_update(self._instances, fields=['title'])
print("save content in save func", Post)
app/urls.py
from django.urls import path
from . import views
app_name = 'app'
urlpatterns = [
path('', views.PostIndex.as_view(), name='index'),
path('import/', views.PostImport.as_view(), name='import'),
path('export/', views.post_export, name='export'),
]
Parmi les sources suivantes, [API-KEY] insère la clé API. Veuillez émettre Google_API-Key par vous-même.
app/templates/app/base.html
<!doctype html>
{% load static %}
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<style>
#chartdiv {
width: 100%;
height: 500px;
}
#map {
width: 100%;
height: 400px;
}
</style>
<!-- Resources -->
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
<!-- Chart code -->
<script src="{% static 'js/mychart.js' %}"></script>
<title>Visualisation du capteur Rover</title>
</head>
<body>
<ul class="nav justify-content-center">
<li class="nav-item">
<a class="nav-link" href="{% url 'app:index' %}">Index</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'app:import' %}">Lecture CSV</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'app:export' %}">Sortie CSV</a>
</li>
</ul>
<div class="container">
{% block content %}{% endblock %}
<div id="map"></div>
<script src="{% static 'js/googlemap.js' %}"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=[API-KEY]"
async defer></script>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</div>
</body>
</html>
app/templates/app/import.html
{% extends 'app/base.html' %}
{% block content %}
<form action="" method="POST" enctype="multipart/form-data">
{{ form.as_ul }}
{% csrf_token %}
<button type="submit">Envoyer</button>
</form>
{% endblock %}
app/templates/app/post_list.html
{% extends 'app/base.html' %}
{% block content %}
<div id="chartdiv"></div>
{% endblock %}
project/static/js/mychart.js
// 2)Conversion de CSV en tableau 2D
function csv2Array(str) {
var csvData = [];
var lines = str.split("\n");
for (var i = 0; i < lines.length; ++i) {
var cells = lines[i].split(",");
csvData.push(cells);
}
return csvData;
}
function drawBarChart(data) {
// 3)chart.Préparer un tableau pour l'ensemble de données js
var tmpLabels = [], tmpData1 = [], tmpData2 = [];
for (var row in data) {
tmpLabels.push(data[row][0])
tmpData1.push(data[row][1])
tmpData2.push(data[row][2])
};
// 4)chart.Dessiner avec js
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: tmpLabels,
datasets: [
{ label: "Tokyo", data: tmpData1, backgroundColor: "red" },
{ label: "Osaka", data: tmpData2, backgroundColor: "blue" }
]
}
});
}
function makeLineChart(data) {
am4core.ready(function() {
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);
// Add data
console.log(data);
console.log(typeof data);
console.log(data[1][1]);
chart.data = generateChartData(data); //ajouter à
console.log(chart.data);
// Create axes
var xAxis = chart.xAxes.push(new am4charts.ValueAxis());
//xAxis.renderer.minGridDistance = 150;
xAxis.title.text = "Time (sec)";
var yAxis = chart.yAxes.push(new am4charts.ValueAxis());
yAxis.title.text = "ax";
// Create series
var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.valueX = "timestamp";
series.dataFields.valueY ="ax";
series.name = "ax";
series.strokeWidth = 2;
series.minBulletDistance = 10;
series.tooltipText = "{valueY}";
series.tooltip.pointerOrientation = "vertical";
series.tooltip.background.cornerRadius = 20;
series.tooltip.background.fillOpacity = 0.5;
series.tooltip.label.padding(12,12,12,12)
var series2 = chart.series.push(new am4charts.LineSeries());
series2.dataFields.valueX = "timestamp";
series2.dataFields.valueY = "ay";
series2.name = "ay";
var series3 = chart.series.push(new am4charts.LineSeries());
series3.dataFields.valueX = "timestamp";
series3.dataFields.valueY = "az";
series3.name = "az";
// Create y axis range
var range = yAxis.axisRanges.create();
range.label.disabled = false;
range.label.rotation = 270;
// Create x axis range
var range_x = xAxis.axisRanges.create();
range_x.label.disabled = false;
range_x.label.rotation = 0;
// Add scrollbar
chart.scrollbarX = new am4charts.XYChartScrollbar();
chart.scrollbarX.series.push(series);
chart.scrollbarX.series.push(series2);
chart.scrollbarX.series.push(series3);
chart.scrollbarY = new am4charts.XYChartScrollbar();
chart.scrollbarY.series.push(series);
chart.scrollbarY.series.push(series2);
chart.scrollbarY.series.push(series3);
// Add cursor
chart.cursor = new am4charts.XYCursor();
chart.cursor.xAxis = xAxis;
chart.cursor.yAxis = yAxis;
chart.cursor.snapToSeries = series;
chart.cursor.snapToSeries = series2;
chart.cursor.snapToSeries = series3;
// Add legend
chart.legend = new am4charts.Legend();
function generateChartData(data) {
var chartData = [];
var index_length = Number(data.length);
const initial_time = data[0][0]
console.log(index_length);
for (var i = 0; i < (index_length-1); i++) {
var data_line = data[i];
chartData.push({
timestamp: (data_line[0]-initial_time)/1000,
ax: data_line[1],
ay: data_line[2],
az: data_line[3],
wx: data_line[4],
wy: data_line[5],
wz: data_line[6],
mx: data_line[7],
my: data_line[8],
mz: data_line[9],
lat: data_line[10],
lng: data_line[11],
yaw: data_line[12]
});
}
return chartData;
}
});
}
function main(file_name) {
// 1)Charger le fichier CSV avec ajax
var req = new XMLHttpRequest();
var filePath = file_name//'acc_gyro.csv';
req.open("GET", filePath, true);
req.onload = function() {
// 2)Appelez la conversion de données CSV
data = csv2Array(req.responseText);
// 3) amChart.js préparation des données, 4) amChart.appel de dessin js
makeLineChart(data);
}
req.send(null);
}
main("/static/media/temp.csv");
static/js/googlemap.js
// 2)Conversion de CSV en tableau 2D
function csv2Array(str) {
var csvData = [];
var lines = str.split("\n");
for (var i = 0; i < lines.length; ++i) {
var cells = lines[i].split(",");
csvData.push(cells);
}
return csvData;
}
//Propriétés et propriétés dans un tableau à deux dimensions
function mapData(data) {
var mapData = [];
const initial_time = data[0][0]
var index_length = Number(data.length);
for (var i = 0; i < (index_length-1); i++) {
var data_line = data[i];
mapData.push({
timestamp: (data_line[0]-initial_time)/1000,
ax: data_line[1],
ay: data_line[2],
az: data_line[3],
wx: data_line[4],
wy: data_line[5],
wz: data_line[6],
mx: data_line[7],
my: data_line[8],
mz: data_line[9],
lat: data_line[10],
lng: data_line[11],
yaw: data_line[12]
});
}
return mapData;
}
function initMap(data) {
var map;
mapdata = mapData(data);
var index_length = Number(data.length);
console.log(mapdata);
console.log(index_length);
initial_loc = mapdata[0];
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: Number(initial_loc.lat), lng: Number(initial_loc.lng)},
zoom: 15
});
for(var i = 1; i < (index_length-1); i++) {
location_line = mapdata[i];
//console.log(i);
//console.log(location_line);
//Paramètres initiaux du marqueur
var markerOpts = {
position: {lat: Number(location_line.lat), lng: Number(location_line.lng)},
map: map,
title: "mark"
};
//Créez un marqueur à l'aide des options de marqueur créées juste avant
var marker = new google.maps.Marker(markerOpts);
}
}
function main(file_name) {
// 1)Charger le fichier CSV avec ajax
var req = new XMLHttpRequest();
var filePath = file_name;//'static/js/acc_gyro.csv';
req.open("GET", filePath, true);
req.onload = function() {
// 2)Appelez la conversion de données CSV
data = csv2Array(req.responseText);
// 3)préparation des données de google map, 4)appel de dessin de google map
initMap(data);
}
req.send(null);
}
main("/static/media/temp.csv");
project/setting.py
(Omission)
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
・ Ce sera la première application Web créée avec Django. Je suis profondément ému. -Comme il n'y avait pas de description dans le tutoriel sur la façon de définir le répertoire statique, j'ai beaucoup appris. ・ Ensuite, je voudrais rapporter les résultats du déploiement d'AWS sur les instances EC2.
Comment implémenter amchart: https://www.suzu6.net/posts/56-amcharts-samples/ Implémentation de la fonction de téléchargement csv: https://qiita.com/t-iguchi/items/d2862e7ef7ec7f1b07e5
Recommended Posts