前の関連記事:linuxBean14.04(78)Jupyter Notebookの内容を直接Bloggerに貼り付ける方法
linuxBean14.04(76)MySQL5.6からPython3.4で散布図をプロットするの散布図にlinuxBean14.04(75)matplotlibのインタラクティブなグラフでインストールしたmpldatacursorパッケージを使って、マーカーをクリックすると値がポップアップするようにします。Jupyter NotebookではポップアップはでませんのでPyCharmから実行しています。
マーカーのx,y座標の値を使ってラベルをポップアップする
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
#!~/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オプションに渡す引数を関数で修飾してラベルを作成しました。
1 2 |
from mpldatacursor import datacursor ?datacursor() |
例がないとヘルプを読んだだけではなかなか理解できませんね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#!~/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 件のコメント:
コメントを投稿