株価シュミレーターの計算結果確認ツール作成

###今回は、前回3部作で紹介させて頂いた、「なんちゃって株価データ」生成ツールGUI版用の、生成データ可視化専用ツールについて簡単に触れさせて頂きます。

##この可視化ツールが出来ること・・・
この可視化ツールは、前回までのデータ生成ツール専用に作られていますので、他のケースへの転用を検討される場合は、その関連部分を書き直して頂く必要があります。

下図は、このツールを使ってSingleStore向けに生成された株価データを可視化した例になります。
基本的にはPython界の汎用モジュールを幾つか組み合わせたモノになりますので、改造や他のデータ可視化の際にも柔軟に対応出来るかと思います。

![スクリーンショット 2021-11-05 7.52.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/01b0ae3f-1ff7-e0d3-6990-5d49b88864b9.png)

データの可視化・・・・と最近よく耳にされるかと思います。確かに自分で作って言うのも・・の典型的なパターンですが、数値データの塊を理解する場合の可視化は非常に便利・・・・これは人類が表計算ソフトと初めて出会ってからの経験と常識なのですが・・・改めてPython環境って凄い！と思った次第です（苦笑）。

##先ずはお約束の事前設定部分です。
この部分は、ある意味で定番のモジュールを書き並べていますので、特に説明は不要かと思います。
また、転用される際には随時必要なモジュールの取り込みや削除を行う様にしてください。
後半部分は、内部で改造等に使う場合の変数などを抽出して書き並べているだけになります。

この部分での留意点は、

~~~Python
Viz_Type = MySQL_CDC
~~~

の設定で、此処で可視化対象を選択し変数設定しています。使う変数については解り易い様にこの上の部分にリアル名で記述してありますので、そのまま＝の右側に書けばOK!です。

但し、今回はEqualumのCDCストリーミングで使うケースと、SingleStoreのSQL性能検証や機械学習、AI連携用の2種類しか想定していませんので、設定する選択肢はSingleStoreとそれ以外（MySQL_CDCかMySQL_TGT）の2択になります。

~~~Python
#
#  株価シュミレータ専用可視化ツール
#
import matplotlib.pyplot as plt
import datetime
import pymysql.cursors
#
# 日本語フォントの設定
from matplotlib import rcParams
rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = ['Hiragino Maru Gothic Pro', 'Yu Gothic', 'Meirio', 'Takao', 'IPAexGothic', 'IPAPGothic', 'VL PGothic', 'Noto Sans CJK JP']
#
# 可視化するデータテーブルを設定
#
SingleStore = 0
MySQL_CDC = 1
MySQL_TGT = 2
#
Viz_Type = MySQL_CDC
#
# Equalumソース側のMySQL情報
CDC_Host = "xxx.xxx.xxx.xxx"
CDC_Port = 3306
CDC_User = "xxxxx"
CDC_Pass = "xxxxx"
CDC_DB = "xxxxx"
CDC_Char = "utf8mb4"
#
# Equalumターゲット側のMySQL情報
TGT_Host = "yyy.yyy.yyy.yyy"
TGT_Port = 3306
TGT_User = "yyyyy"
TGT_Pass = "yyyyy"
TGT_DB = "yyyyy"
TGT_Char = "utf8mb4"
#
# SigleStoreへ出力
SS_Host = "zzz.zzz.zzz.zzz"
SS_Port = 3306
SS_User = "zzzzz"
SS_Pass = "zzzzz"
SS_DB = "zzzzz"
SS_Char = "utf8"
#
T_Name = "Stock_Demo"
#
SQL1 = "SELECT Stock1 FROM Stock_Demo ORDER BY "
SQL2 = "SELECT Stock2 FROM Stock_Demo ORDER BY "
SQL3 = "SELECT Stock3 FROM Stock_Demo ORDER BY "
#
ODR_SQL_CDC = "id_CDC"
ODR_SQL_TGT = "id_TGT"
ODR_SQL_SS = "id_SS"
#
RUN_Message = "株価シュミレーション・ツールを起動します。"
EXT_Message = "全ての処理が終了しました。"
DTS_Message1 = "指定されたデータベースから可視化データを抽出します。"
DTS_Message2 = "指定されたデータベースから可視化データを抽出しました。"
SQL_Message1 = "クエリに利用するSQLを作成します。"
SQL_Message2 = "クエリに利用するSQLを作成しました。"
VIZ_Message1 = "データの可視化処理を開始します。"
VIZ_Message2 = "データの可視化処理が終了しました。"
INT_Message = "!!!!! 割り込みが発生しました。 !!!!!"
#
ON = 1
OFF = 0
#
~~~

