niszetの日記

細かい情報を載せていくブログ

(R) ggimageパッケージのgeom_image()でアスペクト比を与えて表示する

サークルカットをRで描きたいだけなのに…。

さて、ggimageパッケージ、用途が良くわかりませんが、ggplot()でプロットする中に画像を埋め込めるので便利です。

が、なんかアスペクト比がおかしくなるのですよね。たとえば

library(ggimage)
ggplot()+geom_image(aes(x=0, y=0), image="circle_title.bmp", size=1, by="width")+coord_equal()

で、こんな感じ。

f:id:niszet:20180824002721p:plain

本当はアスペクト比が勝手に決まるような意図でコードが書かれているようなのですが、有効になっていないようで(原因はちょっと心当たりはある)、内部のコードから必要な部分を取り出して無理やりアスペクト比を変換してみます。

ggimageの内部では下記のようにimage_read2()という関数で画像を取り込んでいます。

ggimage::image_read2("circle_title.bmp")
##  format width height colorspace matte filesize density
## 1    PNG  1008    591       sRGB FALSE        0   72x72

…なのですが、この関数は余白を除いた領域のサイズをとってきます。なんかbmpなのにpngになってますね…。
この関数、画像の表示には良いですが、画像サイズを知りたい場合はこれでは困るので、オリジナルの関数を使います。

magick::image_read("circle_title.bmp")
##   format width height colorspace matte filesize density
## 1   BMP3  1152    648       sRGB FALSE  2239542   72x72

こんな感じ。ちなみにこれらの関数は実行するとVIewerペインに画像が表示されます。

また、この戻り値は

str(ggimage::image_read2("circle_title.bmp"))
## Class 'magick-image' <externalptr> 

でmagick-imageクラスになっています(どちらの場合も)。このクラスのオブジェクトが持っている画像の情報を抜き出すにはmagick::image_info()を使います。

magick::image_info(magick::image_read("circle_title.bmp"))
##   format width height colorspace matte filesize density
## 1   BMP3  1152    648       sRGB FALSE  2239542   72x72

これで、widthとheightを知ることが出来ました。この値をとってくるにはそれぞれ

image_width <- magick::image_info(magick::image_read("circle_title.bmp"))$width
image_width
## [1] 1152

image_height <- magick::image_info(magick::image_read("circle_title.bmp"))$height
image_height 
## [1] 648

でよいです。あとはgeom_image()の引数aspに↑で得た幅と高さからアスペクト比を計算して与え、表示領域の固定をします。

ggplot()+geom_image(aes(x=0, y=0), image="circle_title.png", size=1, by="width", asp=image_width/image_height)+
  coord_fixed()+xlim(-image_width/2, image_width/2)+ylim(-image_height/2, image_height/2)

f:id:niszet:20180824002733p:plain

これに軸を消したり背景消したり…ということをthemeで与えてあげると…

ggplot()+geom_image(aes(x=0, y=0), image="circle_title.png", size=1, by="width", asp=image_width/image_height)+
  coord_fixed()+xlim(-image_width/2, image_width/2)+ylim(-image_height/2, image_height/2)+
    theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
          panel.background = element_blank(), axis.line = element_line(colour = "black", size=1),
          axis.text = element_blank(), axis.title = element_blank(), axis.ticks.length = grid::unit(rep(0, 4), "points"),
          axis.ticks = element_blank(), axis.line.x = element_blank(),
          axis.line.y = element_blank(), plot.margin=grid::unit(rep(0, 4), "points"))

f:id:niszet:20180824003032p:plain

と、オリジナルの画像そのままの表示となりました。

あとはこれに好きな文字を足したり、plotを重ねたりしてあげればよいですね。

ようやくこれでサークルカットが描ける…よかったよかった。

Enjoy!!