mathjax

2013年9月17日火曜日

Windows環境における、Pythonインストール環境の現状認識

Windows環境における、Pythonインストール環境の現状認識

Pythonを科学分野で使うには、様々なサードパーティのパッケージが必要となります。これらを一つ一つ探してインストールするのは面倒ですが、幸いな事にまとめて簡単にインストール、アップデートすることができるフリーの環境が幾つも公開されています。(以上、9/19 追記)
個人的に試用してみての意見を記録しておきます。おそらく半年も経てば違う意見になると思います。そのくらい、各ソフトの開発が高速で進んでいるからです。

  • Windows32bit or 64bit?: 今や販売されているほとんどのPCは64bitシステムだろうと思います。私自身はまだ32bitを使っています。32bitではPythonXYというインストールパッケージが使えます。少数かもしれませんが、32bitの人はこれでも良いかもしれません。ただし、ipythonのバージョンが未だに古いので、私は今は使っていません。pipを用いれば、アップグレードは簡単ですが、多数の64bitの人達と異なる環境になることを避けたいという意図もあります。
  • Python2.7 or 3.3?: 現状での3.3の問題点は、Spyderがまだ対応していないという事です。Experimental Releaseというのが出ていますが、まだ安定版ではありません。Windows環境においては、長いスクリプトを書く場合にはSpyderが一番使いやすい開発環境だと感じているので、この一点で2.7を勧めたいと思います。もし、Spyderのpython3.3対応の安定版がなかなか出ないのなら、他の開発環境を模索する必要があると思います。その場合にはIpython Notebookもその候補に入るでしょう。
  • Winpython or Anaconda?: Winpythonはpython2.7版、3.3版を独立に出していますが、Anacondaはpython2.7をインストールした後にpython3.3を追加する必要があります。(しかし、Spyderの3.3対応版が出る頃に前後して、3.3を最初からインストール可能なAnacondaのバージョンが公開される可能性もあります。)WinpythonのメリットはWindows環境に特化しているので、使い方がWindowsユーザにわかりやすい事、また、Ipython、IDLE、IpythonNotebook、SpyderなどがExeファイルやBatファイルとしてインストールされることがあります。また、Anacondaの環境ではSpyderの動作に多少の問題があるようです。Anacondaの方が様々なシステムに対応しているためか、Web上に情報が多い気がしますので、Anacondaの更なるバージョンアップを期待しつつ、現状ではWinpythonの方がわずかに便利な気がしています。
  • Winpythonのpython2.7版ではipython1.1(最新版)がインストールされませんが、Winpython Control Panelを用いれば、アップグレードしてくれます。ダウンロードサイトから ipython-1.1.0.tar.gz をダウンロードして、ドラッグアンドドロップする必要があります。また、登録と拡張子(.py)に対する既定のプログラム(python.exe)の設定、環境変数Pathにインストールディレクトリ内のipython.exeがあるディレクトリ(例えば、C:\WinPython-32bit-2.7.5.3\python-2.7.5\Scripts)を追加することをお勧めします。Ipython Notebook.exeのあるディレクトリ(例えば、C:\WinPython-32bit-2.7.5.3)はPathに設定しません。理由は次に述べます。
  • Winpythonは元々がインストールフォルダの内部だけで読み書きを完結しようとするプロジェクトです。その為か、インストールフォルダにある"Ipython Notebook.exe"はデフォルトのディレクトリがカレントディレクトリではなくてC:\WinPython-32bit-2.7.5.3\python-2.7.5\Scriptsというような場所に設定されてしまいます。通常の用途ではこれは却って不便なので、C:\WinPython-32bit-2.7.5.3\python-2.7.5\Scriptsのipython.exeを使用します。いずれにせよ、ipython notebookと打ち込めばipython notebookが起動する事には変わりません。ipython.exeはnbconvertやprofile createでも必要になります。
  • 少し話題がそれますが、Python2.7と3.3の一番身近で大きな違いはprint文の有無です。3.3ではprintは単なる関数なので、print()とする必要があります。近々python3.3に移行する事を考慮し、先頭にfrom __future__ import print_functionを入れておく事をお勧めします。

2013年9月10日火曜日

PEOPLE_2: 質点のクラス(part 1)

PEOPLE_2: 質点のクラス(part 1)

ソースファイル