##処理の実際部分
基本的には、前回までのデータ生成ツールと同じ様な作りになっています。
（1）　指定されたデータベースとの接続処理（接続情報を戻す）
（2）　指定されたデータベースに指示されたSQLを投げてデータを取り出す（データリストを戻す）
（3）　条件に応じたSQL文を作成する
の各手続きが記述されています。

~~~Python
print("------------------------------------------------")
print("******************* 処理開始 *******************")
print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") + " : " + RUN_Message)
print("------------------------------------------------")
#
# データベースとの接続とテーブルの作成
def Open_DB(DB_Type):

    # シングルストア向けの設定
    if DB_Type == SingleStore:

        Host_Info = SS_Host
        Port_Info = SS_Port
        User_Info = SS_User
        Pass_Info = SS_Pass
        DB_Info   = SS_DB
        Char_Info = SS_Char

    # MySQL_CDC向けの設定
    elif DB_Type == MySQL_CDC:

        Host_Info = CDC_Host
        Port_Info = CDC_Port
        User_Info = CDC_User
        Pass_Info = CDC_Pass
        DB_Info   = CDC_DB
        Char_Info = CDC_Char

    # MySQL_TGT向けの設定
    elif DB_Type == MySQL_TGT:

        Host_Info = TGT_Host
        Port_Info = TGT_Port
        User_Info = TGT_User
        Pass_Info = TGT_Pass
        DB_Info   = TGT_DB
        Char_Info = TGT_Char

    # ターゲットのデータベースに接続してポインタを取得
    db = pymysql.connect(host = Host_Info, port = Port_Info, user = User_Info, password = Pass_Info, db = DB_Info, charset = Char_Info, cursorclass = pymysql.cursors.DictCursor)     

    # データベース処理に必要なポインタを戻す
    return(db)
#
# 指定されたDBにクエリを掛けてデータを抽出する
#
def Data_Set(DB_Type, SQL):

    print("------------------------------------------------")
    print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") + " : " + DTS_Message1)
    print("------------------------------------------------")   

    # ローカル変数の初期化
    Tmp_Data = []
    Data = []
    i = 0
    Offset = 1

    # 抽出先のデータベースと接続
    db = Open_DB(DB_Type)

    # データの抽出作業を行う
    with db.cursor() as cursor:

        # クエリ関連の初期化設定
        cursor.arraysize = 1000

        # データベースへの書き込み
        cursor.execute(SQL)    
        db.commit()

        # クエリ結果を取り出す
        for Query_Data in cursor.fetchall():                
            for item in Query_Data.values(): Tmp_Data.append(item) 

        # クエリ結果を利用可能な状態に変換する
        for start in range(0, len(Tmp_Data), Offset):              
            Data.append(Tmp_Data[i])  
            i = i  + 1

    # データベース接続を切断
    db.close()

    print("------------------------------------------------")
    print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") + " : " + DTS_Message2)
    print("------------------------------------------------")  

    # 利用可能な状態のデータリストを戻す
    return(Data)
#
# 格納データ読み出し用のSQLを作る
#
def Make_SQL(DB_Type, SQL):

    print("------------------------------------------------")
    print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") + " : " + SQL_Message1)
    print("------------------------------------------------")   

    # クエリ用のSQLを完成させる（オーダー対象を合わせる）
    if DB_Type == MySQL_CDC:    SQL = SQL + ODR_SQL_CDC
    elif DB_Type == MySQL_TGT:  SQL = SQL + ODR_SQL_TGT
    else:                       SQL = SQL + ODR_SQL_SS

    print("------------------------------------------------")
    print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") + " : " + SQL_Message2)
    print("------------------------------------------------")   

    # 利用可能な状態のSQLにして戻す
    return(SQL)
~~~

##可視化関連の処理とメイン部分・・・
以下は、可視化処理に必要な処理と、全体を仕切るメイン部分になります。
基本的には
（1）　必要なデータを読み出して描画に必要なデータ列を作る
（2）　可視化チャートの準備を行う
（3）　実際にプロットする
の手順で処理が行われます。

EqualumのCDCストリーミング用の場合は、双方のデータを可視化比較出来る様に、2つのチャートを並べて出力するようにしています。

メインの処理は・・・・・これだけになりました（汗）。。。

