[PYTHON] Faisons une carte du nouveau site d'infection corona [FastAPI / PostGIS / deck.gl (React)] (Traitement des données)

New Corona ... La propagation de l'infection ne s'arrête pas ...

En tant que nouveau magasin SIG, je voulais mettre des données sur une carte et la visualiser, mais la plupart des données accessibles au public étaient au format PDF, il était donc difficile de les collecter.

Mais! !! !! !! !! !!

Sites qui fournissent d'excellentes données avec copie, citation et réimpression gratuites à des fins non commerciales ([https://gis.jag-japan.com/covid19jp/](https: // gis. J'ai trouvé jag-japan.com/covid19jp/)), donc j'aimerais utiliser ces données pour l'exprimer sur une carte! !! xf

Cette fois, après étude, il a une configuration légèrement redondante (comme le lancement d'un serveur d'application et d'un serveur DB avec docker-compose et la livraison de GeoJSON avec API).

Obtenez des données

Jetons un coup d'œil aux données immédiatement!

Allez sur le site ci-dessus et cliquez sur le lien csv en haut à gauche.

スクリーンショット 2020-03-30 7.40.44.png

Ensuite, vous pouvez télécharger le csv suivant.

COVID-19.csv


À travers,Ministère de la santé, du travail et de la protection sociale NON,Transporteur pathogène asymptomatique,National,Vol charter,Âge,sexe,Date fixe,Date d'apparition,Préfecture de consultation,Préfecture de résidence,Dans la juridiction résidentielle,Ville de résidence,Clé,Présentation,Numéro de dossier préfectoral,statut,Remarques,La source,La source2,La source3,Nombre de personnes,Cumulatif,Le ratio de la veille,Total mort,Nombre de déchargesCumulatif,Nombre de décharges,Nombre de cas,PCR検査実施Nombre de personnes,PCR検査Le ratio de la veille,Métier_Pour confirmation d'exactitude,Lieu de travail_Pour confirmation d'exactitude,Hospital Pref,Residential Pref,Release,Gender,X,Y,Date fixeYYYYMMDD,Préfecture de consultationコード,Préfecture de résidenceコード,Mettre à jour la date et l'heure,Field2,Field4,Field5,Field6,Field7,Field8,Field9,Field10
1 ,1 ,,A-1,,30 ,Masculin,1/15/2020,1/3/2020,Préfecture de Kanagawa,Préfecture de Kanagawa,,,Préfecture de Kanagawa,Préfecture de Kanagawa,1,Décharge,,https://www.mhlw.go.jp/stf/newpage_08906.html,https://www.pref.kanagawa.jp/docs/ga4/bukanshi/occurrence.html,,1 ,1 ,1 ,0 ,1 ,1 ,0 ,,,,,Kanagawa,Kanagawa,Kanagawa Prefecture,Male,139.642347,35.447504,2020/1/15,14,14,3/29/2020 18:50,,,,,,,,
2 ,2 ,,A-2,,40 ,Masculin,1/24/2020,1/14/2020,Tokyo,les gens de la République de Chine,,,les gens de la République de Chine,Tokyo,1,Décharge,,https://www.mhlw.go.jp/stf/newpage_09079.html,https://www.metro.tokyo.lg.jp/tosei/hodohappyo/press/2020/01/24/20.html,,1 ,2 ,1 ,0 ,,,2 ,,,,,Tokyo,China(Mainland),Tokyo Metropolitan Government,Male,116.409685,39.903832,2020/1/24,13,NA,,,,,,,,,

csv est le meilleur.

Le nombre de personnes infectées = le nombre d'enregistrements, et ils fournissent des données assez détaillées, mais je ne peux pas les gérer, alors concentrons-nous sur les données que vous souhaitez utiliser!

Créez un environnement virtuel avant de traiter les données

Créons un répertoire de travail et un répertoire de travail informatique pour le moment! (Le nom du répertoire (covid_sample cette fois) est arbitraire)

Vous pouvez créer le répertoire covid_sample et le répertoire de script sous celui-ci à la fois avec la commande suivante.

$mkdir -p covid_sample/script

Cette fois, je veux juste afficher les données sur la carte, donc [" À travers "," Âge "," Sexe "," Date confirmée "," Date de début "," Préfecture de consultation "," Préfecture de résidence "," Supprimons seulement autour de X "," Y "]!

Je ne veux pas polluer l'environnement de la machine principale, donc je crée un environnement virtuel en utilisant pipenv etc. et le modifie rapidement à l'aide de pandas.

Je pense que l'article ici sera très utile pour savoir comment utiliser pipenv!

Si pipenv est installé, déplacez le répertoire de script avec $ cd covid_sample / script et créez un Pipfile comme celui ci-dessous.

Pipfile


[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]
pandas = "==0.24.2"
requests = "*"

[requires]
python_version = "3.8"

Le fichier ci-dessus est un fichier qui spécifie comment créer un environnement virtuel. Dans l'exemple ci-dessus, la version Python est 3.8 et les pandas et les requêtes sont installés.

Créez un environnement virtuel avec la commande $ pipenv install et entrez dans l'environnement virtuel avec le $ pipenv shell.

Ensuite, je pense qu'un caractère comme (script) apparaîtra à l'extrémité gauche du shell, mais si cela apparaît, c'est dans l'environnement virtuel.

Si vous vérifiez les bibliothèques installées avec $ pip list dans cet état, vous pouvez voir que les pandas et les requêtes et leurs dépendances sont installés.

(script) hogehoge:script$pip list
Package         Version   
--------------- ----------
certifi         2019.11.28
chardet         3.0.4     
idna            2.9       
numpy           1.18.2    
pandas          0.24.2    
pip             20.0.2    
python-dateutil 2.8.1     
pytz            2019.3    
requests        2.23.0    
setuptools      46.1.3    
six             1.14.0    
urllib3         1.25.8    
wheel           0.34.2    

Ceci termine la création de l'environnement virtuel!

Traitement de l'information

Créons un script Python comme celui ci-dessous! Je l'ai nommé format.py!

Ce script téléchargera et traitera csv à la fois!

format.py


import pandas as pd
from datetime import datetime as dt
import requests

#URL csv
csv_url = "https://dl.dropboxusercontent.com/s/6mztoeb6xf78g5w/COVID-19.csv"

try:
    #Spécifiez l'url et la requête http avec la méthode GET
    r = requests.get(csv_url)
    # COVID-19.Enregistrer sous csv
    with open("COVID-19.csv", 'wb') as f:
        f.write(r.content)
except requests.exceptions.RequestException as err:
    print(err)

#Spécifiez le nom de la colonne à utiliser
column_names = [
    "À travers", "Âge", "sexe", "Date fixe", "Date d'apparition",
    "Préfecture de consultation", "Préfecture de résidence", "X", "Y",
]

#Changer le nom de la colonne
changed_column_name = {
    "À travers": "id",
    "Âge": "age",
    "sexe": "gender",
    "Date fixe": "fixed_data",
    "Date d'apparition": "onset_data",
    "Préfecture de consultation": "consultation",
    "Préfecture de résidence": "prefectures",
    "X": "lng",
    "Y": "lat",
}

#Spécifiez le nom de la colonne utilisé dans usecols au format tableau
df = pd.read_csv('COVID-19.csv', usecols=column_names)
#Spécifiez le nom de la colonne à modifier au format dictionnaire
rename_df = df.rename(columns=changed_column_name)

#Créer une liste en supprimant la chaîne spécifiée de la colonne d'âge
rename_df["age"] = [string.strip(' ') for string in list(rename_df["age"])]
#Convertir l'heure en type de date
rename_df["fixed_data"] = [dt.strptime(data_string, "%m/%d/%Y").date() for data_string in list(rename_df["fixed_data"])]
# onset_Remplacer NaN dans les données
rename_df.fillna({'onset_data': '1/1/0001'}, inplace=True)
rename_df["onset_data"] = [dt.strptime(data_string, "%m/%d/%Y").date() for data_string in list(rename_df["onset_data"])]

#Remplacez la valeur spécifiée dans la colonne spécifiée
# inplace=Changer le df d'origine avec True
rename_df.replace(
    {
        "age": {"inconnue": "999", "0-10": "10"}
    }
    , inplace=True)

#Exporter vers csv
rename_df.to_csv("../docker/postgis/custom_COVID-19.csv", index=False)

Lorsque cette commande est exécutée, csv est téléchargé et stocké dans le même répertoire que le script, puis les données nécessaires sont extraites et traitées et déchargées dans le répertoire spécifié.

Les détails sont décrits dans les commentaires du code, donc si vous regardez là, vous pouvez le comprendre!

Pour l'emplacement de décharge csv (covid_sample / fastAPI / docker / postgis / custom_COVID-19.csv), spécifiez le nouveau répertoire créé en construisant l'environnement docker expliqué dans l'élément, et spécifiez le même répertoire dans les paramètres du docker. Soyez prudent lors de l'exécution du script!

Construction d'environnement avec docker-compose

Une fois que vous avez fini de traiter csv, appuyez sur control + D pour quitter l'environnement virtuel et utilisez cd ../ pour retourner au répertoire racine (covid_sample).

Convertissons les données en GeoJSON, un format d'informations géospatiales facile à gérer sur le Web!

N'importe quelle méthode peut être utilisée, mais à l'avenir, je souhaite utiliser les données en tant qu'API, alors enregistrons-les dans la base de données et démarrons le serveur API en utilisant le backend!

Dans ce cas, nous utiliserons Docker, ce qui est très pratique pour le démarrage du serveur personnel!

Nous allons procéder en supposant qu'il est installé, donc si vous utilisez mac, veuillez vous référer à Docker Compose --Installation etc. avec Docker Veuillez installer docker-compose. (Si vous recherchez un autre système d'exploitation sur Google, il sortira bientôt!)