前回、質点を「質量を持ち、その存在位置以外に自由度を持たない物体」と定義した。 今回からは、この定義をPythonのクラスとして表現する事を試みる。

「質量を持ち」について。

普通は、ある一定の質量を持ち、という意味である。つまり、これは質点の自由度ではなく、個々の質点に固有の値である。

この事を考慮した質点クラスの定義を行う。それにはプロパティを用いるのが良い。

質点クラスの定義

In [1]:
class PointMass(object):
    def __init__(self,sitsuryo=1.0):
        self.__mass=sitsuryo
    @property
    def mass(self):
        return self.__mass

クラス定義の解説

クラスの定義の仕方は、上記の様に

class クラス名(継承する元のクラス):

とする。この時、既存のクラスの定義を引き継いで再利用する場合には括弧内に引き継ぐ(継承する)元のクラス名を書くのだが、今回は特に無い。 その場合、括弧内にはobjectという最も基本となるクラスを継承する。

また、

@property

はデコレータと呼ばれる文で、これによって、直後の関数定義がこのクラスに属するオブジェクトのプロパティと呼ばれる変数になる。

今回の場合、直後に

def mass()

によってmassという関数が定義されているが、これは実際にはPointMassというクラスのmassというプロパティを定義している事になる。

オブジェクト指向プログラミングを知らない人の為に、 クラスの使用方法と、プロパティの使用例を以下に示す。

質点オブジェクトの生成

In [2]:
pm1=PointMass()
pm2=PointMass(2.0)

解説

pm1=PointMass()

これで、pm1という名前を持ち、PointMassというクラスに属するオブジェクトが作られる。具体的には、PointMassの定義の中にある、

__init__(self,sitsuryo=1.0)

が実行される。その際、sitsuryoという引数には1.0というデフォルトの数値が代入される。

pm2=PointMass(2.0)

こちらの方が一般的な方法で、この場合にはsitsuryo=2.0という数値を用いて、__init__()が実行される。

selfというのは、オブジェクト自身を表す引数で、__init__()の中身を見ると、

self.__mass=sitsuryo

とあるが、これは例えば、pm1というオブジェクトに__massという変数が定義され、そこに先ほどのsitsuryoという引数を代入せよという意味になる。

その後、この__massという値はpm1のプロパティであるmassという変数の呼び出し命令によって呼び出される事になる。

つまり、外部からみると、pm1はmassというプロパティを持っているが、内部では__massという名前の変数として扱っている。

その様子を以下で見てみる。

質量の読み出し(呼び出し)

In [3]:
print pm1.mass
print pm2.mass
1.0
2.0

In [4]:
print pm1.__mass
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-947959c917a9> in <module>()
----> 1 print pm1.__mass

AttributeError: 'PointMass' object has no attribute '__mass'

PointMassというクラスのオブジェクトは__massという変数を持っていない

というエラーメッセージが出るはずである。

* (「__massという変数にはアクセスできない」というメッセージでないのは一見不思議だが、pythonでは他の多くのプログラミング言語とは異なり、オブジェクト変数に対する本当の意味でのアクセス制限は行わない。その代わりに、オブジェクト変数の名前を自動的に複雑化する事でアクセスを難しくしている。 この手法を Name Manglingと呼んでいる。) *

このように、外部からは__massという変数は見えない。

また、sitsuryoという変数も見えない。 こちらは__init__という関数の内部でのみ使われているローカルな変数で、オブジェクトの変数ですらない。

In [5]:
pm1.sitsuryo
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-5-cf74258e4a57> in <module>()
----> 1 pm1.sitsuryo

AttributeError: 'PointMass' object has no attribute 'sitsuryo'

質量の不変性

質量の変更を試みる。

In [6]:
pm1.mass=3.0
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-6-9b92080ef8e1> in <module>()
----> 1 pm1.mass=3.0

AttributeError: can't set attribute

変更はできない。これによって、質点の質量は不変ということになる。

次に、質量というプロパティそのものを消してみる。

In [7]:
del pm1.mass
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-8c8d28d11d94> in <module>()
----> 1 del pm1.mass

AttributeError: can't delete attribute

これによって、質量を持たない質点は存在できない。

個々の質点そのものなら消すことができる。

In [8]:
del pm1

まとめ

プロパティというのはオブジェクトが持っている変数の一種だが、そのアクセス方法はクラス定義の内部の関数によって定義されている。 今回の場合、massというプロパティは読み出す(呼び出す)方法だけを定義したので、設定(つまり値を変更)したり、削除したりすることは出来ない。

