LoginSignup
58
53

More than 3 years have passed since last update.

新型コロナ感染箇所マップを作ってみる【FastAPI/PostGIS/deck.gl(React)】(データ表示編)

Last updated at Posted at 2020-04-01

こちらの記事は新型コロナ感染箇所マップを作ってみる【FastAPI/PostGIS/deck.gl(React)】(データ加工編)の続きです。

上の記事をご覧になってからお読みください!

Reactの環境構築

ここまででcsvの元データをAPIからGeoJSON形式で吐き出せるようになっていると思いますので、そのデータを利用して地図上にコロナウイルス感染者の位置を表示できるようにしていきましょう!

まずはReactのプロジェクトを簡単に作成できるcreate-react-appを実行するためのNode.jsがインストールされているか確認しましょう

$node -v
v12.13.1

$npm -v
6.12.1

上記2つのコマンドを入力してバージョンの数字が表示されればインストールされています。

コマンドがないよー!なんて怒られた場合にはインストールされていませんのでNodebrewでNodeをインストールするなんかを参考にしてnodebrewのインストール→nodebrewからNode.jsをインストール→npmのインストールを行っていきましょう!

npmのインストールまで終わったらcovid_sampleに移動し、以下のコマンドでReactのプロジェクトを作成していきます。

$npm install -g create-react-app
$npx create-react-app .

これでcovid_sample自体がReactのプロジェクトになります。(コマンド最後の.はカレントディレクトリにプロジェクトを作成するという意味で、ここに何か任意の名前を入れると、covid_sample以下にその名前でディレクトリが作成されます)

$npm start

のコマンド入力後、localhost:3000へブラウザからアクセスし、以下のような画面が表示されればプロジェクトの作成成功です!

スクリーンショット 2020-04-01 8.06.28.png

deck.glの環境構築

deck.glは自動車配車サービスのUberが作成した大規模なデータセットの視覚的・探索的データ分析のためのWebGLを利用したフレームワークで、React上で動作させることを想定されています。(最近はpureJSでもちゃんと動くみたいですが)

めっちゃかっこいいです。

データさえあれば、以下のサンプルのように地図上に美しくデータを表現することができます。

スクリーンショット 2020-04-01 8.14.02.png

スクリーンショット 2020-04-01 8.16.58.png

今回はこのdeck.glを利用して地図上にデータを表示させていきましょう!

(ちなみに!!!!!今回扱うデータはただのポイントデータ(箇所ごとに緯度経度の位置情報があるだけのデータ)なので上のサンプルのようにかっこよくはなりません!!!!!!!すいません!!!!)

deck.glを利用するために以下の2つのコマンドを入力しましょう。

$npm install deck.gl
$npm install react-map-gl

下のreact-map-glはこちらもUberが作ったもので、Mapbox GL JSというWebGIS界隈では非常に有名なライブラリのReact用ラッパーになります。

今回は背景地図の表示に利用していきます。

これでいよいよ開発環境が整ったので、アプリケーションを作成していきましょう!

アプリケーションの作成

mapboxの登録とトークンの発行

mapboxとは、Google マップのようなサービスですが、JavaScriptやネイティブ用のSDKが公開されており、自由に、簡単にカスタマイズできる地図サービスのことです。

今回は背景地図としてmapboxを利用していきますので、トップページから会員登録・マイページに表示されるトークンをコピーしておいてください。

スクリーンショット 2020-04-02 7.37.09.png

背景地図の表示

srcというディレクトリが出来ているはずなのでそちらに移動しましょう。

Reactのプロジェクトでは基本的にこのsrc以下のファイル群をいじっていきます。

srcディレクトリの構成は以下のような感じになっていると思いますが、今回編集するファイルはApp.jsのみになります。

tree
.
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
├── serviceWorker.js
└── setupTests.js

ということでゴリゴリ修正していきましょう!

src/App.js
// Reactのインポート
import React from 'react';
// deck.glを利用
import DeckGL from '@deck.gl/react';
// geojsonを使うのでGeoJsonLayerを利用
import {GeoJsonLayer} from '@deck.gl/layers';
// 背景地図の表示にMapbox GL JSのラッパーを利用
import {StaticMap, Popup} from 'react-map-gl';


// 先ほど取得したトークンを文字列で格納
const MAPBOX_ACCESS_TOKEN = <MAPBOX_ACCESS_TOKEN>;

