付記 2018/3/2
ENV["CONDA_JL_VERSION"]=3
してね。
→ [Julia] miniconda 3 を導入させるように指定した (= PyPlot が正しく動いた)
https://qiita.com/tenfu2tea/items/917dceb14687ffb1988c
元記事
Julia advent calendar 2016 5日目の記事です。
今年の個人トピックに、mayavi というライブラリが anaconda パッケージで提供されるようになったことがあります。Python でしばらく楽しんでいましたが、Julia からも使いたくなりました。けれど、conda 環境を Julia から使う方法が分かりません。
conda 環境を Julia から操作する仕組みは、PyCall.jl
と Conda.jl
の二つのパッケージが提供しています。これらの機能をユーザ目線で整理してまとめてみました。
前提
- MacOS X 10.12.1 Sierra で実行した結果を以下に引用しました。(私のユーザ名は ___ で隠してあります)
- カタカナの「パッケージ」は Julia パッケージを、ひらがなの「ぱっけーじ」は anaconda パッケージをそれぞれ指します。
- カタカナの「モジュール」は Julia モジュールを、ひらがなの「もじゅーる」は Python モジュールをそれぞれ指します。(前者は記事中に出現しませんけれども)
PyCall 概説
PyCall
パッケージは、Julia から Python を呼び出すためのパッケージです。呼び出すだけでなく conda ぱっけーじを追加できます。
PyCall
パッケージは、自分でインストールしてなくても、Python を呼び出すパッケージをインストールする際に同時にインストールされることがあります。
例えば、2次元グラフ描画のパッケージ PyPlot
をインストールした場合のメッセージを一部抜粋してみましょう。PyCall
と Conda
パッケージもインストール (あわせてビルド)されています。
julia> Pkg.add("PyPlot")
INFO: Initializing package repository /Users/___/.julia/v0.5
INFO: Cloning METADATA from https://github.com/JuliaLang/METADATA.jl
...
INFO: Cloning cache of Conda from https://github.com/JuliaPy/Conda.jl.git
INFO: Cloning cache of PyCall from https://github.com/JuliaPy/PyCall.jl.git
INFO: Cloning cache of PyPlot from https://github.com/JuliaPy/PyPlot.jl.git
INFO: Installing Conda v0.4.0
INFO: Installing PyCall v1.7.2
INFO: Installing PyPlot v2.2.4
...
INFO: Building Conda
INFO: Building PyCall
PyCall が呼ぶ Python の場所
PyCall
を使うには using PyCall
します。
PyCall
で呼び出される python インタプリタのバージョン、絶対パス、ライブラリパスは PyCall.pyversion
, PyCall.pyprogramname
,PyCall.libpython
で、それぞれ得ることができます。
julia> Pkg.add("PyCall") # 一度インストールすれば OK
...
INFO: PyCall is using python (Python 2.7.12) at /Users/___/.julia/v0.5/Conda/deps/usr/bin/python, libpython = /Users/___/.julia/v0.5/Conda/deps/usr/lib/libpython2.7 # PyCallを buildすると Pythonの実行パスとライブラリパスが表示されます
julia> using PyCall
julia> PyCall.pyversion
v"2.7.12"
julia> PyCall.pyprogramname
"/Users/___/.julia/v0.5/Conda/deps/usr/bin/python"
julia> PyCall.libpython
"/Users/___/.julia/v0.5/Conda/deps/usr/lib/libpython2.7"
さて、上の Python は Julia 自身が追加したものです。
PyCall
パッケージをビルド Pkg.build("PyCall")
する際に Python の実行ファイルが見つからないと、miniconda がインストールされます。 例えば、上で例に挙げた PyPlot
は、matplotlib
もじゅーるを使います。anaconda を自分で入れなくても matplotlib
が使えるのは、この仕組みからですね。
で。この miniconda-python の在処は、上の PyCall.pyprogramname
が示すディレクトリ、つまり、ホームディレクトリ直下 .julia
ディレクトリの下の Conda
ディレクトリです。
@pyimport : Python もじゅーるをインポートする
Python もじゅーるをインポートする (= Julia で使えるようにする)には、PyCall
パッケージの @pyimport
マクロを使います。
例えば、matplotlib
もじゅーるを、PyPlot
を用いずに直に使ってみると、以下のような感じです。
julia> using PyCall
julia> @pyimport matplotlib.pyplot as plt
julia> plt.plot( [1,2,3] )
julia> plt.show()
Python と見分けがつきませんが、これは @pyimport マクロが Python 型とJulia 型を相互に変換しているからです。
Python に渡す引数の型や戻り値の型を細かく指定したい場合には PyCall.pycall
命令で pythonの関数を呼び出します。 この辺は、別の解説に譲ります。
@pyimport
マクロで、python もじゅーるが見つからないと例外が発生します。
もう一つ、pyimport
という命令があります。こちらは、Python もじゅーるをインポートしますが、 Python 型とJulia 型を変換する機能はありません。
pyimport_conda : conda ぱっけーじの追加
PyCall
パッケージの pyimport_conda()
命令を用いると、上の miniconda 環境に、Python もじゅーる(ぱっけーじ)を追加できます。
呼び出し形式は
pyimport_conda(modulename, pkg, [channel])
です。
この命令では、最初に、Pythonの ぱっけーじ modulename を探索し、見つからないと pkg ぱっけーじを追加します。その後、上の pyimport(modulename, pkg, [channel])
を実行し、その戻り値を返します。
例えば mayavi というもじゅーる (ぱっけーじ名も同じ)を追加するには、以下のようにします。
julia> @pyimport mayavi
ERROR: PyError (:PyImport_ImportModule) <type 'exceptions.ImportError'>
ImportError('No module named mayavi',)
julia> pyimport_conda( "mayavi", "mayavi")
pyimport_conda
は、次に説明する Conda.add()
命令を内部で呼び出しています。
Conda パッケージを用いた conda環境の操作
Conda
パッケージを用いて、miniconda 環境を操作できます。シェル (コマンドライン、ターミナル)から使う conda
コマンドと同様の操作ができます。
-
Conda.list([env])
: インストールされている conda ぱっけーじ のリストを出力します。 -
Conda.add(pkg, [env])
: conda ぱっけーじ pkg を追加します。 -
Conda.rm(pkg, [env])
: conda ぱっけーじ pkg を削除します。 -
Conda.update([env])
: インストールされている conda ぱっけーじ を最新に更新します。
実行例を見てみます。
julia> Pkg.add("Conda") # PyCallパッケージをインストールしたら、たいていインストール済炭です。
julia> using Conda
julia> Conda.PYTHONDIR
"/Users/__/.julia/v0.5/Conda/deps/usr/bin"
julia> Conda.list()
# packages in environment at /Users/___/.julia/v0.5/Conda/deps/usr:
#
apptools 4.2.1 py27_0
conda 4.2.13 py27_0
conda-env 2.6.0 0
configobj 5.0.6 py27_0
... # 省略
julia> Conda.add("mayavi")
Fetching package metadata .............
Solving package specifications: ..........
Package plan for installation in environment /Users/___/.julia/v0.5/Conda/deps/usr:
The following NEW packages will be INSTALLED:
mayavi: 4.4.0-np19py27_0
Linking packages ...
[ COMPLETE ]|###################################################| 100%
... # 省略
julia> Conda.rm("mayavi")
Fetching package metadata .............
Solving package specifications: ..........
Package plan for package removal in environment /Users/___/.julia/v0.5/Conda/deps/usr:
The following packages will be REMOVED:
mayavi: 4.4.0-np19py27_0
Unlinking packages ...
[ COMPLETE ]|###################################################| 100%
... # 省略
julia> Conda.update()
Fetching package metadata .............
Solving package specifications: ..........
Package plan for installation in environment /Users/___/.julia/v0.5/Conda/deps/usr:
The following packages will be downloaded:
package | build
---------------------------|-----------------
openssl-1.0.2j | 0 3.0 MB
... # 省略
以上説明した Conda.list()
, Conda.add()
, Conda.rm()
, Conda.update()
を含めて、Conda
の命令は全て env
という省略可能パラメータをとります。env
は 操作対象の minionda 環境を指定するもので、既定値は Conda.PYTHONDIR
(miniconda環境の親ディレクトリのパス)です。
標準ではない anacondaぱっけーじをインストールする際には、チャネル channel を指定できます。
-
Conda.channels([env])
: conda環境env
に含まれるチャネルのリストを出力します。 -
Conda.add_channel(channel, [env])
: conda環境env
に、チャネルchannel
を追加します。 -
Conda.rm_channel(channel, [env])
: conda環境env
から、チャネルchannel
を削除します。
既定のチャネルは "defaults" です。
julia> Conda.channels()
1-element Array{String,1}:
"defaults"
Python - Conda 環境の変更
PyCall
の呼び出し先をを、自分でインストールした anaconda 環境に変更できます。1. 呼び出す Python パスの修正と、2. conda 環境の参照先の修正の、二つの手順を踏みます。
1. 呼び出す Python パスの修正
ENV["PYTHON"]
に、Python 実行ファイルのフルパスを指定します。
次いで、仮想環境 (virtualenv)を用いて anaconda環境を構築した場合は、rm(Pkg.dir("PyCall","deps","PYTHON"))
を実行します (ここ重要)。
仕上げに Pkg.build("PyCall")
で、PyCall
をビルドします。
julia> using PyCall
julia> ENV["PYTHON"]="/anaconda/bin/python"
"/anaconda/bin/python"
julia> rm(Pkg.dir("PyCall","deps","PYTHON"))
julia> Pkg.build("PyCall")
INFO: Building Conda
INFO: Building PyCall
INFO: PyCall is using /anaconda/bin/python (Python 2.7.12) at /anaconda/bin/python, libpython = //anaconda/lib/libpython2.7
2. conda環境の参照先を変更する
上では、PyCall で呼ぶ Python の実行パスが変更されただけです。
conda環境の参照先を変更するには、シェル(ターミナル、コマンドライン)で作業します。
最初に、Julia から呼び出されるための conda 環境を、新規に作成しておきます。その conda 環境のパスを環境変数 CONDA_JL_HOME
に設定して julia -e 'Pkg.build("Conda")’
を実行します。
$ conda create -n conda_jl python
$ export CONDA_JL_HOME="/Users/___/.pyenv/versions/anaconda-2.4.0/envs/conda_jl"
$ julia -e 'Pkg.build("Conda")'
INFO: Building Conda
以後は、Conda
を用いて、この conda環境を操作できます。しかし、混乱しそうなので、私は、シェルからぱっけーじを追加・削除することにしています。
$ conda install mayavi -n conda_jl
Using Anaconda Cloud api site https://api.anaconda.org
Fetching package metadata .............
Solving package specifications: ..........
Package plan for installation in environment /Users/___/.pyenv/versions/anaconda-2.4.0/envs/conda_jl:
... 以下略。
3. Juliaがインストールした Python に戻す
Juliaがインストールした conda環境に再び戻してみます。 2. → 1. の順に戻すのが、確実のようです。
(1) condaの参照先を戻して
$ export CONDA_JL_HOME="/Users/___/.julia/v0.5/Conda/deps/usr"
$ julia -e 'Pkg.build("Conda")'
INFO: Building Conda
(2) python 参照先を戻します。
ENV["PYTHON"]
に空文字列を指定して Pkg.build("PyCall")
します。
julia> ENV["PYTHON"]=""
julia> Pkg.build("PyCall")
INFO: Building Conda
INFO: Building PyCall
INFO: No system-wide Python was found; got the following error:
could not spawn `'' -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('VERSION'))"`: no such file or directory (ENOENT)
using the Python distribution in the Conda package
... 省略
julia> Conda.PYTHONDIR
"/Users/___/.julia/v0.5/Conda/bin"
以上の手順でたいてい conda環境の参照先は元に戻るのですが、戻らない場面も経験しました。最後の手段として "~/.julia/v0.5/Conda" 以下のファイルを削除してから ENV["PYTHON"]="" ; Pkg.build("Conda")
で、miniconda環境をビルドします (強引?)。
予告
以上で、解説は終わりです。この解説が、所望の conda ぱっけーじを Juliaから使うための参考になれば、うれしいです。
明日の Julia Advent Calendar も、私の担当です。 本題である mayavi ぱっけーじを Julia から使ってみた例を紹介します。