このような性質は一定の質量を持つ質点の定義方法として適切であろう。

2013年9月5日木曜日

Ipython Notebookを簡単に立ち上げる

Ipython Notebookを簡単に立ち上げる

初期設定をすることにより、

ipython notebook

と打ち込むだけでpylabなどの設定が済んだ状態でダッシュボードが立ち上がります。
しかし、16文字を打ち込むのは面倒。コマンドプロンプトを立ち上げたり、ディレクトリを移動したり、バッチファイルをディレクトリ毎に書いたりというのも面倒」という方(私)のために、簡単なスクリプトを書いてみました。

Pythonはこういう用途、つまり日常的なPC周りのルーチンの省力化にも使えるという例として見てもらっても良いと思います。

Windows向けに作りましたので、よろしければ使ってみてください。
utf-8に対応したテキストエディタかpython用のエディタ(spyder, IDLEなど)を利用すると良いと思います。


ノートブックファイル(*.ipynb)をドラッグアンドドロップすると、そのファイルが立ち上がります。
違う拡張子のファイルをドロップすると、そのディレクトリに移動してからダッシュボードが立ち上がります。
ただ、ダブルクリックすると、デフォルトディレクトリでダッシュボードが立ち上がります。
デフォルトディレクトリがNoneなら、このスクリプトが置かれたディレクトリに移動してダッシュボードが立ち上がります。

適宜、使いやすいように書き直して下さい。

Windowsのパイソンファイル(*.py)のアイコンがドラッグアンドドロップに使えるかどうかについては、あまりネット上では見つからないのですが、少なくとも私の環境ではOKでした。

かつては、バッチファイルを介する必要があったようです。

参考サイト:http://tuchinoko.moe-nifty.com/oboegaki/2004/12/_python_.html

# -*- coding: utf-8 -*-
"""
Created on Thu Sep 05 13:31:30 2013

@author: mk

script name: ipynb_starter.py

Drag and drop ipython notebook starting script.

Double click will start ipython notebook dashboard.
The directory can be set as the default_directory below.
If not set, the folder at which this script file placed will be used.

If a notebook file(*.ipynb) is dropped, change directory and start the notebook.
If the dropped file is not .ipynb, change directory and start the dashboard.

So, you can put this script on the Desktop folder or any other easy-access folder.

"""
#default_directory=None
default_directory='C:\Users\mk\Documents\Python'#ここにデフォルトディレクトリを書く
import sys

argvs = sys.argv
argc = len(argvs)
print argvs
print argc

import os
import os.path

if argc>1:
    os.chdir(os.path.dirname(argvs[1]))
    print os.path.dirname(argvs[1])
    if os.path.splitext(argvs[1])[1]=='.ipynb':
        s='ipython notebook '+os.path.basename(argvs[1])
    else:
        s='ipython notebook '
else:
    if default_directory==None:
        os.chdir(os.path.dirname(argvs[0]))
    else:
        os.chdir(default_directory)      
    print('no file is dropped')
    s='ipython notebook '

print(os.getcwd())
print s  
import subprocess
subprocess.Popen(s)

2013年9月4日水曜日

Gifアニメーション

 Gifアニメーション

ソースファイル
最新のmatplotlib(1.3.0)ではanimationにImagemagickという画像変換ソフトが使え、gifアニメが作れます。 このソフトはpythonのライブラリでは無くて、外部アプリケーションなので、別途インストールする必要がありますが、 便利でメジャーなソフトなので、入れておいて良いと思います。
Gifアニメはコマ送りのアニメなので、粗い時間間隔で計算された物理状態変化を見せたい場合に向いていると思います。 また、markdown上にもhtmlにも画像として貼れるので、扱いが容易です。
ただし、Windowsでは注意点があります。 Imagemagickのconvert.exeというのを内部で利用するのですが、windowsのシステム内にある別のconvertというコマンドと間違える恐れがあります。
参考サイト:http://stackoverflow.com/questions/3060205/error-invalid-parameter-fom-imagemagick-convert-on-windows
そこで、Imagemagickをインストールしたディレクトリをmatplotlibrc(matplotlibの設定ファイル)に登録しておく必要があります。
ユーザーの
.matplotlib\matplotlibrc
をテキストエディタで開いて、最後の行に
animation.convert_path: C:\Program Files\ImageMagick-6.8.6-Q16\convert
などと適切なディレクトリ名とコマンド名を入れておきましょう。
In [1]:
%matplotlib qt
通常、アニメーションは外部Window上で見ますので、上記のようにします。
In [2]:
from matplotlib import animation