// 初期表示位置などを指定
const initialViewState = {
  longitude: 139.7212733,
  latitude: 35.6606213,
  zoom: 8,
  pitch: 45,
  bearing: 0
};

// 最近は関数ベースのコンポーネントが主流だが、サンプルに合わせてクラスベース
class App extends React.Component {
  // コンストラクターでデータを格納するstateを定義
  constructor(props) {
    super(props);
    this.state = {
      geojsonPoint: null,
    };
  }

  // コンポーネントがマウントされてから動作するメソッド
  // APIにアクセスしてデータを取得しておく
  componentDidMount() {
    fetch("http://0.0.0.0:8000/")
      .then(res => res.json())
      .then(
        (result) => {
          this.setState({
            geojsonPoint: result
          });
          console.log("result", result);
        },
        (error) => {
          console.log(error)
        }
      )
  }

  // ポップアップを表示させるためのメソッド
  _renderTooltip() {
    // hoveredObjectはホバーしている地物の情報
    const {hoveredObject} = this.state || {};
    console.log("hoveredObject", hoveredObject);
    if (hoveredObject !== undefined) {
      return (
        // react-map-glのPopupコンポーネントを利用してポップアップを表示
        <Popup
          longitude={hoveredObject.geometry.coordinates[0]}
          latitude={hoveredObject.geometry.coordinates[1]}>
          <div>
            <p>id:{hoveredObject.properties.id}</p>
            <p>年齢:{hoveredObject.properties.age}</p>
            <p>確定日:{hoveredObject.properties.fixed_data}</p>
          </div>
        </Popup>
      )
    }
  }

  // レンダリング用のメソッド
  render() {
    // コンストラクターで定義したstateからGeoJSONを取得
    const geojsonPoint = this.state.geojsonPoint;
    console.log("geojsonPoint: ", geojsonPoint);
    const layers = [
      new GeoJsonLayer({
        // 任意のid
        id: 'point_layer',
        // GeoJSONを指定
        data: geojsonPoint,
        // pointの半径
        getRadius: d => 2000,
        // 地物のカラーをRGBaで指定
        // aは透過度で0~255から指定
        getFillColor: d => [245, 36, 36, 150],
        pickable: true,
        // 地物にホバーした時に発生するイベント
        // stateを更新する
        onHover: info => this.setState({
          hoveredObject: info.object,
        })
      }),
    ];

    return (
      <>
        {/*DeckGLコンポーネントに必要な情報を渡す*/}
        <DeckGL
          initialViewState={initialViewState}
          controller={true}
          layers={layers}
        >
          {/*利用したいmapboxのスタイルとトークンを渡す*/}
          <StaticMap
            mapStyle="mapbox://styles/mapbox/dark-v9"
            mapboxApiAccessToken={MAPBOX_ACCESS_TOKEN}>
            {/*ポップアップ用の関数も入れる*/}
            {this._renderTooltip()}
          </StaticMap>
        </DeckGL>
      </>
    );
  }
}

export default App;

Reactの基本的な解説などは別記事に書こうと思っていますが、Reactでは基本的にコンポーネントの戻り値はJSXというJavaScript内にHTMLを埋め込むような記法で書いていきます。

なので、Appクラスのrenderメソッドの戻り値はHTMLのタグのようなものがずらっと並んでいます。

しかし、実際にはトランスパイルされてJavaScriptに変換されるので

<DeckGL initialViewState={initialViewState}></DeckGL>

のようにタグの中にpropsと呼ばれる変数のようなものを渡して表示を動的に切り替えることが出来ます!

その他、どういう処理を行なっているのか…という部分はコード中にコメントを書いているので参考にしてみてください!

注意する点としては

だけ気をつけてもらえればあとはちゃんと表示されるはずです!

ブラウザで表示させてみる

ここまで出来たらあとは表示させるだけです!

$npm startでサーバーを起動させてlocalhost:3000に接続してみましょう!

mov.gif

こんな感じで地図上にポイントが表示されて、ホバーすると情報が表示されるようになったと思います!!!

最後に

こんな感じで情報の収集・加工・配信・表示まで一連で行なってきましたが、データさえあれば簡単に可視化できるのが、最近のフレームワークの良いところですね!

また、データの加工段階でQGISなどのGISソフトなどを使えば都道府県ごとの人数をヒートマップで可視化などいろんなことができると思いますのでみなさんどんどんGISやっていきましょう!

58
53
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
58
53