LoginSignup
1
1

More than 1 year has passed since last update.

PythonのJupyter NotebookでグラフだけRのggplot2で描きたい(ほぼ標準ライブラリ)

Last updated at Posted at 2021-09-07

データ分析をしていて、基本的にはPythonでの作業が快適だけど、グラフだけはRのggplot2で描きたい、ということが私はよくあります。
そういうとき、普通は次の2つの手段を取ることが多いと思います。

  • ggpy ライブラリを使う。これは、ggplot2の機能をPythonに移植したものです。
  • rpy2 ライブラリを使い、Rのコードをセルに書く(

1つめの手段はPythonネイティブなのが嬉しいものの、完璧な移植とは限らないのと文法の差を覚え直す必要があるところが難点です。
2つめの方が個人的には好みですが、Rでやりたいことがggplot2のグラフを書くだけなら、もう少し簡単にできそうです。

そこで、ggplot2でグラフを書いて表示させるだけの関数です。IPythonとデータフレームを渡す場合にpandasの機能を使う以外は標準ライブラリで完結しています。
やっていることはシンプルです。

  1. 一時フォルダを作成
  2. データフレームを利用する場合、それらを一時フォルダのCSVファイルに書き出し
  3. Rコードを生成
    1. ライブラリの読込
    2. データのロード
    3. ggplot2による描画を画像ファイルとして保存
  4. 保存した画像ファイルを表示
  5. 一時フォルダごと削除
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のコードを実行しているだけなので、自由度は高いです。
Screenshot_2021-09-08_01-44-19.png

関数に少し変更を加えれば、Jupyter上で表示するのではなく指定の場所にファイルを書き出すようにもできます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1