# Set up the axes, making sure the axis ratio is equal
plt.figure(figsize=(5,3))
line,=plt.plot(0,0,'ko')
title=plt.title('')
plt.xlabel('x(m)')
plt.ylabel('y(m)')
plt.xlim(0,30)
plt.ylim(0,12)
plt.grid()
fig=plt.gcf()
ax=plt.gca()
ax.set_aspect('equal')

# This function moves the polygons as a function of the frame i
Nframes = 600
def animate(nframe):
    time=(nframe%60)*50.0e-3
    v=16.0
    g=9.8
    theta=20.0+(nframe/60)*5
    vx=v*np.cos(theta*np.pi/180.0)
    vy=v*np.sin(theta*np.pi/180.0)
    line.set_data(vx*time,vy*time-0.5*g*time**2)
    title.set_text(u'投げ上げ角度:'+str(theta)+u'度')
    return line,title
    
anim = animation.FuncAnimation(plt.gcf(), animate,
                               frames=Nframes, interval=50)
qtウィンドウ上でアニメーションが見えていると思います。 これを残したままでも、閉じてしまってもよいので、以下のコマンドを実行すれば、gifアニメーションが出来上がります。
In [6]:
anim.save('throw_up.gif',fps=20, writer='imagemagick')
これを
![image](files/throw_up.gif)
などとして、markdownセルに貼り付ければ、以下のようになります。
これを一般的な動画形式と比べてみましょう。
In [8]:
FFMpegWriter = animation.writers['ffmpeg']
metadata = dict(title='Movie Test', artist='Matplotlib',
        comment='Movie support!')
writer = FFMpegWriter(fps=15, metadata=metadata)
with writer.saving(fig, "writer_test.mp4", 100):
    for i in range(Nframes):
        animate(i)
        writer.grab_frame()
以上のようにすると、mp4という形式の動画ファイルができますが、これはノートブック上に貼り付ける事はできません。 以下のサイトを見ると、何とかできるのかも知れませんが、私にはまだ理解できていません。
参考サイト: http://jakevdp.github.io/blog/2013/05/12/embedding-matplotlib-animations/
youtubeに投稿すれば、貼りこめるようですが、ローカルに置けないのは不便ですね。 Bloggerでは動画として貼り込めますので、比較することができます。 mp4の方がサイズは小さいようですので、多数や長時間のアニメーションを公開する場合にはこちらの方が良いのかも知れません





2013年9月2日月曜日

初期設定の仕方

初期設定の仕方

ソースファイル

初期設定の仕方については、 別ページ でも少し触れました。

今回は、現時点でお勧めの初期設定内容の紹介を含めて、改めて述べておきます。

まずは、

In [1]:
import IPython
from IPython.utils.path import get_ipython_dir
IPython.utils.path.get_ipython_dir()
Out[1]:
u'C:\\Users\\mk\\.ipython'

上記のコマンドで設定(profile)が置かれるフォルダが分かります。 その中身を見てみましょう。

In [2]:
!dir C:\Users\mk\.ipython
 ドライブ C のボリューム ラベルがありません。
 ボリューム シリアル番号は 4655-D599 です

 C:\Users\mk\.ipython のディレクトリ

2013/09/02  16:51    <DIR>          .
2013/09/02  16:51    <DIR>          ..
2013/09/02  16:51    <DIR>          profile_default
2013/05/20  14:12               100 README
               1 個のファイル                 100 バイト
               3 個のディレクトリ  669,010,583,552 バイトの空き領域

デフォルトのプロファイルを置くフォルダ(profile_default)が見つかりましたので、その中を更に見てみましょう。

In [3]:
!dir C:\Users\mk\.ipython\profile_default
 ドライブ C のボリューム ラベルがありません。
 ボリューム シリアル番号は 4655-D599 です

 C:\Users\mk\.ipython\profile_default のディレクトリ

