データ分析をしていて、基本的にはPythonでの作業が快適だけど、グラフだけはRのggplot2で描きたい、ということが私はよくあります。
そういうとき、普通は次の2つの手段を取ることが多いと思います。
1つめの手段はPythonネイティブなのが嬉しいものの、完璧な移植とは限らないのと文法の差を覚え直す必要があるところが難点です。
2つめの方が個人的には好みですが、Rでやりたいことがggplot2のグラフを書くだけなら、もう少し簡単にできそうです。
そこで、ggplot2でグラフを書いて表示させるだけの関数です。IPython
とデータフレームを渡す場合にpandas
の機能を使う以外は標準ライブラリで完結しています。
やっていることはシンプルです。
- 一時フォルダを作成
- データフレームを利用する場合、それらを一時フォルダのCSVファイルに書き出し
- Rコードを生成
- ライブラリの読込
- データのロード
- ggplot2による描画を画像ファイルとして保存
- 保存した画像ファイルを表示
- 一時フォルダごと削除
import os
import subprocess
from tempfile import TemporaryDirectory
from IPython.display import Image
def ggplot(plotcode, libs=("magrittr", "ggplot2"),
dispwidth=None, dispheight=None,
width=None, height=None,
showcode=False, **dataframes):
with TemporaryDirectory() as tmpdir:
importcode = ";".join(f"library({l})" for l in libs)
readcode = []
for name, df in dataframes.items():
filename = os.path.join(tmpdir, f"__data_{name}.csv")
df.to_csv(filename, index=False)
readcode.append(f"{name} <- read.csv('{filename}', as.is=TRUE)")
readcode = ";".join(readcode)
graphfile = os.path.join(tmpdir, "__graph.png")
if width is None:
width = "NA"
if height is None:
height = "NA"
code = f"""
{importcode}
{readcode}
..g <- {{
{plotcode}
}}
ggsave("{graphfile}", ..g, width={width}, height={height})
"""
if showcode:
print(code)
subprocess.run(["Rscript", "-e", code])
display(Image(filename=graphfile, width=dispwidth, height=dispheight))
上のセルを1回実行したうえで、下記のようなコードでグラフの描画ができます。
width
, height
は保存時のサイズ、dispwidth
は表示時のサイズです。
import pandas as pd
import numpy as np
df = pd.DataFrame({"x": np.linspace(-10, 10, 100)})
df["y"] = np.sin(df.x)
df2 = pd.DataFrame({"x": np.linspace(-10, 10, 100)})
df2["y"] = 1.2*np.cos(0.6*df2.x)
ggplot(
"""
ggplot(dat, aes(x=x, y=y)) +
geom_line() +
geom_line(aes(x=x, y=y), data=dat2, linetype="dotted") +
theme_bw()
""",
dat=df, dat2=df2,
width=4, height=2, dispwidth=640)
こういった出力がでます。基本的にはRのコードを実行しているだけなので、自由度は高いです。
関数に少し変更を加えれば、Jupyter上で表示するのではなく指定の場所にファイルを書き出すようにもできます。