Une fois créé, créez un répertoire pour l'API comme suit!

$mkdir -p docker/fastapi
$mkdir -p docker/postgis/init
$mkdir docker/postgis/sql

La structure actuelle des répertoires devrait ressembler à ceci!

covid_sample
├── docker
│   ├── fastapi
│   └── postgis
│       ├── init
│       └── sql
└── script
    ├── COVID-19.csv
    ├── Pipfile
    ├── Pipfile.lock
    └── format.py

De plus, il y a pas mal de fichiers requis pour démarrer docker, ils sont donc décrits de manière approximative ci-dessous, alors veuillez les copier et les utiliser! Lol

--Fichier de paramètres principal pour docker-compose: configurez le conteneur à lancer, les paramètres de connexion entre les conteneurs et le répertoire de montage avec la machine hôte.

docker/docker-compose.yml


version: '3.7'
services:
    fastapi:
#Nom du conteneur
        container_name: fastapi
#Répertoire contenant le fichier docker à construire
        build: fastapi
        volumes:
#Répertoire à monter
            - ./fastapi:/usr/src/app/
        ports:
#Port côté hôte: port côté conteneur
            - 8000:8000
        env_file:
#Fichier à définir dans la variable d'environnement
            - fastapi/.env
        depends_on:
#Service de connexion
            - postgis

    postgis:
        container_name: postgis
        build: postgis
        volumes:
            - covid_postgis_data:/var/lib/postgresql/data