2013/09/02  16:51    <DIR>          .
2013/09/02  16:51    <DIR>          ..
2013/09/02  16:51    <DIR>          db
2013/09/02  16:51             7,168 history.sqlite
2013/09/02  16:51             3,608 history.sqlite-journal
2013/09/02  16:51    <DIR>          log
2013/09/02  16:51    <DIR>          pid
2013/09/02  16:51    <DIR>          security
2013/09/02  16:51    <DIR>          startup
               2 個のファイル              10,776 バイト
               7 個のディレクトリ  669,010,587,648 バイトの空き領域

いままでプロファイルを作ったことが無い方は上記のようにipython_notebook_config.pyが見当たりません。 そうでない方も、古いバージョンを使っていて、過去の設定を捨ててしまっても良い方は、profile_defaultというフォルダを消して下さい。 重要で覚えていないような設定をなさっている方はバックアップをとってください。

そして、以下のコマンドでデフォルト設定を作り直します。

In [4]:
!ipython profile create
[ProfileCreate] WARNING | Generating default config file: u'C:\\Users\\mk\\.ipython\\profile_default\\ipython_config.py'
[ProfileCreate] WARNING | Generating default config file: u'C:\\Users\\mk\\.ipython\\profile_default\\ipython_qtconsole_config.py'
[ProfileCreate] WARNING | Generating default config file: u'C:\\Users\\mk\\.ipython\\profile_default\\ipython_notebook_config.py'

もし、デフォルトでない設定を追加したい方は、
!ipython profile create custom

などとするとよいでしょう。

In [5]:
!dir C:\Users\mk\.ipython\profile_default
 ドライブ C のボリューム ラベルがありません。
 ボリューム シリアル番号は 4655-D599 です

 C:\Users\mk\.ipython\profile_default のディレクトリ

2013/09/02  16:51    <DIR>          .
2013/09/02  16:51    <DIR>          ..
2013/09/02  16:51    <DIR>          db
2013/09/02  16:51             7,168 history.sqlite
2013/09/02  16:51                 0 history.sqlite-journal
2013/09/02  16:51            19,000 ipython_config.py
2013/09/02  16:51            23,386 ipython_notebook_config.py
2013/09/02  16:51            23,903 ipython_qtconsole_config.py
2013/09/02  16:51    <DIR>          log
2013/09/02  16:51    <DIR>          pid
2013/09/02  16:51    <DIR>          security
2013/09/02  16:51    <DIR>          startup
               5 個のファイル              73,457 バイト
               7 個のディレクトリ  669,010,518,016 バイトの空き領域

今度はipython_notebook_config.pyが見つかります。これがnotebook用の設定ファイルです。 この中身を見てみましょう。

In [6]:
f=open( u'C:\\Users\\mk\\.ipython\\profile_default\\ipython_notebook_config.py','r')
lines=f.readlines()# ファイル全体を1行ずつリストにして取り出す。
for line in lines:#各行に対して
    if line[0]!='#' and line[0]!='\n':
        # 先頭が#や改行コードだったら表示しない。
        print line[:-1]
c = get_config()

上記ファイルは実質的に一行しかなく、あとはコメント行です。 このファイルをテキストエディタで開き、一部のコメントを外して書き直すか、若しくは以下のように上書きします。

In [7]:
%%file C:\\Users\\mk\\.ipython\\profile_default\\ipython_notebook_config.py
# Configuration file for ipython-notebook.

c = get_config()
c.IPKernelApp.pylab = 'inline'
c.IPKernelApp.pylab_import_all = False
c.InlineBackend.figure_format = 'svg'
Overwriting C:\\Users\\mk\\.ipython\\profile_default\\ipython_notebook_config.py

以上のようにすれば、後は任意のフォルダからipython notebookとやればそのフォルダを保存フォルダとするダッシュボードと呼ばれるipython notebookのページが立ち上がります。ここから既存のノートブックを立ち上げたり、ここを保存フォルダとする新規ノートを作ることができます。

デフォルト以外のプロファイル(例えばcustom)を作って、そこから起動させたい場合には

ipython notebook --profile custom

と打ち込んで起動させます。

参考サイト

プロファイルの設定全般について:http://ipython.org/ipython-doc/stable/config/overview.html#profiles

c.IPKernelApp.pylab = 'inline'について: http://comments.gmane.org/gmane.comp.python.ipython.user/10610

c.IPKernelApp.pylab_import_allについて:http://ipythonnb4jpnexp.blogspot.jp/2013/08/pylab-ipython1.html

