前の関連記事:linuxBean14.04(78)Jupyter Notebookの内容を直接Bloggerに貼り付ける方法
linuxBean14.04(76)MySQL5.6からPython3.4で散布図をプロットするの散布図にlinuxBean14.04(75)matplotlibのインタラクティブなグラフでインストールしたmpldatacursorパッケージを使って、マーカーをクリックすると値がポップアップするようにします。Jupyter NotebookではポップアップはでませんのでPyCharmから実行しています。
マーカーのx,y座標の値を使ってラベルをポップアップする
#!~/anaconda3/bin/python3.4 # -*- coding: utf-8 -*- import mysql.connector from mysql.connector import errorcode import pandas as pd import matplotlib.pyplot as plt import matplotlib from mpldatacursor import datacursor matplotlib.rcParams['toolbar'] = 'None' # ツールバーを抑制。 config = { 'user': 'User01', 'password': 'user01_pass', 'database': 'world' } try: cnx = mysql.connector.connect(**config) # MySQLサーバに接続する。 except mysql.connector.Error as err: if err.errno == errorcode.ER_ACCESS_DENIED_ERROR: print("ユーザー名かパスワードが間違っています。") elif err.errno == errorcode.ER_BAD_DB_ERROR: print("データベース「{}」が存在しません。".format(config['database'])) else: print(err) else: query = 'SELECT Name, Continent, Population, LifeExpectancy, GNP FROM Country' # MySQLに渡すSQL文。 df=pd.read_sql(query,cnx) # pandasのデータフレームにテーブルを取得。 cnx.close() # MySQLとの接続を閉じる。 df.rename(columns={'Name': '国', 'Continent': '大陸', 'Population': '人口', 'LifeExpectancy': '平均余命', 'GNP':'国民総生産'},inplace=True) # 列インデックス名を変更。 df.dropna(inplace=True) # 欠損値がある行を削除。 df = df.ix[df['国民総生産']>100] # 国民総生産が100より大きい行のみ取得。 fig, ax = plt.subplots(figsize=(8,6)) # 8x6インチの図に設定。 ax.grid(True) # グリッドの表示を有効にする。 ax.scatter(x=df['国民総生産'], y=df['平均余命'], s=df['人口']/300000, alpha=0.5) # 散布図をプロットする。 ax.set_xlim((100, 20000000)) # x軸の目盛りを100から20000000に制限する。 ax.set_xlabel('国民総生産',size=15) # x軸のラベルを設定。 ax.set_xscale('log') # x軸の目盛りをlogにする。 ax.set_ylabel('平均余命',size=15) # y軸のラベルを設定。 ax.set_title('平均余命 対 国民総生産', size=20) # プロットのタイトルを設定。 ax.tick_params(labelsize=15) # 目盛りラベルのフォントサイズを設定。 label = '国民総生産:{x:,}\n平均余命:{y}' # マウスカーソル近くのマーカーの座標x,yを使ってラベルを作成。 datacursor(hover=True, formatter=label.format) plt.show()
マウスカーソルの近くにあるマーカーの座標がx, yで得られることを利用して40行目でポップアップあせるラベルの書式を作っています。
formatterオプションを指定しない場合はmatplotlib.axes.scatter()の引数のx, y, sの値が表示されました。でもxの値がおかしいですね。
マーカーのx,y座標の値を使ってデータフレームの同じ行の値を表示させる
これが結構悩みました。
Nullege: A Search Engine for Python source codeの例をいくつか眺めてようやくひとつの解を得ました。
datacursor()のprops_overrideオプションを使ってformatterオプションに渡す引数を関数で修飾してラベルを作成しました。
from mpldatacursor import datacursor ?datacursor()Jupyter Notebookで?をつけて実行するとヘルプが表示されます。
例がないとヘルプを読んだだけではなかなか理解できませんね。
#!~/anaconda3/bin/python3.4 # -*- coding: utf-8 -*- import mysql.connector from mysql.connector import errorcode import pandas as pd import matplotlib.pyplot as plt import matplotlib from mpldatacursor import datacursor matplotlib.rcParams['toolbar'] = 'None' # ツールバーを抑制。 config = { 'user': 'User01', 'password': 'user01_pass', 'database': 'world' } try: cnx = mysql.connector.connect(**config) # MySQLサーバに接続する。 except mysql.connector.Error as err: if err.errno == errorcode.ER_ACCESS_DENIED_ERROR: print("ユーザー名かパスワードが間違っています。") elif err.errno == errorcode.ER_BAD_DB_ERROR: print("データベース「{}」が存在しません。".format(config['database'])) else: print(err) else: query = 'SELECT Name, Continent, Population, LifeExpectancy, GNP FROM Country' # MySQLに渡すSQL文。 df=pd.read_sql(query,cnx) # pandasのデータフレームにテーブルを取得。 cnx.close() # MySQLとの接続を閉じる。 df.rename(columns={'Name': '国', 'Continent': '大陸', 'Population': '人口', 'LifeExpectancy': '平均余命', 'GNP':'国民総生産'},inplace=True) # 列インデックス名を変更。 df.dropna(inplace=True) # 欠損値がある行を削除。 df = df.ix[df['国民総生産']>100] # 国民総生産が100より大きい行のみ取得。(logグラフに表示しやすいため) df = df.set_index(['国民総生産','平均余命']) # ('国民総生産','平均余命')をインデックスを変更。 idx = df.index # インデックスオブジェクトを取得。 fig, ax = plt.subplots(figsize=(8,6)) # 8x6インチの図に設定。 ax.grid(True) # グリッドの表示を有効にする。 ax.scatter(x=idx.get_level_values(0), y=idx.get_level_values(1), s=df['人口']/300000, alpha=0.5) # 散布図をプロットする。 ax.set_xlim((100, 20000000)) # x軸の目盛りを100から20000000に制限する。 ax.set_xlabel('国民総生産',size=15) # x軸のラベルを設定。 ax.set_xscale('log') # x軸の目盛りをlogにする。 ax.set_ylabel('平均余命',size=15) # y軸のラベルを設定。 ax.set_title('平均余命 対 国民総生産', size=20) # プロットのタイトルを設定。 ax.tick_params(labelsize=15) # 目盛りラベルのフォントサイズを設定。 def override(**kwargs): # datacursorのformatterに渡す変数を変更する関数。 s = df.ix[(kwargs['x'], kwargs['y'])] # (x,y)座標をインデックスとしてdfの行のデータを取得。 kwargs['label'] = '{0}\n{1}\n国民総生産:{2:,.0f}\n平均余命:{3}\n人口:{2:,.0f}'.format(s[0], s[1], kwargs['x'], kwargs['y'], s[2]) return kwargs datacursor(hover=True, props_override=override, formatter='{label}'.format) plt.show()
31行目でデータフレームdfのインデックスを('国民総生産','平均余命')のタプルに変更しています。
こうすることによって43行目でマーカーの座標(xが国民総生産、yが平均余命)をインデックスにしてデータフレームdfから他の列のデータを得ています。
難点はプロットがでてくるまで時間がかかることです。
プロットがでたあとはマウスカーソルを動かすとでてくるポップアップは素早く切り替わります。
こうすることによって43行目でマーカーの座標(xが国民総生産、yが平均余命)をインデックスにしてデータフレームdfから他の列のデータを得ています。
難点はプロットがでてくるまで時間がかかることです。
プロットがでたあとはマウスカーソルを動かすとでてくるポップアップは素早く切り替わります。
参考にしたサイト
mpldatacursor/README.rst at master · joferkington/mpldatacursor · GitHub
ヘルプはJupyter Notebookで?datacursor()で表示されるdocstringに詳しいです。
axes — Matplotlib 1.4.3 documentation
プロットはこのaxesオブジェクトを操作します。
Nullege: A Search Engine for Python source code
このサイトはPythonのコード例がたくさんあって便利に使えそうです。
pandas: powerful Python data analysis toolkit — pandas 0.17.0 documentation
私はPythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理の本も参考にしています。
0 件のコメント:
コメントを投稿