まるっとワーク

データ分析・電子工作など気になることを残していきます

Rasberry PiとSORACOMサービスとで異常検知システムを作成 1/2 (システム概要とセットアップ編)

f:id:toku_dango:20210515193032p:plain
会社での作業員異常通報に関する改善が図れそうだったので、試作をしてみました。
ここでは、Rasberry PiとSORACOMサービスとを組み合わせた作業員の異常状態検知 監視システムについてご紹介します。


目次


背景

私が所属している会社では、作業員が危険な状態に陥った場合を検知/通報する「作業員異常通報装置」が運用されています。
危険な状態とは、体調不良や事故で他の人に助けを求める必要がある状態のことです。
単独作業の場合は、この装置を身に付けるルールとなっていますが、「きちんと使われない」「誤作動が多い」など運用に難ありな状況です。

作業員異常通報装置の運用

該当の装置についてちょっとだけ紹介します。※装置画像はあえて載せません
この装置は、ズボンのベルトに装着し、手動のスイッチと人の転倒を検知するセンサのいずれかが作動することで所定の場所に無線連絡する装置です。
単独作業時に装着するルールになっていますが、急に一人になる場合/装着し忘れる場合があります。また、装置の装着位置や作業内容によって、「転倒を検知するセンサが誤報する」という問題があり、誤報時には管理者が現場確認に行く手間が発生します。このような状況では、誤報を恐れて積極的に装着したくないという気持ちも出てくるのではと思っています。

上記問題点を踏まえて、「装置を装着する等の作業員の追加作業が必要ない」「異常を正しく検知」方法を検討しました。また、誤報に対する追加の対策として、管理者が遠隔で即座に状況確認できる方法も検討しました。

実施したいこと

作業者の異常を検知して、管理者に通知するシステムの作成が目標となるため、以下機能の実現を目指しました。

機能①:作業者(人)を認識して、異常を検知する
機能②:異常を検知したら、その旨をスマートスピーカーで管理者に通知する
機能③:異常を検知したら、状況の画像と位置情報をLINEで管理者に通知する
機能④:異常を検知したら、状況の画像と位置情報をSORACOM Lagoonダッシュボードで表示
おまけ機能:新型コロナ対策 密集検知機能(規定人数以上の人が会議室内にいる場合にその旨を管理者に通知する)

人の認識機能を有した市販の監視カメラは最近出てきましたが、まだまだ高価ですね。また、その中でも異常を検知する機能を有したものもそこまで多くないと思います。

今回SORACOMサービスを使用した理由としては、Wi-Fiが届かない様々な場所にも設置することを想定しているからです。
SORACOMではRaspberry Pi等に接続し、セルラー通信が可能となるUSBドングルがあるので、今回はそれを使用しています。

下記に本システムの概要図を示します。

f:id:toku_dango:20210508152246p:plain
システム概要図


使ったもの

  • Rasberry Pi 4 Model B+

www.amazon.co.jp

 公式のカメラモジュールなります。USBカメラでも代用がきくと思います。
www.amazon.co.jp

 SORACOMのSIMを入れて使うUSBモデムです。
 USBに接続状態を示すインジケーター付いているので、
 状態が分かりやすいのが利点です。

 音声で通知するために、今回はスマートスピーカーを使用します。
 Amazon Echoを喋らせる方法は色々とあるので、使い勝手が良いです。
 Amazon Echoを喋らせる方法は、以下にまとめています。
dango-study.hatenablog.jp

機能実装に向けて

機能①~④およびおまけ機能は、以下機能を組み合わせて実現します。
実装までの説明が少し長くなりそうなので、ここではセットアップまでを記載します。

  1. システム概要とセットアップ (本ページ)
  2. 機能の実装 (次ページ)


f:id:toku_dango:20210516162100p:plain

環境の構築

1. ハードウェアの構成について

Rasberry Piと周辺機器は以下の通り接続します。
f:id:toku_dango:20210516195405p:plain

本記事で記載の対象となるRasberryPiは、OS(Rasbian)が既にインストールされていることを前提としています。
※開発環境は以下の通り

$python3 -V
Python 3.7.3


2. Camera Moduleを使うための設定

RaspberryPiでカメラを動かす必要があるので、その設定を実施します。
Camera Moduleのセットアップ方法は、多く掲載されているので、ここでは割愛します。
詳細は以下リンクを参照してください。
thepihut.com

動作確認用に、画像をキャプチャするコードを紹介します。
コードを実行して、カメラ映像が写った5秒後の映像をキャプチャして表示するコードとなっています。

