Rで描いたグラフのスクリーンショットをquartz.save()で保存したPNG画像と比べたらグラフの縦が僅かに短い

[前回の記事](https://qiita.com/kazhashimoto/items/6d8f555b2cbc2ba7dfd6)の続きです。


Rの[png()](https://search.r-project.org/R/refmans/grDevices/html/png.html)関数と[quartz.save()](https://search.r-project.org/R/refmans/grDevices/html/quartz.html)関数を使ってファイルに書き出したグラフのPNG画像。これらをQuartzウインドウのスクリーンショット画像に重ねてみたところ、あることに気づきました。

スクリーンショットのグラフは、他の2つの画像のそれに比べて縦方向が少し縮んでいるように見えます！

https://twitter.com/kazhashimoto1/status/1672247711830278144


以下、現象の説明です。

**実行環境[^1]**
R 4.3.1, macOS 12.6.5, iMac (Retina 5K)
[^1]: 上のツイートの動画で使用したRのバージョンは4.3.0でしたが、R4.3.1でも現象は再現しました

ズレの検証がしやすいように、この記事では正方形のボックスと45度の直線をプロットしたグラフを使います（図1）

**図1**
![quartz.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/23d34b67-19cb-c7fc-4355-b4d17ee78903.png)
上のグラフを描くRのスニペットはこれです。

```R:例1
par(pty="s")
plot(0:100, 0:100, xaxs="i", yaxs="i", type="l", asp=1)
```

引数の意味は次のとおり。

- [`par()`](https://search.r-project.org/R/refmans/graphics/html/par.html)関数の引数`pty="s"`でプロット領域を正方形に指定し、
- XY軸のアスペクト比が1:1になるように[`plot()`](https://search.r-project.org/R/refmans/graphics/html/plot.default.html)関数の引数[`asp`](https://search.r-project.org/R/refmans/graphics/html/plot.window.html)に1を指定します。
- さらに、(0,0)と(100,100)がboxの頂点にくるように`plot()`に[グラフィカルパラメーター](https://search.r-project.org/R/refmans/graphics/html/par.html)の引数`xaxs="i"`と`yaxs="i"`を指定します。

同様に次の例2と例3は、それぞれ`png()`と`quartz.save()`を使ってファイルに書き出すスニペットです。

```R:例2
png("graph.png", width=1520, height=1520, res=218, type="quartz")
par(pty="s")
plot(0:100, 0:100, xaxs="i", yaxs="i", type="l", asp=1)
dev.off()
```

```R:例3
par(bg="white", pty="s")
plot(0:100, 0:100, xaxs="i", yaxs="i", type="l", asp=1)
quartz.save("quartz.png", dpi=218)
```

### ズレの検証手順
冒頭のツイート添付の動画に使われているPhotoshopの画像についての説明です。

最初に、スクリーンショットに撮った例1の出力画像をPhotoshopに読み込みます（レイヤー1）、その上に例2と例3の出力画像を配置します（レイヤー2と3）。その際、グラフのボックスの幅と上辺の位置がレイヤー1（screenshot）のものと一致するように画像の位置を調整します[^1]。
[^1]: 上側のレイヤーの不透明度を下げて、画像を上下にドラッグしながら手作業で調整しました。

:::note info
Photoshopで画像のリンクを配置する際、筆者の環境では **環境設定 > 一般 > 画像をサイズ変更して配置** がON（デフォルト）になっています。背景レイヤー(screenshot)の横幅(1520px)より広い画像(1525px)を配置した時、Photoshopがアスペクト比を維持したまま画像の幅を1520pxに調整してくれるので、手作業で画像を拡大・縮小する操作は行なっていません。
:::


次にPhotoshopで正方形のシェイプを作り（マゼンタ色の線色）、レイヤー4に追加します。シェイプの上辺の位置をグラフのボックスに合わせ、縦横比を固定でドラッグしながらシェイプを拡大し、幅をボックスと一致させます。

結果、レイヤー2と3のPNG画像については、期待どおりレイヤー4「正方形」のシェイプとグラフのボックスが一致しました（図2）。

**図2**
![clip03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/b4049a01-d2c3-55fd-117a-df67bcf7a309.png)
ところが、レイヤー1の画像は正方形の下辺の位置がマゼンタ色の線より上にズレてしまってます（図3）。

**図3**
![clip01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/e9d934a1-06c9-fea1-b06b-66734b61b8f6.png)
高さが正方形の一辺より短くなっているため、45度になるはずの対角線もズレてしまっているのがわかります（図4）。図で、グレーの線色が薄い方がレイヤー3（quartz.save）です。実際、Photoshopのものさしツールで対角線の角度を測るとレイヤー2と3の画像では45度になるのに対して、レイヤー1の画像では44.7度でした。

**図4**
![diagonal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/b57a1df7-7b35-d445-6e4f-14a7f5672dfe.png)
この現象、最初、筆者が使っているモニターの画面が歪んでいるのかと疑いましたが、CSSで正方形を作ってブラウザーに表示したものをスクリーンショットで撮り、同様の手順でPhotoshopで確認したところ正しく正方形になっていましたから、RのQuartzウインドウの問題ではないかと思います。

## キャンバスのサイズが正方形ではない？
グラフを描かずに別の方法で検証してみます。
筆者の環境では、RのQuartzウインドウのキャンバスがそもそもデフォルトで正方形になっていないことがわかりました。

Rの[`dev.size()`](https://search.r-project.org/R/refmans/grDevices/html/dev.size.html)関数を呼んで、ブランクのQuartzウインドウを表示させてみます。

```R
> dev.size("in")
[1] 7 7
> 
```

`dev.size()`はサイズ"7 インチ"を返してきますが、実際に表示されたQuartzウインドウのスクリーンショットを撮り、Photoshopに読み込んでキャンバス部分を切り抜くと縦のピクセル数が幅よりも短いのがわかります。

まず、自動選択ツールでキャンバスの領域を選択します（図5）。

**図5**
![blank_select.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/d29e0676-73f2-7c1b-0ec0-36c621f298ce.png)
次にその選択範囲で画像を切り抜きます（図6）
**図6**
![blank_crop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/794be7ea-9205-83cd-9378-79f83346dbde.png)
切り取った結果の画像の寸法を右上のプロパティで確認すると、W 1520 px, H 1505 pxになっています。

やはり幅に比べて縦が15 px（デバイスピクセル）短い！画面上の寸法に換算[^2]すると幅760px, 高さ752.5pxだったというわけです。
[^2]: 使用したモニターのデバイスピクセル比は2

縦が短くなる現象は使用するモニターにも依存するのでしょうか。原因は分かりませんでした。