#            down -Spécifiez le fichier à exécuter au premier démarrage, y compris lorsqu'il n'y a pas de volume avec v etc.
            - ./postgis/init:/docker-entrypoint-initdb.d
#Répertoire à monter
            - ./postgis:/home
        env_file: postgis/.env_db
        ports:
#Le port du côté hôte bat avec le psql local, il semble donc meilleur que 5432
            - 5433:5432

volumes:
    covid_postgis_data:

--Fichier de paramétrage des variables d'environnement pour le conteneur fastapi

docker/fastapi/.env


DATABASE_HOST=localhost
DATABASE_PORT=5433

--Dockerfile pour démarrer le conteneur fastapi (docker / fastapi / Dockerfile)

docker/fastapi/Dockerfile


FROM python:3.8

RUN apt-get update -y --fix-missing \
    && apt-get install -y -q --no-install-recommends

# install
RUN pip install pipenv
ADD Pipfile Pipfile.lock /
RUN pipenv install --system

# add to application
ADD app.py /

CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

docker/fastapi/Pipfile


[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]
fastapi = "*"
uvicorn = "*"
psycopg2-binary = "*"

[requires]
python_version = "3.8.0"

--Fichier d'application pour fastapi

docker/fastapi/app.py


from fastapi import FastAPI