c.InlineBackend.figure_format = 'svg'について:http://ipythonnb4jpnexp.blogspot.jp/2013/08/svg-ipython-notebookmatplotlibpng-plt.html

2013年8月30日金曜日

reStructuredText からmarkdownへの変換

reStructuredText からmarkdownへの変換

ソースファイル
前回、ノートブックファイルをreStructured text(rst)に変換することによって、画像ファイルが取り出せるという事を書きました。 その際、画像ファイルの対応箇所を見つけるのに、rstファイルをテキストエディタで開く必要がありました。
その続編として、rstがmarkdownに変換できる事が分かりましたので、紹介しておきます。(コメントを追加しましたので、参照下さい。)
ノートブックを他の形式に変換するnbconvertでは内部でpandocというソフトを使っているのですが、これにはパイソン版(正確には薄いラッパーと呼ぶそうです)があります。 これをpipなどを使ってインストールしておきます。 すると以下のように簡単なコマンドでmarkdown(md)に変換できました。
In [1]:
import pypandoc
output = pypandoc.convert('SVG2PNG.rst', 'md')
ただ、残念ながらそのままではノートブックでは読めませんでした。画像ファイルへのリンクの仕方が微妙に違うようです。
詳細は不明なのですが。
参考サイト
ともかくも、"files/"というのを付ければよさそうなので、以下のコマンドを書きました。 正規表現というモジュール(re)を用いて、該当箇所を書き換えます。
今回は、svgファイルだけに関心があるので、そこだけを書き換えますが、pngファイルも同様に可能です。
また、画像ファイルへのリンクの手前に次の画像はこういうファイル名だよ、と注釈を挿入しました。
In [2]:
import re
output2=re.sub(r'(!\[image\]\()(.+\.(svg|SVG)\))',r'</br><FONT color="red">(the next image is \2</br>\n\n\1files/\2</FONT> ',output)
#output2=re.sub(r'(!\[image\]\()(.+\.(png|svg|PNG|SVG)\))',r'**(the next image is \2**\n\n\1files/\2 ',output)
#pngを含める場合は上記のようにする。
出来上がった文字列(output2)をmarkdownセルに書き込めば良いのですが、簡単な方法が見つからなかったので、以下のように一旦ファイルに落としてから、読み出しました。
In [3]:
f = open('tmp.md', 'w') # 書き込みモードで開く
f.write(output2) # 引数の文字列をファイルに書き込む
f.close()
%load tmp.md
(以下、一部抜粋)
In[6]: .. code:: python
x=np.linspace(0,2*np.pi) plt.plot(x,np.sin(x)) plt.figure()
plt.plot(x,np.cos(x))
(the next image is SVG2PNG_files2PNG_8_1.svg)

(the next image is SVG2PNG_files2PNG_8_2.svg)



(以上、抜粋終わり)

まとめ

上のセルはcodeセルとして出力されますので、手動でMarkdownセルに変更しました。 また、長いので、SVGファイルがある周辺だけを抜粋しました。 このようにすれば、画像ファイルとノートブックとの対応は見やすいと思います。

なお、ブログに貼り付けるためにこのノートはnbconvertでhtmlに変換していますが、その際にローカルなSVGとのリンクは切れてしまっているので、代わりにPNGファイルを貼り込んであります。

nbconvertが改良されれば、nbconvertで変換したmarkdownで済む話なのかも知れませんが、参考まで。

2013年8月29日木曜日

SVGファイルの利用

SVGファイルの利用

ソースファイル

Ipython Notebook内にMatplotlibで描画されるグラフは、標準ではpngと呼ばれる、ビットマップイメージです。 この形式はブラウザ上に表示するには適していますが、そのままの設定で印刷物にすると解像度が十分ではありません。

plt.savefig()というコマンドで実行時に高解像度の画像ファイルに変換する事は可能で、 恐らく、それが一般的な使用方法として想定されているものと思います。 しかし、この方法だと画像保存のために演算を初めからしなおして、必要な箇所にplt.savefig()を追加していく必要があります。 計算時間が掛かる場合など、このようなやり方を避けたい場合もあると思います。

その解決方法には2つあると思います。 一つ目は、初めから高解像度のpngファイルにするという方法です。 これは、ipython notebook用のmatplotlibの設定を変える必要があります。

