忍者ブログ

Py淡 (PyTan)

Home > ブログ > 記事一覧

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

Google日本語入力とSublime Textの相性が悪い問題が解決!

Sublime Textは開発者がオーストラリア人のJon Skinnerさんで、Gtkをベースにした独自のGUIでできているらしいのでやはり日本語に弱く、日本語IMEを使うと入力中の日本語がカーソルのある位置でインライン表示されずに画面左上あたりに表示されてしまう問題がある。



これはIMESupportという素晴らしいプラグインのお陰でちゃんとした位置に表示されるようになるんだけども、Google日本語入力では”ひらがなモード”から”Direct inputモード”にしてアルファベットを入力しようとすると入力モードの[あ]とか[A]とかのインライン表示が常にカーソルを追いかけて来てしまう。EmEditorなど日本語対応している他のエディタだとIMEの切替時や入力モードの切替時に一度表示されておしまい。

MS-IMEならこの問題はないが、とてもおかしな変換ばかりするので使い物にならない。ATOKは好きでダウンロード販売で買ってずっと使っていたが、インストーラーのファイルがどっかに行ってしまい、再ダウンロードしようとしたら期限切れだそうで、バカバカしい。

普段はプログラミングにアルファベットを入力することの方が多いがデフォルトのIMEを英語に設定しても必ず日本語のDirect inputモードに戻ってしまうので、このインライン表示が非常にうっとおしい。

どうにかならないかとGithub上のIMESupportプラグインのコードを眺めていると割りと短い綺麗なコードでこれならハックできるかもしれないと思い色々やってみたら、二行コメントアウトするだけで見事に問題が解決出来てしまった。詳細はプールリクエストしていますが、imesupportplugin.pyの162行目あたり、上の画像のifのブロックをコメントアウトするだけです。このファイルは通常はC:\Users\ユーザー名\AppData\Roaming\Sublime Text 2\Packages\IMESupportにあるはずです。

Sublime TextのプラグインってPythonなのでとてもハードルが低かった。なんか作ってみたくなった。
PR

np.ones_like, np.zeros_likeでboolアレイの初期化。

覚書です。

array1 = np.zeros((w,h))

なんかであらかじめプリアロケーションしたゼロ行列を作ることはよくありますが、ブーリアンのときはどうやるとスマートなのかと思って調べました。

bool値で満たされた行列の初期化

私の場合、既にあるmyarrayと同じ次元のマスクが欲しい時は

mask = np.ones(myarray.shape, dtype=np.bool) * False

でFalseの部分を必要に応じて変えて急場をしのいでましたが、

どうせmyarray.shapeってやるならnp.ones_likeをつかって

mask = np.ones_like(myarray, dtype=np.bool) * False

と書くべきだし、ones_likeだとTrueの行列になるので

mask = np.zeros_like(myarray, dtype=np.bool)

がスマートな方法っぽい。

boolに限らずもっと一般的な方法としてはあまり使ったことなかったけどnp.full_likeというのがあって、第二引数の値で満たされた行列を作れる。

mask = np.full_like(myarray, Flase, dtype=np.bool)

または

mask = np.full_like(myarray, True, dtype=np.bool)

nanで満たされた行列の初期化


np.full_likeを使うとnanで満たされた行列の初期化がスマートになります。

mask = np.full_like(myarray, np.nan)

でいけます。いままではnp.onesにnp.nanをかけていたけどこっちのほうがスマートですね。

np.emptyはいつ使うのか

np.zerosに似たnp.emptyは初期化しないでメモリだけ確保するので、次元とデータ型は正しいが、確保されたメモリに残っているめちゃめちゃな値の行列ができる。全要素を上書きするのが確定している場合にはいいけど、忘れそうで危険なので使わないことにしている。そこまでパフォーマンスにこだわる状況っていまのところあまりない。

matplotlibの図をBMPとしてクリップボードにコピーする関数作った。

よくデータ解析しているとmatplotlibでfigure(facecolor='w')にしてプロットした図をウィンドウズのSnipping toolでクリップボードにコピーして、パワーポイントに貼って、ノーテーションしたりするわけですが、これが何度も続くと面倒い。

ぐぐってみたらwxのバックエンドではツールバーにクリップボードにコピーするアイコンを追加するハックがあった。残念ながらこのパッチはマージされなかったようで、1.4.2でもクリップボードにコピーできない。

で、やっぱり自分で作る。

matplotlibのデフォルトのバックエンドはいまQt4Aggだと思うのでQtでやるにはどうしたら良いのかなとぐぐってみたら、こんな質問があって、もしウィンドウズならwin32clipboardつかってみたら?という回答があったのでやってみた。