app = FastAPI()

# `uvicorn app:app --reload`Commencer avec
@app.get("/")
async def hello():
    return {"text": "hello"}

--postgis fichier de paramètres de variable d'environnement de conteneur

Spécifiez un mot de passe pour docker / postgis / .env_db.

docker/postgis/.env_db


#Dans le conteneur postgres, si vous écrivez dans env, la base de données sera créée automatiquement
POSTGRES_USER=covid_user
POSTGRES_PASSWORD=hogehoge
POSTGRES_DB=covid_db

--Postgis Dockerfile pour le démarrage du conteneur (docker / postgis / Dockerfile)

docker/postgis/Dockerfile


FROM mdillon/postgis:9.6

# locale settings.
RUN localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8
ENV LANG ja_JP.UT

--postgis Script Shell chargé lorsque le conteneur est démarré pour la première fois

docker/postgis/init/init.sh


#!/bin/sh

psql -U covid_user -d covid_db -f /home/sql/init.sql

psql -U covid_user -d covid_db -c "COPY covid_data FROM '/home/custom_COVID-19.csv' WITH CSV HEADER DELIMITER ',';"

psql -U covid_user -d covid_db -f /home/sql/create_geom.sql

--Fichier SQL exécuté par le script shell ci-dessus

docker/postgis/sql/init.sql


CREATE EXTENSION postgis;

create table covid_data
(
    id           smallint not null,
    age          int,
    gender       text,
    fixed_data   date,
    onset_data   date,
    consultation text,
    prefectures  text,
    lng          float,
    lat          float
);

--Fichier SQL exécuté par le script shell ci-dessus

docker/postgis/sql/create_geom.sql


alter table covid_data
	add geom geometry(point, 4326);

UPDATE covid_data SET geom = ST_GeogFromText('SRID=4326;POINT(' || lng || ' ' || lat || ')')::GEOMETRY;

Une fois que vous avez traité le csv avec les fichiers et scripts ci-dessus, construisez-le et démarrez-le avec $ docker-compose up -d --build!

Cette fois, nous lançons un conteneur pour FastAPI, un framework de microweb pour Python, et PostGIS, une extension géospatiale pour PostgreSQL.

Lorsque le conteneur est démarré, les données csv sont enregistrées dans la base de données et init.sh génère automatiquement une colonne geom de type géométrie à partir de ces données et entre les données.

À ce stade, vous devriez pouvoir voir les données en vous connectant à la base de données dans le conteneur postgis par certains moyens (tels que pgadmin ou $ psql -U covid_user -d covid_db -h localhost -p 5433).

De plus, si vous accédez à localhost: 8000 depuis votre navigateur et que l'affichage de` {" text ":" hello "} ʻest renvoyé, la construction de l'environnement docker-compose est terminée!

Créer une API

Une fois que vous avez un environnement, créons une API!

Plus précisément, modifiez docker / fastapi / app.py comme suit!

docker/fastapi/app.py


from fastapi import FastAPI
import psycopg2
from starlette.middleware.cors import CORSMiddleware

app = FastAPI()

#Ajouté pour les paramètres CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"]
)