from picamera import PiCamera
import os
from time import sleep

camera = PiCamera()
camera.resolution = (300, 200)
camera.framerate = 15
camera.start_preview(alpha=100)
sleep(5)

camera.capture("image1.jpg")
camera.stop_preview()
os.system("xdg-open image1.jpg")


3. SORACOMを使うための設定

SORACOMを使い始めるまでのフロー、SORACOMのUSBモデムをRasberry Piで使用する方法については、公式サイトで説明されているので、そのリンクを紹介します。
SORACOM の利用を始める | ガイド | SORACOM Users
Getting Started: Raspberry Pi と USB モデム | 各種デバイスで SORACOM Air を使用する | SORACOM Users

4. 必要なモジュールのセットアップ

人物検知と異常検知には、ディープラーニングを使った画像認識ライブラリであるTensorFlowとOpenCVを使います。
自身でパッケージをインストールすることも可能ですが、より簡単にインストールができるスクリプトをからあげさんが公開して下さっている(以下URL)ので、それを活用させていただきます。
以下のように、コマンドでスクリプトを「setup-ai.sh」をダウンロードして実行しましょう。
karaage.hatenadiary.jp


$ git clone https://github.com/karaage0703/raspberry-pi-setup #スクリプトファイルのダウンロード
$ cd raspberry-pi-setup && ./setup-ai.sh #スクリプトファイルのパスへ移動/スクリプト実行


5. 物体検知ツールのセットアップ

上記までで開発環境は整いました。
ここからはコードを書いていくことになるのですが、まずは物体検知ができるようするために、同じくからあげさんが公開して下さっている「Object Detection Tools」を活用させていただきます。
人物含めた物体の検知を手軽に実施するには、Googleさんが提供している「Object Detection API」を使う例もあるのですが、
Rasberry Pi で使用するにはデータ容量や実装までのハードルが高かったため、活用させていただきます。
物体検出に必要な学習モデルも学習済みのモデルを用いています。

以下のように、コマンドでスクリプトを「get_ssdlite_mobilenet_v2_coco_model.sh 」をダウンロードして実行しましょう。

$ cd && git clone https://github.com/karaage0703/object_detection_tools #スクリプトファイルのダウンロード
$ cd ~/object_detection_tools/models #スクリプトファイルのパスへ移動
$ ./get_ssdlite_mobilenet_v2_coco_model.sh #スクリプト実行


試しに物体検知を実施する場合は、以下の通りコードを実行ください。
カメラの映像とともに物体検知(認識したものを四角で囲み左下に名前を記載)されていれば成功です。

$ cd ~/object_detection_tools #pythonファイルパス ディレクトリへ移動
$ python3 scripts/object_detection.py -l='models/coco-labels-paper.txt' -m='models/ssdlite_mobilenet_v2_coco_2018_05_09/frozen_inference_graph.pb' -d='raspi_cam' #コード実行


実行結果
f:id:toku_dango:20210516121933p:plain
物体の半分しか映っていなくてもある程度の精度で認識してくれるようです。
簡単にこんなことが試せるのは素晴らしいですね、からあげさんに感謝です。

まとめ

本記事では、システム概要とセットアップについて説明をしました。
物体検知だけでもかなり遊べると思いますが、次ページはこの機能を使って目的の機能を組み込んでいきます。

次の記事

  1. システム概要とセットアップ
  2. 機能の実装 (次ページ)

Python:LINEに通知をする

PythonでLINEにメッセージや画像を送りたい時に、毎回検索しているのでここにまとめておきます。
プログラムの完了通知をLINEに送りたい/センサーの値を監視していて、特定の値になったらその通知をLINEに送りたいなどで使えるかと思います。

1.LINE Notifyのトークン取得

パーソナルアクセストークンを利用することで、Webサービスの登録をせずに通知を設定することができるようです。
詳細は以下公式ページを参考にしてください。
LINE Notify

1.1 LINEのマイページにアクセスする

上記公式ページにアクセスして、自身のLINEアカウントにログイン後、マイページをクリックする。

1.2 LINE Notifyのトークン発行

以下順番でページをクリックして、 発行されたトークンをコピーする。
トークンを発行する>通知を送信するグループを選択>発行する」

2.LINE通知機能を実装

2.1 必要なモジュールをインストールする

 以下コードを実行。

$pip install requests 

2.2 LINEに通知

以下コードを実行する。
LINEにメッセージを送れます。

import requests