そのために、今回はipython notebookをpylabの引数無しで起動しています。

Matplotlibの設定を変えるには、pylabの実行前に以下のようなコマンドを実行する必要があります。

In [1]:
%config InlineBackend.rc = {'font.size': 20, 'figure.figsize': (12.0, 8.0),'figure.facecolor': 'white', 'savefig.dpi': 72, 'figure.subplot.bottom': 0.125, 'figure.edgecolor': 'white'}
In [2]:
%pylab inline
Populating the interactive namespace from numpy and matplotlib

In [3]:
x=np.linspace(0,2*np.pi)
plt.plot(x,np.sin(x))
plt.figure()
plt.plot(x,np.cos(x))
Out[3]:
[<matplotlib.lines.Line2D at 0x3fda830>]

デフォルトの設定(私の場合にはC:.ipythondefaultnotebook_config.py)の値と比べて、'font.size'と 'figure.figsize'を大きくしました。 ところが、こうすると線が細すぎます。 つまり、このようなやり方だと折角Matplotlibにおいて、グラフを綺麗に見せるために設定されている様々な初期設定を、色々と変えなければならなくなる可能性があります。

また、ブラウザで見る際には見た目が大きすぎます。

2つ目の方法は画像形式をSVGに変える事で、これが本命です。

In [4]:
%config InlineBackend.rc = {'font.size': 10, 'figure.figsize': (6.0, 4.0),'figure.facecolor': 'white', 'savefig.dpi': 72, 'figure.subplot.bottom': 0.125, 'figure.edgecolor': 'white'}

まずは設定を戻しておきます。

In [5]:
%config InlineBackend.figure_format = 'svg'
%pylab inline
Populating the interactive namespace from numpy and matplotlib

In [6]:
x=np.linspace(0,2*np.pi)
plt.plot(x,np.sin(x))
plt.figure()
plt.plot(x,np.cos(x))
Out[6]:
[<matplotlib.lines.Line2D at 0x40c4ed0>]

この方法だと、ブラウザ上で大きく表示されていませんが、全体の表示を拡大(「ctrl」+「+」)すると解像度が高い事が分かります。 ベクターグラフィックなので、当然ですが。

この埋め込まれたSVGファイルを取り出す方法として二つの方法を紹介します。

一つはInternetExplorer(IE)を用いる方法です。 ノートブックファイル(".ipynb")やnbconvertで作成したhtmlファイルをIEで開き、SVGファイルの上でマウスを右クリックすれば、svgファイルで保存することが出来ます。 その際、pngファイルやbitmapファイルでも保存できますが、高い解像度の画像にはなりませんでした。 一つのノートブックから数個のグラフを保存するにはこの方法が良いでしょう。

二つ目は、nbconvertを用いる方法です。nbconvertでrst(reStructured Text)というファイル形式にすると、画像ファイルは別フォルダに保存されます。

In [7]:
!ipython nbconvert --to rst SVG2PNG
[NbConvertApp] Using existing profile dir: u'C:\\Users\\mk\\.ipython\\profile_default'
[NbConvertApp] Converting notebook SVG2PNG.ipynb to rst
[NbConvertApp] Support files will be in SVG2PNG_files\
[NbConvertApp] Loaded template rst.tpl
[NbConvertApp] Making directory SVG2PNG_files
[NbConvertApp] Writing 7211 bytes to SVG2PNG.rst

その際、画像ファイルのファイル名には自動的に番号が振られますので、どのファイルがどのグラフに対応しているのかがすぐには分かりません。

In [8]:
!dir SVG2PNG_files\*.SVG
 ドライブ C のボリューム ラベルがありません。
 ボリューム シリアル番号は 4655-D599 です

 C:\Users\mk\Documents\Python\ipython_notebook\SVG2PNG_files のディレクトリ

2013/08/30  13:04            16,980 SVG2PNG_8_1.svg
2013/08/30  13:04            16,981 SVG2PNG_8_2.svg
               2 個のファイル              33,961 バイト
               0 個のディレクトリ  669,050,675,200 バイトの空き領域

似たようなグラフがある場合には出来上がった".rst"という拡張子のファイルをエディタで開いてみて下さい。 rstはipython notebookで採用されているmarkdownと似たような軽量マークアップ言語なので、エディタでみればノートブックとの対応は完全につくはずです。