# `uvicorn app:app --reload`Commencer avec
@app.get("/")
async def hello():
    #Connectez-vous à PostgreSQL
    connection = psycopg2.connect(
        # host="localhost",
        host="postgis",
        user="covid_user",
        password="hogehoge",
        dbname="covid_db",
        port=5432
    )

    #Définir le codage du programme client (convertir automatiquement à partir du code de caractère DB)
    connection.set_client_encoding('utf-8')

    #Récupérez le curseur
    cursor = connection.cursor()

    #Générer geojson
    sql = """
    SELECT jsonb_build_object(
        'type',     'FeatureCollection',
        'features', jsonb_agg(features.feature)
    )
    FROM (
      SELECT jsonb_build_object(
        'type',       'Feature',
        'id',         id,
        'geometry',   ST_AsGeoJSON(geom)::jsonb,
        'properties', to_jsonb(inputs) - 'gid' - 'geom'
      ) AS feature
      FROM (SELECT * FROM covid_data) inputs) features;
    """

    #Exécution SQL
    cursor.execute(sql)

    #Résultat d'acquisition de sortie
    results = cursor.fetchall()[0][0]

    #Fermer le curseur
    cursor.close()

    #Déconnecter
    connection.close()

    return results

Dans cette application, tout d'abord, il est nécessaire d'accéder à l'API de React avec Ajax pour acquérir et afficher des données, nous définissons donc CORS (cette fois, à titre d'essai, tous les hôtes et méthodes sont autorisés, mais Arrêtez-vous autant que possible car c'est dangereux).

Si vous ne le définissez pas, vous ne pourrez pas accéder à l'API du côté JavaScript (application d'affichage des cartes), alors assurez-vous de le paramétrer! (Pour plus d'informations, essayez google avec CORS!)

Dans la partie de @ app.get (" / "), cela signifie que le traitement lorsque / est accédé par la méthode GET est écrit en dessous. Écrivons le processus ici cette fois.

Après cela, accédez à la base de données en utilisant un module appelé psycopg2 pour vous connecter à PostgreSQL depuis Python.

Dans la partie SQL, les données sont converties de force en GeoJSON à l'aide de la fonction de type JSONB de PostgreSQL.

Après la réécriture, arrêtez les conteneurs avec $ docker-compose down et redémarrez avec $ docker-compose up -d --build!

Reconnectons-nous à localhost: 8000 lorsque le démarrage est terminé.

Si tout se passe bien, vous devriez obtenir un GeoJSON comme celui-ci!

{
    "type": "FeatureCollection",
    "features": [
        {
            "id": 1,
            "type": "Feature",
            "geometry": {
                "type": "Point",
                "coordinates": [
                    139.642347,
                    35.447504
                ]
            },
            "properties": {
                "id": 1,
                "age": 30,
                "lat": 35.447504,
                "lng": 139.642347,
                "gender": "Masculin",
                "fixed_data": "2020-01-15",
                "onset_data": "2020-01-03",
                "prefectures": "Préfecture de Kanagawa",
                "consultation": "Préfecture de Kanagawa"
            }
        },
        {
            "id": 2,
            "type": "Feature",
            "geometry": {
                "type": "Point",
                "coordinates": [
                    116.409685,
                    39.903832
                ]
            },
            "properties": {
                "id": 2,
                "age": 40,
                "lat": 39.903832,
                "lng": 116.409685,
                "gender": "Masculin",
                "fixed_data": "2020-01-24",
                "onset_data": "2020-01-14",
                "prefectures": "les gens de la République de Chine",
                "consultation": "Tokyo"
            }
        },
        ...
}

Maintenant, les données sont prêtes! !!

La prochaine fois, affichons ces données sur la carte!

→ Cliquez ici pour plus d'informations: Créer un nouveau plan du site d'infection corona [FastAPI / PostGIS / deck.gl (React)](Affichage des données)

Recommended Posts

Faisons une carte du nouveau site d'infection corona [FastAPI / PostGIS / deck.gl (React)] (Traitement des données)
Faisons l'analyse des données de naufrage du Titanic comme ça
Jetons un coup d'œil à la carte des fonctionnalités de YOLO v3
Faisons un site multilingue en utilisant flask-babel
Comment créer un plan de site Pelican
L'histoire du traitement A du blackjack (python)
Essayez de tracer la concentration environnementale des composés organiques du fluor sur une carte à l'aide de données ouvertes
Créez un BOT qui affiche le nombre de personnes infectées dans le nouveau Corona