def main():
    message =  ""#ここにメッセージを入力
    send_line_notify('message')

def send_line_notify(message):
    """
    LINEに通知する
    """
    url = "https://notify-api.line.me/api/notify"
    token = "" #ここにトークンを入力
    headers = {"Authorization" : "Bearer "+ token}

    headers = {'Authorization': f'Bearer {token}'}
    payload = {"message" :  message}
    requests.post(url, headers = headers, params=payload, files=files)

if __name__ == "__main__":
    main()


+αサンプルコード

Rasberry Piにて、Rasberry Pi Cameraで写真を撮ってLINEに画像とメッセージを送るPythonコードです。

from picamera import PiCamera
from time import sleep
import subprocess, os, sys, re
from datetime import datetime
import time
import requests
import os
import subprocess
from base_camera import BaseCamera

def camera():
    now = datetime.now()
    dir_path = '/home/pi/smart/image/'
    file_name= now.strftime('%Y%m%d%_H') + '.jpg'
    fname    = dir_path + file_name
    try:
        os.mkdir(dir_path)
    except OSError:
        print('Date dir already exists')
    #os.system('raspistill -w 480 -h 360 -o ' + fname)
    camera = PiCamera()
    camera.resolution = (600, 400)
    camera.framerate = 15
    camera.start_preview(alpha=200)
    sleep(4)
    camera.capture(fname)
    camera.stop_preview()
    return fname

def line(fname):
    url = "https://notify-api.line.me/api/notify"
    token = "" #ここにトークンを入力
    headers = {"Authorization" : "Bearer "+ token}

    message =  "写真を撮りました!"
    payload = {"message" :  message}
    files = {"imageFile": open(fname, "rb")}
    r = requests.post(url, headers = headers, params=payload, files=files)
    print(r.text)
    

def main(image=""):
    if image == "":
        call_alexa()
        sleep(5)
        fname = camera()
    else:
        fname = image
    if fname:
      line(fname)

if __name__ == '__main__':
    main()


通知画像とメッセージ
f:id:toku_dango:20210515140217p:plain

まとめ

今回はPythonでLINEに通知する方法をまとめました。
LINEは、普段から使うタイミングが多いと思うので、通知するには良いですね。

RasberryPi:Pythonコードを定期実行する

特定のスクリプトを定期実行したいケースがあったため、指定の時間でコードを実行する方法を紹介します。
今回はcronという機能を使っていきます。

開発環境について

【ハードウェア】
RasberryPi

$python -V
Python 2.7.16


目次


cronが有効になっているかどうかを確認

pi@rasberrypi: ~ $chekconfig cron
>>cron on


上記の通り「cron on」と表示されていれば有効になっているので、問題ありません。
「cron off」と表示されている場合は以下実行して、有効化してください。

pi@rasberrypi: ~ $sudo systemctl enable cron


cronの設定

crontabを起動し、ルールに従って内容を修正して設定します。

pi@rasberrypi: ~ $crontab -e

crontabの書き方

以下ルールに従って、それぞれの項目をスペースで区切って設定します。
crontabを開くと、初期状態では全てコメントアウトされている状態になっているので、その一番下に記載するとよいです。
「分[0-59] 時[0-23] 日[1-31] 月[1-12] 曜日[0-7] 実行内容」

※細かい設定
範囲指定:ハイフンで設定「1-12, 2-4」
複数指定:カンマで区切って設定「1-12, 2-4」
実行間隔:このように記載「*/5」#5分間隔


※書き方例

0 9 1 1 * python /home/pi/Desktop/camera.py #1月1日9時0分にcamera.pyを実行する
0 9 * * 1-5 python /home/pi/Desktop/camera.py #月曜日から金曜日まで、9時0分にcamera.pyを実行する
*/15 * * * * python  /home/pi/Desktop/camera.py #5分ごとにcamera.pyを実行する
@reboot python  /home/pi/Desktop/camera.py #起動時に毎回、camera.pyを実行する

設定後は書き込み(保存)をしましょう。

まとめ

今回はPythonコードを定期実行する方法についてまとめました。
是非活用してください

Amazon Echo(Alexa)を喋らせる

f:id:toku_dango:20210425134042p:plain

Amazon Echoは、話をするようにAmazon Echoに話しかける or Amazon アプリから話すように指示をする等でないと喋ってくれないので、もう少し色々と喋らせる方法はないかと探していました。

本記事ではalexa_remote_controlを使用しますが、その他の方法としてはNode-redを使った方法もあるようです。
他の記事でも色々とまとめられているので、実用性を意識してまとめます。