nbconvertはmarkdownにも変換できるとされているのですが、なぜか私が変換すると、画像ファイルへのリンクが出来ませんでした。 まだバグがあるのだと思います。 markdownへの変換が出来れば、IpythonNotebookに貼り付ける事で対応がより分かりやすくなるのですが。。

SVGからPNGへの変換

さて、出来上がったSVGファイルを高解像度のPNGファイルにしたいという方も多いと思います。 SVGというのは国際標準に基づいた形式なのですが、現実には対応ソフトが少ないのです。 PNGへの変換ソフトとして、Inkscapeを紹介します。 これはWindowsでも簡単に動作するオープンソースのソフトです。 このソフトはSVGのファイルを作成、編集するのが本来の目的なのですが、ファイル変換ソフトとしても使えます。

InkscapeはPythonのソフトではないのですが、コマンドラインからGUI無しでファイル変換を実行できます。 そこでsubprocessというpythonモジュールを用いて、ipython notebook上から実行してみましょう。

まずは、変換するファイルの入ったフォルダを指定します。

In [9]:
def get_directory():
    import Tkinter
    import tkFileDialog
    import tkMessageBox
    root=Tkinter.Tk()
    root.withdraw()
    tkMessageBox.showinfo('showinfo','ディレクトリ名を取得します。')
    dirname=tkFileDialog.askdirectory()
    return dirname
image_folder=get_directory()
print image_folder
C:/Users/mk/Documents/Python/ipython_notebook/SVG2PNG_files

フォルダ内のsvgファイル名を取得します。

In [10]:
import glob
import os.path
filenames = glob.glob(image_folder+'/*.svg')
filenames_without_ext=[] 
for filename in filenames:
    #print file
    root, ext = os.path.splitext(filename)
    #print root
    filenames_without_ext.append(root)
for filename in filenames_without_ext:
    print filename
C:/Users/mk/Documents/Python/ipython_notebook/SVG2PNG_files\SVG2PNG_8_1
C:/Users/mk/Documents/Python/ipython_notebook/SVG2PNG_files\SVG2PNG_8_2

Inkscapeをsubprocessで動かして、SVGファイルをPNGファイルに変換します。この段階で解像度を選択できます。

In [11]:
import subprocess
for file in filenames_without_ext:
    args= '"c:\Program Files\Inkscape\Inkscape.com" -z -e ' +file+'.png '+ '-w 1024 '+file+'.svg '
    #上の-w 1024の数字で横幅のピクセル数が決まる。
    #-h 600 などと縦のピクセル数で指定することも可能。
    p=subprocess.Popen(args,stdout=subprocess.PIPE)
    for i in p.stdout.read().split('\n'):
        print i
    if p.wait()==0:
        print u"変換成功!"
Background RRGGBBAA: ffffff00

Area 0:0:472.5:315 exported to 1024 x 683 pixels (195.048 dpi)

Bitmap saved as: C:/Users/mk/Documents/Python/ipython_notebook/SVG2PNG_files\SVG2PNG_8_1.png


変換成功!
Background RRGGBBAA: ffffff00

Area 0:0:472.5:315 exported to 1024 x 683 pixels (195.048 dpi)

Bitmap saved as: C:/Users/mk/Documents/Python/ipython_notebook/SVG2PNG_files\SVG2PNG_8_2.png


変換成功!

変換結果を表示します。

In [12]:
from IPython.core.display import Image, display
for file in filenames_without_ext:
    filename=file+'.png'
    print filename
    display(Image(filename=filename,width=512))
    #そのまま表示すると大きすぎるので縮小して表示する。なぜか、nbconvert後のhtmlでは元に戻ってしまうので、貼り直しました。
    
C:/Users/mk/Documents/Python/ipython_notebook/SVG2PNG_files\SVG2PNG_8_1.png

C:/Users/mk/Documents/Python/ipython_notebook/SVG2PNG_files\SVG2PNG_8_2.png

まとめ

SVG形式は殆どのブラウザが対応しています。また、グラフによってはファイルサイズを小さくできます。 ですから、デフォルトでSVGになるように、初期設定ファイル(ipython_notebook_config.py)を変更しておいても良いと思います。 デメリットはブラウザ上で画像だけを拡大するというのが出来なくなる程度でしょう。 また、今回は自分自身の中でnbconvertや変換を行いましたが、この作業は別のノートブック上で行った方が実際には混乱が少ないと思います。