linuxBean14.04(80)mpld3でツールチップ

2015-10-21

旧ブログ

t f B! P L

前の関連記事:linuxBean14.04(79)mpldatacursorで散布図のマーカーのラベルをポップアップ表示する


マウスカーソルを合わせるとでてくるポップアップをツールチップというそうです(ツールチップ - Wikipedia)。前回やったmatplotlibでツールチップを表示させる方法はJupyter Notebookでは使えないのでmpld3を使ってツールチップを表示させます。散布図で対数スケールを使う場合は少々難がありました。

(2015.10.23追記。対数スケールの対処方法がわかったのでlinuxBean14.04(82)mpld3でツールチップ(やり直し編)でやり直しました。)

mpld3で散布図で軸スケールに'log'を指定するとプロットが逆転する

linuxBean14.04(69)MySQL5.6にPython3.3から接続するのMySQLのworld databaseからデータフレームにデータを得ます。
In [1]:
#!~/anaconda3/bin/python3.4
# -*- coding: utf-8 -*-
import mysql.connector
from mysql.connector import errorcode
import pandas as pd
import matplotlib.pyplot as plt
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との接続を閉じる。
プロッティングに使うpandasのデータフレームのデータを整えます。
In [2]:
    df.rename(columns={'Name': '国', 'Continent': '大陸', 'Population': '人口', 'LifeExpectancy': '平均余命', 'GNP':'国民総生産'},inplace=True) # 列インデックス名を変更。
    df.dropna(inplace=True)  # 欠損値がある行を削除。
    df = df.ix[df['国民総生産']>100]  # 国民総生産が100より大きい行のみ取得。(logグラフに表示しやすいため)
mpld3のHTML tooltip pluginの設定をします。

まずツールチップで表示される表のCSSの設定をしています。
In [3]:
    import mpld3
    from mpld3 import plugins
    # ラベルのCSSの設定
    css = """
    table
    {
      border-collapse: collapse;
    }
    th
    {
      color: #ffffff;
      background-color: #000000;
    }
    td
    {
      background-color: #cccccc;
    }
    table, th, td
    {
      font-family:Arial, Helvetica, sans-serif;
      border: 1px solid black;
      text-align: right;
    }
    """
mpld3のツールチッププラグインで表示されるラベルは前回のmpldatacursorと違ってマーカーと同じ順に予め作成してリストに入れておきます。
In [4]:
    df = df.set_index(['国'])  # ラベルの列名を国にしたいので国をインデックスに変更する。
    # プロットするマーカーと同じ順にリストにラベルを取得。
    labels = []  # マーカーのラベルを入れるリスト。
    for i in df.index:  # iには国が入る。
        label = df.ix[[i],:].T  # 国の行を転置して縦にする。
        label.columns = [i] # ラベルの列名を国にする。(国をインデックスにしてから転置したのでこの操作は不要になりました。)
        labels.append(label.to_html())  # データフレームをhtmlに変換してリストに取得。
matplotlibのプロットの作成とmpld3.display()はひとつのセルでやってしまわないといけません。
In [5]:
    fig, ax = plt.subplots(figsize=(8,6))  # 8x6インチの図に設定。
    ax.grid(True)  # グリッドの表示を有効にする。
    ax.set_xlim((100, 20000000))  # x軸の目盛りを100から20000000に制限する。
    ax.set_xlabel('国民総生産',size=15)  # x軸のラベルを設定。
    ax.set_xscale('log')  # x軸の目盛りをlogにする。散布図のmpld3では正しく表示されない。
    ax.set_ylabel('平均余命',size=15)  # y軸のラベルを設定。
    ax.set_title('平均余命 対 国民総生産', size=20)  # プロットのタイトルを設定。
    ax.tick_params(labelsize=15)  # 目盛りラベルのフォントサイズを設定。
    points = ax.scatter(x=df['国民総生産'], y=df['平均余命'], s=df['人口']/300000, alpha=0.5)  # 散布図をプロットする。
    tooltip = plugins.PointHTMLTooltip(points, labels, voffset=10, hoffset=10, css=css)
    plugins.connect(fig, tooltip)
    mpld3.display()