~~~Python
#
# Equalum用の比較チャートを作成
#
def Viz_Stock2(Fig):

    # MySQLのCDC側のデータを読み出す
    Result1 = Data_Set(MySQL_CDC, Make_SQL(MySQL_CDC, SQL1))
    Result2 = Data_Set(MySQL_CDC, Make_SQL(MySQL_CDC, SQL2))
    Result3 = Data_Set(MySQL_CDC, Make_SQL(MySQL_CDC, SQL3))

    # MySQLのTGT側のデータを読み出す
    Result4 = Data_Set(MySQL_TGT, Make_SQL(MySQL_TGT, SQL1))
    Result5 = Data_Set(MySQL_TGT, Make_SQL(MySQL_TGT, SQL2))
    Result6 = Data_Set(MySQL_TGT, Make_SQL(MySQL_TGT, SQL3))

    # 2つの可視化チャートを並べて表示
    axes1 = fig.add_subplot(1,2,1)
    axes2 = fig.add_subplot(1,2,2)

    axes1.plot(Result1, label = "（株）松_CDC", color = "magenta")
    axes1.plot(Result2, label = "（株）竹_CDC", color = "lime")
    axes1.plot(Result3, label = "（株）梅_CDC", color = "cyan")
    axes1.set_title("MySQL_CDC側の可視化")
    axes1.legend()

    axes2.plot(Result4, label = "（株）松_TGT", color = "red")
    axes2.plot(Result5, label = "（株）竹_TGT", color = "green")
    axes2.plot(Result6, label = "（株）梅_TGT", color = "blue")
    axes2.set_title("MySQL_TGT側の可視化")
    axes2.legend()
#
# SingleStore用のチャートを作成
#
def Viz_Stock1(Fig):

    # SingleStoreのデータを読み出す
    Result1 = Data_Set(SingleStore, Make_SQL(SingleStore, SQL1))
    Result2 = Data_Set(SingleStore, Make_SQL(SingleStore, SQL2))
    Result3 = Data_Set(SingleStore, Make_SQL(SingleStore, SQL3))

    # 可視化チャートを表示
    axes = fig.add_axes([0.1, 0.1, 0.8, 0.8])
    
    axes.plot(Result1, label="（株）松_SS")
    axes.plot(Result2, label="（株）竹_SS")
    axes.plot(Result3, label="（株）梅_SS")
    fig.suptitle("SingleStoreに格納されたデータの可視化", fontsize = 16)
    axes.legend()
#
# メインの処理
#
try:

    print("------------------------------------------------")
    print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") + " : " + VIZ_Message1)
    print("------------------------------------------------")

    # グラフ描画の準備
    fig = plt.figure()

    # Equalum向けの可視化
    if Viz_Type == SingleStore: Viz_Stock1(fig)
    else:                       Viz_Stock2(fig)

    print("------------------------------------------------")
    print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") + " : " + VIZ_Message2)
    print("------------------------------------------------")   

    # 画面に出力
    plt.show()

except KeyboardInterrupt:

    print("------------------------------------------------")
    print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") + " : " + INT_Message)
    print("------------------------------------------------") 

finally:

    print("------------------------------------------------")
    print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") + " : " + EXT_Message)
    print("******************* 処理終了 *******************")
    print("------------------------------------------------")
#########################################################################################
~~~

##Equalum向けの出力例
以下は、Equalumで処理を行った結果と、CDCストリーミングに使った生成データ（前回までののGUIツール）を可視化比較出力した例になります。

![スクリーンショット 2021-11-05 7.58.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/73b09244-6ada-9474-1b01-88f9e46cbd46.png)

EqualumのCDC即時同期がExactlyOnceで安心・安全・確実に行われ、綺麗な同期結果が表示されている事が解ります。

##まとめ
各種検証系で、乱数や多様な方程式等を駆使して算出した数値データを、シンプルに可視化確認出来ると便利かと思いますので、お役に立てるのであれば、遠慮無くNDA（ノン・ダメ出し・アグリーメント）ベースにてご活用ください。

次回は、以前予定していた記事に戻りたいと思いますので、その際はまた宜しくお願い致します。

[**株価シュミレーター（？）を作る（1）**](https://qiita.com/wadaken1961/items/e0b4b4c64e6b8329354c)はこちら
[**株価シュミレーター（？）を作る（2）**](https://qiita.com/wadaken1961/items/c7c740944aeff52a1e49)はこちら
[**株価シュミレーター（？）を作る（3）**](https://qiita.com/wadaken1961/items/9c2ab22b2ffe1c828bb3)はこちら