0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

RでグラフのPNG画像を高画質で保存したい

Last updated at Posted at 2023-06-23

Rで描いたグラフの画像をQiitaの記事に埋め込むためPNG形式でファイルに保存したい1。グラフのPNG画像を作成するには、Rのpng()関数やquartz.save()関数を使えばできます。ただ、これらの関数をデフォルトの引数で実行した場合、出力されたPNG画像は寸法が小さくて画質もよくありません2。Rの関数を使ってスクリーンショットのように高画質な画像で保存したい。その方法のメモです。

実行環境
R 4.3.1, macOS 12.6.5, iMac (Retina 5K)

スクリーンショットの代わりにわざわざRの関数を使う理由は、MacのScreenshot.appを使ってウインドウをキャプチャした場合、図1のようにウインドウのタイトルバーも画像に含まれてしまい、余分なのでトリミング作業が必要になるからです。画像が1枚だけなら取り込みたい部分をドラッグし範囲指定してキャプチャするのもよいですが、撮りたいグラフが複数あって、別々の画像に大きさや位置を揃えて作りたい場合、ウインドウの位置を移動してしまった時に、取り込み範囲を前回の画像と同じに合わせるのが難しいです(翌日に作業したときとか)。

図1
screenshot.png

スクリーンショットの撮り方: Shift + ⌘ + 4 の後に Space bar を押してカメラのポインターをグラフのウィンドウの上に移動し、⌥ + Click で選択するとウインドウの影を含めないで撮れます。

方法1. png()関数でファイルに書き出す

はじめにpng()関数を使う方法です。例1のスニペットは、png()で描画の出力先をファイルに指定し、グラフのPNG画像をスクリーンショット(図1)とほぼ同じ画質でファイルに書き出します。

例1
png("graph.png", type="quartz", width=1520, height=1520, res=218)
hist(data)
dev.off()

ここで、解像度(ppi: pixels per inch)を指定する引数resの値は次のようにして求めました。

まず、RのヘルプmacOS Quartz Deviceによると、Quartzウインドウのキャンバスの幅と高さのデフォルトは7インチとあります。Rのdev.size()関数でデバイスの画面サイズを確認しても7インチになっていました。

> dev.size("in")
[1] 7 7
> dev.size("px")
[1] 504 504
> dev.size("cm")
[1] 17.78 17.78
> 

dev.size()でブランクのQuartzウインドウを表示させて、タイトルバーを除くキャンバス部分の寸法を定規で測ってみると、筆者のモニターでは約178mm x 178mmでしたので、dev.size()を"in"や"cm"単位で指定したときの戻り値は、画面上の実際の寸法を表しています。

一方、dev.size("px")の戻り値は、筆者のモニター上でのピクセル数と一致しません。Screenshot.appでキャンバス部分を範囲指定すると画面には"760 x 752"と表示されます。ブランクのQuartzウインドウをスクリーンショットに撮り、Photoshopを使ってキャンバス部分だけトリミングしてサイズを調べると、画像の幅1520px, 高さ1505pxでした。使用しているモニターのデバイスピクセル比が2なので、元のピクセル数は幅760px, 高さ752.5pxということになりScreenshot.appの表示とほぼ一致します。

キャンバスの画面上の高さの実測値が幅より僅かに短いのが気になりますが、計算を簡単にするため、キャンバスの形状を正方形とみなします。この正方形の一辺の長さ(ピクセル数)は、図1のPNG画像の解像度情報3からもわかります(図2)。高さの値はタイトルバーを含んでいるため、幅の方の値1520pxを採用します。

図2
screenshot_info_resize.png
iMac (Retina 5K, 27-inch, 2017) Technical Specificationsによると、筆者が使っているモニターの解像度は218 ppiです4。一方、図2から解像度を算出すると、
1520 px / 7 inch = 217.14 ppi
になり、仕様とほぼ一致します。

以上より、引数resの値を218とします。

図3は、例1のスニペットを実行して出力されたPNG画像です。その解像度情報が図4です。図1と図3の画像を比較すると、ほぼ同じ画質に見えます。

図3
graph.png
図4
graph_info_resize.png
この方法で実行した場合、グラフの描画のためのQuartzウインドウは画面に表示されません。なぜなら、png()関数が呼ばれた後、dev.off()関数が呼ばれるまでの間、グラフィックデバイスへのグラフの描画はファイルに向けられるからです。これだとQuartzウインドウでグラフを見ながらPNG画像をファイルに保存したいとき不便です。次に説明するquartz.save()関数を使えば、グラフの画面出力とファイル保存が可能です。

方法2. quartz.save()関数でファイルに書き出す

次にquartz.save()関数を使う方法です。例2のスニペットは、Quartzウインドウに描画されたグラフに対して、quartz.save()でPNG形式の画像としてファイルに書き出します。

例2
par(bg="white")
hist(data)
quartz.save("quartz.png", dpi=218)

例1の手順と異なり、グラフを描画する前にpar()関数により現在のプロットデバイスに対して背景色をwhiteに設定しておく必要があります。

今回、Quartzウインドウのキャンバスの寸法はデフォルトのままなので、quartz.save()の引数に指定するのは出力先のファイル名と解像度dpi=218だけで十分です。

図5は、例2のスニペットを実行して出力されたPNG画像です。その解像度情報が図6です。図1と図5の画像を比較すると、こちらもほぼ同じ画質に見えます。

図5
quartz.png
図6
quartz_info_resize.png

(続きはこちら)

  1. 2023年6月現在、Qiitaにアップロード可能な画像はgif , jpeg , png , tiff形式のみ。https://help.qiita.com/ja/articles/qiita-image-upload

  2. png()関数で書き出した場合のデフォルトは480px x 480px。quartz.save()のデフォルトは699px x 699px (7in x 7in、100dpi)。

  3. MacのプレビューでPNG画像を開き、ツールインスペクターを表示をクリック

  4. 筆者が使っているディスプレイは27インチ、5120 x 2880なので、X軸の解像度ppi = 5120 / (cos(arctan(2880/5120)) * 27) = 217.571。真の値は217と218の間と思われる

0
2
5

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
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?