Alexa-remote-controlのダウンロード

Alexa-remote-controlの「alexa-remote_control.sh」を適当なパスに保存する。

pi@rasberrypi: ~ $wget https://raw.githubuser.com/thorsten-gehrig/alexa-remote-control/master/alexa_remote_control.sh

github.com

Alexa-remote-controlを実行するために必要なライブラリをインストール

JSONツールが必要になるので、インストールする。

pi@rasberrypi: ~ $sudo apt-get install jq


Alexa-remote-controlの設定

alexa-remote-control.sh内に、以下項目の記載があるので、自身のAmazonアカウントに関する情報と必要な設定項目を入力する。

SET_EMAIL='' #Amazonアカウントにログインするためのemailアドレス
SET_PASSWORD='' #Amazonアカウントにログインするためのパスワード
SET_LANGUAGE='ja-JP'
SET_TTS_LOCALE='ja-JP'
SET_AMAZON=''amazon.co.jp 
SET_ALEXA='alexa.amazon.co.jp'


Alexa-remote-controlを使用する

パターン① コマンドラインで実行

pi@rasberrypi: ~ $ ./alexa_remote_control.sh -e "speak:おはよう"


パターン② pythonコード内で実行

import subprocess

cmd = ["./alexa_remote_control.sh", "-e", "speak:おはよう"]
res = subprocess.call(cmd)

Amazon Echoバイスが喋りだしたら成功ですね。"speak:"の後のワードを好きに変えていただければ、そのワードを喋ってくれます。
どちらの方法でも、実行の結果は同じになると思います。

その他コマンドについて

基本公式やalexa-remote-control.sh内にコマンドの詳細記載があるので不要と思いますが、参考まで。


特定の事柄を喋らせる

import subprocess

cmd = ["./alexa_remote_control.sh", "-e", "speak:おはよう"] #自由に設定したワードを喋らせる
cmd = ["./alexa_remote_control.sh", "-e", "weather"] #天気予報について
cmd = ["./alexa_remote_control.sh", "-e", "traffic"] #交通状況について
cmd = ["./alexa_remote_control.sh", "-e", "flashbriefing"] #最新ニュースについて
cmd = ["./alexa_remote_control.sh", "-e", "tellstory"] #適当な話について

res = subprocess.call(cmd)



指定の呼びかけに対する反応

import subprocess

cmd = ["./alexa_remote_control.sh", "-e", "textcommand:おはよう"] 
res = subprocess.call(cmd)


ラジオ再生

import subprocess

cmd = ["./alexa_remote_control.sh", "-r", "s8638"] #第3引数にラジオIDを入力する

res = subprocess.call(cmd)


まとめ

今回はAmazon Echoを喋らせる方法についてまとめました。
色々と組み合わせて、スマートホーム化を図りたいですね。

RasberryPi:セットアップ(日本語入力設定やLCDの設定について)

f:id:toku_dango:20210403224120p:plain

仕事でちょっとした試作が必要となり、手軽で持ち運びができるRasberryPiを使用しました。
ただ、いろいろと作業している中でGUIが起動しなくなる等、原因不明で初期化が必要になるケースも多かったので、その方法をまとめます。

RasberryPiでできること、初期設定方法はRasberry Pi公式URLで詳しく乗っているので割愛します。
本記事で記載の対象となるRasberryPiは、OS(Rasbian)が既にインストールされていることを前提とします。
projects.raspberrypi.org


※本記事で記載の方法を試した場合の保証は出来かねますので、ご自身の判断で実施ください。

開発環境について