使い方

なんかmatplotlibでプロットしたらこの関数を引数なしでcopy2clipboard()としてやれば現在フォーカスがある図をBMPとしてクリップボードにコピーします。もしくはfigのインスタンスをfig=figure()のようにして取得してからプロットして、copy2clipboard(fig)のように使います。エディターにプロット用のスクリプトがあってなんどもプロットする場合、tight_layout()とかの後にこの関数を置いておくと一手間省けるという感じです。力技ですが、一応つかえます。


bibtexマネージャーを作ってみる。その2:wxPython3.0でwx.lib.agw.auiを使う。

 
作り始めて3日目のスクリーンショット。現在コメントやICONのリソースのバッファ21行を含めて265行。

さて、いろいろな空き時間にコーディングして、とりあえず使えるものが出来ました。

上にあるスクリーン ショットで、authorのところの下矢印はAuthorカラムでの昇順でのソートを示しています。他のカラムをクリックしてタイトルでソートしたり yearでソートしたりできます。listmix.ColumnSorterMixinをつかったので、とっても楽に出来ました。

右クリックメニューから選択中の論文でsublistを作って新しいタブに開いたり、PDFビュワーで一度に開いたりもできます。左端のPDFアイコンはbibtexの'file'タグにあるファイルパスが指定されているもの。

あとは開いたタブを次回起動時に覚えているようにすれば最低限の自分が使えるものは完成です。wxPythonはやっぱり簡単でいいなぁ。

wx.auiとwx.lib.agw.auiの違い

今まではwxPython2.8の安定版をづっと使ってきましたが、最近wxPython3系統が正式にリリースになったのでPython2.7.5とwxPython3.0.0.0で作っています。

bibtexファイルを同時に複数開いた時に、それぞれをタブとして持ちたいので、これには以前カルシウムイメージングのROIドローイングソフトPymagorを作ったときに一度つかったAdvanced User Interface library (AUI)のwx.aui.AuiNotebookを使いました。

AUIは、Advanced User Interface libraryの略で、見た目もスタイリッシュでかっこ良いwxの中のサブライブラリです。

wxPython demoでauiをみてみるとwx.auiではなくってwx.lib.agw.auiを使っている場合が多い。どう違うんだっけと思って調べると、この質問によると
wx.lib.agw.aui is a re-implementation of wx.aui using only Python code.
だそうで、同じ機能+アルファをPython版で提供しているものらしい。基本的にwx.libにあるものは全部Pythonバージョンらしい。
試しにwx.auiで作り始めたアプリをwx.lib.agw.auiに差し替えたところ問題なく動作したので、ちゃんとAPIも互換しているらしいし、+アルファの部分が嬉しい。例えばwx.aui.AuiNotebookにはSetRenamableというメソッドがないが、agwの方にはこれがあるので、タブの名前をがダブルクリックで変えられるようにするのが一行でできてしまった。

wx.lib.agw.auiのAGWとはAdvanced Generic Widgetsのことで、AUIを含めていろいろなちょっと高度なウィジェットが提供されています。APIがwxPythonのバージョン3系(Phenix)のDocにあったのでメモ。見つけるの大変だったが、これで安心してwx.auiから乗り換えられそう。。wxPython3も今のところまったく問題がないです。

bibtexマネージャーを作ってみる。その1:BibtexParserを使う。


JabRefやCiteulikeを長く使ってきましたが、以下の機能が欲しいのでCiteulikeを補完するツールとして自分用bibtexマネージャーを作ってみようと思います。


欲しい機能

  • シンプルなJabRefのインターフェイスっぽいもの。
  • タブグループマネージャー機能。Bib managerから、いくつかの関連する文献をまとめて複数のタブとしてPDF Viewerで開いたり、グループを切り替えたりしたい。
  • ポータブルなアプリでDropboxに入れて置けると一番良い。
  • JabRefみたいに選択した論文をいろいろな雑誌のReferenceのフォーマットでワードに貼ればいいだけなリッチテキスト形式として出力したい。Citeulikeでは有料オプション。
  • bibtexのインポートをサポート(当たり前)
  • フリー


まずはすでに条件を満たすPythonでできたツールがないかググる。Pythonを使ったものはコマンドラインツールばっかり見つかる。

biblio-py

yapbib: Yet Another Python BIBliography manager toolというコマンドラインツールがメインプログラム。bibextract.pyではLaTex中で引用した論文のリストとか得られるようだ。

BibtexManager-Python