/home/pq/anaconda3/lib/python3.4/site-packages/matplotlib/collections.py:590: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
  if self._edgecolors == str('face'):
Out[5]:

何かおかしいです、、、

そう、y軸に対してマーカーの位置が上下逆になっています。

python - Incorrect mpld3 plotting in log scale - Stack Overflowに同様に散布図で軸にlogを指定すると同じようになると報告されています。

Incorrect mpld3 plotting in log scale · Issue #227 · jakevdp/mpld3 · GitHubにすでにバグ報告されていていまのところ原因不明で修正されていないようです。

mpld3では目盛りラベルの変更ができない

(2015.10.23追記linuxBean14.04(81)mpld3で目盛りラベルを変更するで変更できました。)

軸のスケールに対数を指定すると正しくマーカーが表示されないので値の方を対数にします。
In [6]:
    import numpy as np
    fig, ax = plt.subplots(figsize=(8,6))  # 8x6インチの図に設定。
    ax.grid(True)  # グリッドの表示を有効にする。
    ax.set_xlim((np.log10(100), np.log10(20000000)))  # x軸の目盛りを100から20000000に制限する。
    ax.set_xlabel('log10(国民総生産)',size=15)  # x軸のラベルを設定。
    ax.set_ylabel('平均余命',size=15)  # y軸のラベルを設定。
    ax.set_title('平均余命 対 国民総生産', size=20)  # プロットのタイトルを設定。
    ax.tick_params(labelsize=15)  # 目盛りラベルのフォントサイズを設定。
    points = ax.scatter(x=np.log10(df['国民総生産']), y=df['平均余命'], s=df['人口']/300000, alpha=0.5)  # 散布図をプロットする。
    tooltip = plugins.PointHTMLTooltip(points, labels, voffset=10, hoffset=10, css=css)
    plugins.connect(fig, tooltip)
    mpld3.display()
/home/pq/anaconda3/lib/python3.4/site-packages/matplotlib/collections.py:590: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
  if self._edgecolors == str('face'):
Out[6]:

これで思った通りのグラフができてあとはax.set_xticklabels()を使ってX軸の目盛りラベルを$$${10}^{2},{10}^{3},{10}^{4},{10}^{5},{10}^{6},{10}^{7}$$$に変更すればよいと思ったのですがそれができません。

Tick labels & locations · Issue #22 · jakevdp/mpld3

目盛りラベルの変更はmpld3では実装されていないそうです。

matplotlibから変更する部分の取得が困難だそうです。

mpld3のプラグインを使って変更する姑息的方法も紹介されていますが、HTMLの要素の取得を汎用的にする方法はないようです。

このページのJupyter Notebookの出力はlinuxBean14.04(78)Jupyter Notebookの内容を直接Bloggerに貼り付ける方法で行っていますが、mpld3のツールチップの出力部分はjavascriptが長すぎてBloggerにすべてを投稿できませんでした。

なのでBlogger:外部ファイル置き場をGoogleドライブからGoogleサイトへ変更の方法でmpld3の出力のjavascriptの部分だけGoogleサイトにおいてそこから呼び出しています。

図の下の部分が一部欠けて見えています。(2015.10.21修正しました。linuxBean14.04(78)Jupyter Notebookの内容を直接Bloggerに貼り付ける方法の2015.10.21追記、参照。)

iOS Safariで見ると図の右の部分が欠けて見えます。

タップではツールチップは表示されませんでした。

参考にしたサイト


ツールチップ - Wikipedia
マウスカーソルを合わせるとでてくるポップアップをツールチップというそうです。

HTML tooltip plugin
mpld3のツールチッププラグインの例。

python - Incorrect mpld3 plotting in log scale - Stack Overflow
mpld3で散布図の軸スケールに対数を指定するとマーカーの位置がおかしくなります。

Incorrect mpld3 plotting in log scale · Issue #227 · jakevdp/mpld3 · GitHub
上記のバグの修正は難しいようです。

Tick labels & locations · Issue #22 · jakevdp/mpld3
目盛ラベルの変更はmpld3では実装されていないようです。

次の関連記事:linuxBean14.04(81)mpld3で目盛りラベルを変更する

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