【ハードウェア】
RasberryPi
microSDカード(OSインストール済み
USBキーボード
USBマウス
電源ケーブル
3.5インチLCD(液晶ディスプレイ)


目次

日本語入力の設定をする

iBusの言語入力メソッドとMozcという日本語入力エンジンを組み合わせて日本語入力ができるように設定します。
どちらもLinux環境では人気があるようです。

 **LXTerminal以下コードを実行。

$sudo apt install ibus-mozc #root権限にて実行


【インストール後の画面】
右上にひらがな入力を示していることが分かります。
f:id:toku_dango:20210410173451p:plain

LCDの設定をする

基本は以下(メーカーサイト)を見てインストールをいただければ問題ありませんが、本記事でも記載します。
www.lcdwiki.com

1.ドライバーのインストール

$sudo rm -rf LCD-show #対象ディレクトリフォルダの削除
$git clone https://github.com/goodtft/LCD-show.git
$chmod -R 755 LCD-show #アクセス特権の設定


2.LCD画面へ切り替え

$cd LCD-show
$sudo ./LCD35-show


HDMI画面に戻す場合は、以下を実行する。

$cd LCD-show
$sudo ./LCD-hdmi


3.タッチペンのキャリブレーション

$cd LCD-show
$sudo dpkg -i B xinput-calibrator_0.7.5-1_armhf.deb


※タッチペンでの動きが左右・上下逆の場合は、設定ファイルを修正する。

$sudo nano /etc/X11/xorg.conf.d/99-calibration.conf

上記を実行すると、ファイルの修正画面に移行するため、以下修正して保存する。
修正項目: [Option "SwapAces" "1"]という行を削除

メーカー公式ページで画面の設定変更方法も紹介されているのですが、
修正後に"起動時まっくろな画面+入力中のカーソルのみが表示され起動しない"等、問題も生じたので、実行は気を付けた方が良いかもしれません。
困ったときに役に立ったページのURLは以下です。
ラズパイに LCD をつける苦闘 - Qiita

まとめ

今回はRasberryPiを使う際のセットアップ方法をまとめました。
LinuxOSで分からないことはまだ多いので、勉強必要ですね。

Python:seabornを使ったグラフ作成まとめ

Pythonから利用できる可視化ライブラリ、Seabornのグラフの細かい設定
まとめました。
Seabornライブラリは、他の可視化ライブラリ Matplotlibと設定の仕方が違う所もあるので、たまに誤ってイライラしてしまいます・・
完全に自分用な感じもありますが記録を残します。

開発環境について

$wmic os get caption
>Microsoft Windows 10 Pro

$wmic os get osarchitecture
>64ビット

$python -V
Python 3.7.6

目次

グラフを作成する

1. Seabornをインストールする。

 以下コードを実行。

$pip install seaborn


2. データを用意する。

今回はサンプルとして、標準のデータセットirisを使用します。

iris = sns.load_dataset("iris")


3. グラフ(散布図)を描画する。

今回は2行2列の計4グラフを作成します。

 ①散布図
 ②カテゴリ別散布図
 ③折れ線グラフ
 ④散布図+線形回帰

fig, ((ax1, ax2),(ax3, ax4)) = plt.subplots(nrows=2,ncols=2,#グラフ個数の設定
                               figsize=(15, 15),#グラフサイズ設定
                               sharex=False,sharey=False)#グラフラベルの共有有無
sns.set_style("whitegrid") #グラフスタイルの設定
sns.despine(left=False, bottom=False)#軸の削除 Trueで削除

#散布図 (1行1列の設定)

sns.scatterplot(x="sepal_length", y="sepal_width",#対象ラベル選択
                marker="o", #マーカースタイルの設定
                s=30,#プロットサイズ設定
                color="green",#プロットカラー設定
                data=iris,#対象データ
                ax=ax1)


#カテゴリ別散布図 (1行2列の設定)
sns.scatterplot(x="sepal_length", y="sepal_width",#対象ラベル選択
                hue="species",#カテゴリごとに分けてプロット
                size="species",#カテゴリごとにプロットサイズを分ける
     sizes=(30, 100),#サイズの最小値と最大値を設定
                style="species",#カテゴリごとにプロットスタイルを変更する
                s=30,#プロットサイズ設定
                data=iris,#対象データ
                ax=ax2)

ax2.set(xlabel="sepal_length1", ylabel="sepal_width1",#軸ラベル名設定
        xlim=(4,8), ylim=(1,5),#軸レンジ設定
        xticks=[4, 5, 6, 7, 8], yticks=[1, 2, 3, 4, 5])#軸ラベル名設定

ax2.legend(loc='upper left',#凡例位置基準
           bbox_to_anchor=(0.8,1))#凡例位置設定

#折れ線グラフ (2行1列の設定)
sns.lineplot(x="sepal_length", y="sepal_width",#対象ラベル選択
             hue="species",#カテゴリごとに分けてプロット
             size="species", #カテゴリごとにプロットサイズを分ける
     sizes=(1, 3),#サイズの最小値と最大値を設定
             style="species",#カテゴリごとにプロットスタイルを変更する
             data=iris,#対象データ
             ax=ax3)

#散布図+線形回帰 (2行2列の設定)
sns.regplot(x="sepal_length", y="sepal_width",#対象ラベル選択
            marker=".", #マーカースタイルの設定
            scatter_kws={"s": 30},#マーカーサイズの設定
            color="green",#マーカーカラーの設定
            ci=None,#信頼区間の表示
            data=iris,#対象データ
            ax=ax4)

【描画されたグラフ】
f:id:toku_dango:20210403221017p:plain
  
”散布図”scatterplotは、"hue="で設定することでカテゴリ別に色分けすることが可能になります。
またscatterplotの中では、x,y軸の最大値、最小値の設定および、凡例の設定ができないため別途設定する必要があります。

まとめ

今回はSeabornを使ったグラフ作成方法についてまとめました。
可視化ライブラリMatplotlibと比較して、綺麗なグラフが書けるという良さがあるので、できる限り使用していきたいですね

Python:Plotlyを使って描画後に自由に動かせるグラフを作成する

f:id:toku_dango:20210321143714p:plain

Pythonから利用できる可視化ライブラリ、Plotlyの初歩的な使い方と細かい設定をまとめました。
Plotlyで作成したグラフは、描画後にグラフの軸を動かしたり拡大したり、プロットした点の座標(値)も示してくれるので、何回も描画し直す必要がないところが利点ですね。
※データ点が多すぎるとPCの性能によっては動きがカクカクするのでご注意ください。

この記事では紹介しませんが、Plotlyライブラリには種類があるようで、3Dプロットグラフが作成できるPlotly ExpressやDashというWebアプリケーションを使えるライブラリもあるようです。
※Plotly Expressで作成したグラフは、複数を並べて描画することができないので、並べて描画したい場合は使わない方が良いです。

グラフを作成する

1. plotlyをインストールする。

 以下コードを実行。

$pip install plotly


2. データを用意する。

今回はサンプルとして以下系列を用意します。

import numpy as np

t = np.linspace(0, 10, 100)
sin = np.sin(t)
cos = np.cos(t)


3. グラフ(散布図)を描画する。

「go.Figure()」内の引数の「data」に、グラフの種類(今回は散布図なので「go.Scatter()」とデータの配列を入れて、「fig.show()」でグラフを描画する。「go.Figure(data=[])」でデータを指定する方法のほかに、一度「go.Figure()」を作っておいて、「fig.add_trace()」と書く方法もあります。

import numpy as np
import plotly.graph_objects as go

t = np.linspace(0, 10, 100)
sin = np.sin(t)
fig = go.Figure(data=[go.Scatter(x=t, y=sin)]) 

#figの箇所についての別の書き方
#fig = go.Figure()
#fig.add_trace(go.Scatter(x=t, y=sin))

fig.show()


【描画されたグラフ】
f:id:toku_dango:20210321160018p:plain

ここで、「print(fig)」としてみると以下の通り出力されます。
出力結果を見るとどんな引数が必要なのかが分かるので、一度確認するのが良いかと思います。
「data」という引数以外に「layout」という引数があるのも分かりましたね。
詳細は公式ページ「ここ」に載っているのでぜひ参照ください。

print(fig)
>Figure({
    'data': [{'type': 'scatter',
              'x': array([ 0.        ,  0.1010101 ,  0.2020202 ,  0.3030303 ,  0.4040404 ,,,省略]),
              'y': array([ 0.        ,  0.10083842,  0.20064886,  0.2984138 ,  0.39313661,,,省略])}],
    'layout': {'template': '...'}


グラフのカスタマイズ

「go.Figure()」内の引数毎に設定項目と設定方法を説明していきます。
引数「data」で設定できる項目:グラフの種類やプロットの大きさ等のグラフに関すること
引数「layout」で設定できる項目:グラフのレンジ設定やタイトル、凡例などのレイアウトに関すること

グラフの設定について

グラフの種類によって若干設定項目が変わりますが、今回は散布図「go.Scatter」での代表的な設定項目を説明します。
サンプルコードは以下の通りで、「go.Figure()」内の「data」の引数をそれぞれ設定してあげることでグラフの設定ができます。

fig = go.Figure()
fig.add_trace(go.Scatter(x=t, y=sin, #対象データ
                         mode='lines+markers', #散布図+折れ線 散布図だけの場合はmarkers, 折れ線だけの場合はlines
                         line=dict(width=2, color='green'), #折れ線の書式設定
                         marker=dict(symbol='circle', size=10, color='blue'),#散布図の書式設定
                         name="sin",
                         )) 
fig.add_trace(go.Scatter(x=t, y=cos, #対象データ
                         mode='lines', #散布図+折れ線 散布図だけの場合はmarkers, 折れ線だけの場合はlines
                         line=dict(width=2, color='red'), #折れ線の書式設定
                         name="cos",
                         )) 
fig.show()

抜粋ですが、簡単な説明は以下の通り

オプション    説明
-mode	    lines+markers: 散布図+折れ線 / lines: 折れ線のみ / markers: 散布図のみ 
-line      折れ線の設定 width: ライン幅 / color: ライン色 
        (dict形式で渡す or 「line_width=」 のようにアンダースコアを挟んで渡す方法も問題ない) 
-marker	    散布図の設定 symbol: プロット形設定 / size: プロットサイズ /color: プロット色
        (dict形式で渡す or 「marker_symbol=」 のようにアンダースコアを挟んで渡す方法も問題ない) 


【描画されたグラフ】
f:id:toku_dango:20210321160113p:plain

また、上記のように設定した後に以下のようにコードを重ねることで、設定の上書きも可能。
「fig.update_traces」の引数に上記と同じ書き方で設定できます。

fig.update_traces(mode='lines+markers', line_color='blue', marker_size=15)



レイアウトの設定について

サンプルコードは以下の通りで、「go.Figure()」内の「layout」の引数をそれぞれ設定してあげることでグラフの設定ができます。コードをコピー/修正いただければ、好きな設定に変更できるのではないでしょうか。
細かい仕様は以下を参照ください。

plotly.com

fig = go.Figure()
fig.add_trace(go.Scatter(x=t, y=sin, #対象データ
                         mode='lines+markers', #散布図+折れ線 散布図だけの場合はmarkers, 折れ線だけの場合はlines
                         line=dict(width=2, color='green'), #折れ線の書式設定
                         marker=dict(symbol='circle', size=10, color='blue'),
                         name='sin'))
fig.add_trace(go.Scatter(x=t, y=cos, #対象データ
                         mode='lines+markers', #散布図+折れ線 散布図だけの場合はmarkers, 折れ線だけの場合はlines
                         line=dict(width=2, color='orange'), #折れ線の書式設定
                         marker=dict(symbol='circle', size=10, color='red'),
                         name='cos'))

fig.update_layout(template='seaborn',#テーマ
                  autosize=False, width=1200, height=700,#グラフサイズ
                  margin=dict(l=100, r=100, b=200, t=100, pad=10, autoexpand=False),#余白幅
                  title=dict(text="Subplots", font_size=30, font_color='green'), #グラフタイトル書式
                  legend=dict(title_text="legend",#凡例書式
       orientation="h",yanchor="bottom",y=1.02,xanchor="right",x=1, #凡例位置の設定
                  bgcolor='lightgrey', font_color='red'),#凡例色の設定
                  paper_bgcolor="White",#背景色
                  xaxis=dict(range=[0,10],#グラフの範囲 横軸
                             rangeslider=dict(autorange=True),#range sliderを表示 横軸
                             linewidth=1, mirror=True, linecolor='black',#グラフの枠設定 横軸
                             showgrid=True, gridwidth=1, gridcolor='black',#グラフのグリッド設定 横軸
                             zeroline=True, zerolinewidth=1, zerolinecolor='LightPink',#グラフの0ライングリッド設定 横軸
                             title=dict(text='time', font_size=20),#グラフの軸ラベル書式 横軸
                             tickfont=dict(color='black', size=20)),#グラフの軸目盛り書式 横軸
                  yaxis=dict(range=[-1,1],#グラフの範囲 縦軸
                             linewidth=1, mirror=True, linecolor='black',#グラフの枠設定 縦軸
                             showgrid=True, gridwidth=1, gridcolor='black',#グラフのグリッド設定 横軸
                             zeroline=True, zerolinewidth=1, zerolinecolor='LightPink',#グラフの0ライングリッド設定 縦軸
                             title=dict(text='value', font_size=20),#グラフの軸ラベル書式 縦軸
                             tickfont=dict(color='black', size=20)))#グラフの軸目盛り書式 横軸
fig.show()

※サンプルコードは、コードがごちゃごちゃするのを避けるため、「fig.update_layout」を使ってレイアウトを調整しています。このオプションも「fig.update_traces」と同じように設定の上書きができるできます。

【描画されたグラフ】
f:id:toku_dango:20210321162131p:plain

複数グラフの並列描画

Plotlyの「make_subplots」モジュールを使って「fig」を作り、上記と同じように「data」「layout」をグラフごとに設定してあげることで描画することができます。
「data」については、「row」「col」の指定が追加で必要です。
「layout」については、グラフ軸は1グラフ目が「xaxis」「yaxis」、2グラフ目が「xaxis2」「yaxis2」に該当するようです。

from plotly.subplots import make_subplots
fig = make_subplots(rows=1, cols=2)
fig.add_trace(go.Scatter(x=t, y=sin, #対象データ
                         mode='lines+markers', #散布図+折れ線 散布図だけの場合はmarkers, 折れ線だけの場合はlines
                         line=dict(width=2, color='green'), #折れ線の書式設定
                         marker=dict(symbol='circle', size=10, color='blue'),
                         name='sin'), row=1, col=1)
fig.add_trace(go.Scatter(x=t, y=cos, #対象データ
                         mode='lines+markers', #散布図+折れ線 散布図だけの場合はmarkers, 折れ線だけの場合はlines
                         line=dict(width=2, color='orange'), #折れ線の書式設定
                         marker=dict(symbol='circle', size=10, color='red'),
                         name='cos'), row=1, col=2)

fig.update_layout(template='seaborn',#テーマ
                  autosize=False, width=1200, height=700,#グラフサイズ
                  margin=dict(l=100, r=100, b=200, t=100, pad=10, autoexpand=False),#余白幅
                  title=dict(text="Subplots", font_size=30, font_color='green'), #グラフタイトル書式
                  legend=dict(title_text="legend", #凡例書式
     orientation="h",yanchor="bottom",y=1.02,xanchor="right",x=1, #凡例位置の設定
                  bgcolor='lightgrey', font_color='red'),#凡例色の設定
                  paper_bgcolor="White",#背景色
                  xaxis=dict(range=[0,10],#グラフの範囲 横軸
                             rangeslider=dict(autorange=True),#range sliderを表示 横軸
                             linewidth=1, mirror=True, linecolor='black',#グラフの枠設定 横軸
                             showgrid=True, gridwidth=1, gridcolor='black',#グラフのグリッド設定 横軸
                             zeroline=True, zerolinewidth=1, zerolinecolor='LightPink',#グラフの0ライングリッド設定 横軸
                             title=dict(text='time', font_size=20),#グラフの軸ラベル書式 横軸
                             tickfont=dict(color='black', size=20)),#グラフの軸目盛り書式 横軸
                  yaxis=dict(range=[-1,1],#グラフの範囲 縦軸
                             linewidth=1, mirror=True, linecolor='black',#グラフの枠設定 縦軸
                             showgrid=True, gridwidth=1, gridcolor='black',#グラフのグリッド設定 横軸
                             zeroline=True, zerolinewidth=1, zerolinecolor='LightPink',#グラフの0ライングリッド設定 縦軸
                             title=dict(text='value', font_size=20),#グラフの軸ラベル書式 縦軸
                             tickfont=dict(color='black', size=20)),#グラフの軸目盛り書式 横軸
                  xaxis2=dict(range=[0,10],#グラフの範囲 横軸
                             rangeslider=dict(autorange=True),#range sliderを表示 横軸
                             linewidth=1, mirror=True, linecolor='black',#グラフの枠設定 横軸
                             showgrid=True, gridwidth=1, gridcolor='black',#グラフのグリッド設定 横軸
                             zeroline=True, zerolinewidth=1, zerolinecolor='LightPink',#グラフの0ライングリッド設定 横軸
                             title=dict(text='time', font_size=20),#グラフの軸ラベル書式 横軸
                             tickfont=dict(color='black', size=20)),#グラフの軸目盛り書式 横軸
                  yaxis2=dict(range=[-1,1],#グラフの範囲 縦軸
                             linewidth=1, mirror=True, linecolor='black',#グラフの枠設定 縦軸
                             showgrid=True, gridwidth=1, gridcolor='black',#グラフのグリッド設定 横軸
                             zeroline=True, zerolinewidth=1, zerolinecolor='LightPink',#グラフの0ライングリッド設定 縦軸
                             title=dict(text='value', font_size=20),#グラフの軸ラベル書式 縦軸
                             tickfont=dict(color='black', size=20)))#グラフの軸目盛り書式 横軸
fig.show()


【描画されたグラフ】
f:id:toku_dango:20210321163116p:plain

まとめ

今回はPlotlyを使ったグラフ作成方法についてまとめました。
データ数が多くない限り、いろいろと動かすことができるPlotlyのグラフは使い勝手が良いかなと思います。
設定方法に困ったら、「print(fig)」をして引数設定を見ることも重要ですね。