https://github.com/MasterOdin/BibtexManager-Python
コマンドラインツール。bibtextエントリーをPretty printする感じ。


BibReview

https://pypi.python.org/pypi/BibReview


やっと見つかったGtKアプリ。JabRefのインターフェイスとはかなり違う感じ。

Pybliographer



http://pybliographer.org/Welcome

GNOMEがターゲットのようなのでLinuxオンリーか。Windowsに移植するのもつらそう。見た目は好きなんだけど。



結局なさそうなので自分で作る。

計画としては、


新しい論文を見つけた時はすでにウェブブラウザを開いてそのページを開いているわけで、これをCiteulikeに追加するまではCiteulikeのarticleインポーターが秀逸なので、これを使う。

ただし、Citeulikeのインターフェイスはカスタマイズに限界があり自分好みにはできなかったので、JabRefっぽい使い勝手のフロントエンドGUIを慣れたwxPythonでサクッと最低限必要なものだけ作る。

やはり自分の好きなPDFビュワーで論文を開いて、蛍光ペンツールを使ったりしたいのが、ウェブアプリケーションだと読みたい論文のPDFをPDFビュワーで開く部分が難しい。あとは孫引きしたりされたりしている関連する論文も一緒に開く場合が多いので、これをグループにして登録し、まとめて開いたりしたい。ここまではやればできる。

欲を言えば、このグループの論文に対しての著者が同じとか、孫引きされているとかキーワードの相関が高いとかから関連性の順位を決定し、これでLibraryをソートできたりすると素晴らしい。Citeulike上のライブラリが大きくなってくるとすでに登録してある論文を見つけるのに苦労するので、この辺をできるようにするのが最大のモチベーション。

CiteulikeからBibTexを手動できれば自動でライブラリをインポートしてCiteulikeのフロントエンドとして使いたい。bibtexの読み込みはいろいろライブラリがあるので、いいのを選ぶ。


BibtexParser

https://bibtexparser.readthedocs.org/en/latest/

これをつかってJabRefやCiteulikeからインポートする計画。

pip install bibtexparser

Pure pythonモジュールっぽいし、pipでインストール。


チュートリアルを読むとbibtextの読み込みは簡単で、

import bibtexparser
with open('bibtex.bib') as bibtex_file:
    bib_database = bibtexparser.load(bibtex_file)

このbib_databaseオブジェクトをdumpしてbibtexファイルにエクスポートも簡単。

bibtex_str = bibtexparser.dumps(bib_database)

bib_databaseクラスのメソッドをみてみるとentriesで各論文エントリーのメタデータがdictになった要素をもつリストとして格納されているようだ。

しかし、エントリーをデータベースに追加したり削除、マージするAPIが用意されていない上、最終的にエクスポートするにはbib_databaseオブジェクトが必要なので編集できないのは困った。

しょうが無いのでbibdatabaseクラスを定義しているソースを覗き見するとクラスはえらく単純。

newBibDb = bibtexparser.bibdatabase.BibDatabase()

newBibDb.entries = sublist

という感じで、自分でエントリー追加・削除したリスト(sublist)をつくって、新しくインスタンス化したbibdetabaseクラスオブジェクトのself.entriesを上書きしてやればいいと見通しがついた。これでdumpでエクスポートできるはず。

この質問をみるとpybtexというライブラリもあって、こっちでは一応追加・削除とかできそうだが、http://pybtex.sourceforge.net/の方のドキュメンテーションが未完成かつ古いのでメンテイナーがどっか入ってしまったパターンかもしれないので、ドキュメンテーションがかっこいいbibtexparserで頑張ることにする。


ランチャー部分の実装


subprocessモジュールを使って簡単にグループタブを開く部分を実装してみる。

import subprocess
from time import sleep

def PDFopen(files, 
            libraryPath = 'C:\\Dropbox\\PathToYour\\PDFs'
            execPath = r'C:\Path2\PDF-XChangeViewerPortable.exe'
            ):
    
    if type(files) is not list:
        raise ValueError('The first arg should be a list containing more than one file path')
        return

    P = subprocess.Popen([execPath, files[0]])
    sleep(2) # wait until the instance is ready for more files

    for pdf in files[1:]:
        P = subprocess.Popen([execPath, pdf])


if __name__ == '__main__':

    files = [
    'Einstein1997.pdf',
    'Heisenberg2005.pdf',
    'Kandel2009.pdf',
    'Galileo1662.pdf',
    ]
    PDFopen(files, libraryPath)
こんなのでとりあえずやりたいことができた。ぶっちゃけこれだけあれば十分・・・。
さて、あとはGUIなので次回はwxPythonの話。