からっぽのしょこ

読んだら書く!書いたら読む!同じ事は二度調べ(たく)ない

【R】縦軸と横軸の変換を作図したい【ggplot2】

はじめに

 とりあえず我流でやってみる黒魔術シリーズです。もっといい方法があれば教えてください。

 この記事では、縦軸と横軸を変換するグラフを作成します。

【他の内容】

www.anarchive-beta.com

【目次】

縦軸と横軸の変換を作図したい

 縦軸の値から横軸の値へ、または横軸の値から縦軸の値への変換を示す図を作成したい。ただしこの記事では、原点を中心として上下と左右それぞれで同じサイズのグラフを扱う。

 利用するパッケージを読み込む。

# 利用パッケージ
library(tidyverse)
library(gganimate)
library(patchwork)
library(magick)

 この記事では、基本的に パッケージ名::関数名() の記法を使うので、パッケージを読み込む必要はない。ただし、作図コードについてはパッケージ名を省略するので、ggplot2 を読み込む必要がある。
 また、ネイティブパイプ演算子 |> を使う。magrittr パッケージのパイプ演算子 %>% に置き換えられるが、その場合は magrittr を読み込む必要がある。

恒等関数による変換

 恒等関数(  f(x) = x )の直線を用いて軸の変換を可視化する。

変換点

 座標を指定する。

# 値を指定
x_val <- 1

# 値を格納
point_df <- tibble::tibble(
  x = x_val
)
point_df
# A tibble: 1 × 1
      x
  <dbl>
1     1

 変換を行う値を指定して、データフレームに格納する。

 軸変換のグラフを作成する。

# グラフサイズを指定
axis_size <- 1.5

# 軸変換を作図
ggplot() + 
  geom_segment(mapping = aes(x = c(-Inf, 0), y = c(0, -Inf), 
                             xend = c(Inf, 0), yend = c(0, Inf)), 
               arrow = arrow(length = unit(10, units = "pt"), ends = "last")) + # x・y軸線
  geom_abline(slope = 1, intercept = 0, linewidth = 1) + # 恒等関数
  geom_segment(data = point_df, 
               mapping = aes(x = x, y = x, xend = x, yend = -Inf), 
               linewidth = 1, linetype = "dotted") + # x軸の目盛線
  geom_segment(data = point_df, 
               mapping = aes(x = x, y = x, xend = -Inf, yend = x), 
               linewidth = 1, linetype = "dotted") + # y軸の目盛線
  geom_point(data = point_df, 
             mapping = aes(x = x, y = -Inf), 
             size = 4) + # x軸線上の点
  geom_point(data = point_df, 
             mapping = aes(x = -Inf, y = x), 
             size = 4) + # y軸線上の点
  geom_point(data = point_df, 
             mapping = aes(x = x, y = x), 
             size = 4) + # 直線上の点
  coord_fixed(ratio = 1, clip = "off", 
              xlim = c(-axis_size, axis_size), 
              ylim = c(-axis_size, axis_size)) + 
  labs(title = "convert axis", 
       subtitle = parse(text = paste("x ==", x_val)), 
       x = "x", y = "y")

恒等関数による軸の変換図


・作図コード(クリックで展開)

 フレーム数を指定して、値を作成する。

# フレーム数を指定
frame_num <- 100

# 値を格納
anim_point_df <- tibble::tibble(
  frame_i = 1:frame_num, 
  t = seq(from = 0, to = 2*pi, length.out = frame_num+1)[1:frame_num], # 座標計算用のラジアン
  x = cos(t), 
  val_label = paste("x ==", round(x, digits = 3))
)
anim_point_df
# A tibble: 100 × 4
   frame_i      t     x val_label 
     <int>  <dbl> <dbl> <chr>     
 1       1 0      1     x == 1    
 2       2 0.0628 0.998 x == 0.998
 3       3 0.126  0.992 x == 0.992
 4       4 0.188  0.982 x == 0.982
 5       5 0.251  0.969 x == 0.969
 6       6 0.314  0.951 x == 0.951
 7       7 0.377  0.930 x == 0.93 
 8       8 0.440  0.905 x == 0.905
 9       9 0.503  0.876 x == 0.876
10      10 0.565  0.844 x == 0.844
# ℹ 90 more rows

 フレーム数 frame_num を指定して、変換を行う値を frame_nun 個作成する。

 軸変換のアニメーションを作成する。

# グラフサイズを指定
axis_size <- 1.5

# 軸変換を作図
anim <- ggplot() + 
  geom_segment(mapping = aes(x = c(-Inf, 0), y = c(0, -Inf), 
                             xend = c(Inf, 0), yend = c(0, Inf)), 
               arrow = arrow(length = unit(10, units = "pt"), ends = "last")) + # x・y軸線
  geom_abline(slope = 1, intercept = 0, linewidth = 1) + # 恒等関数
  geom_segment(data = anim_point_df, 
               mapping = aes(x = x, y = x, xend = x, yend = -Inf), 
               linewidth = 1, linetype = "dotted") + # x軸の目盛線
  geom_segment(data = anim_point_df, 
               mapping = aes(x = x, y = x, xend = -Inf, yend = x), 
               linewidth = 1, linetype = "dotted") + # y軸の目盛線
  geom_point(data = anim_point_df, 
             mapping = aes(x = x, y = -Inf), 
             size = 4) + # x軸線上の点
  geom_point(data = anim_point_df, 
             mapping = aes(x = -Inf, y = x), 
             size = 4) + # y軸線上の点
  geom_point(data = anim_point_df, 
             mapping = aes(x = x, y = x), 
             size = 4) + # 直線上の点
  geom_text(data = anim_point_df, 
            mapping = aes(x = -Inf, y = Inf, label = val_label), 
            parse = TRUE, hjust = 0, vjust = -1.1) + # 値ラベル
  gganimate::transition_manual(frames = frame_i) + # フレーム切替
  coord_fixed(ratio = 1, clip = "off", 
              xlim = c(-axis_size, axis_size), 
              ylim = c(-axis_size, axis_size)) + 
  labs(title = "convert axis", 
       subtitle = "", # ラベル表示用の空行
       x = "x", y = "y")

# gif画像を作成
gganimate::animate(plot = anim, nframes = frame_num, fps = 10, width = 500, height = 500)

恒等関数による軸の変換図

  y = x の直線上の点  (x, y) = (x, x) を噛ませることで縦軸と横軸の値の入れ替えを表現できる。

利用例

 恒等関数による軸の変換を示す図を作成する。
 作図コードについては「GitHub - anemptyarchive/Black-Magick/.../convert_axis.R」を参照のこと。

・円周上の点の軸変換

恒等関数による円周上の点の軸の入れ替え

 左上図の円周上の点のx・y座標をそれぞれ入れ替えた円周と点が右下図である。左下図はx軸からy軸への変換、右上図はy軸からx軸への変換を表している。
 円周の形状は軸を入れ替えても変化しない。点の位置は恒等関数に対して線対称な位置に変換する。

・楕円周上の点の軸変換

恒等関数による楕円周上の点の軸の入れ替え

 楕円の場合は、形状も線対称に変化する。

円弧による変換

 続いて、円弧(中心点からの距離が同じ点を結んだ曲線)を用いて軸の変換を可視化する。

変換曲線

 変換の軌道を示す曲線を描画する。

 座標を指定して、点の描画用のデータフレームを作成する。

# 値を指定
x_val <- 1

# 値を格納
point_df <- tibble::tibble(
  x = x_val
)
point_df
# A tibble: 1 × 1
      x
  <dbl>
1     1

 変換を行う値を指定して、データフレームに格納する。

・作図コード(クリックで展開)

 アニメーション用に、フレーム数を指定して、点の描画用のデータフレームを作成する。

# フレーム数を指定
frame_num <- 100

# 値を格納
anim_point_df <- tibble::tibble(
  frame_i = 1:frame_num, 
  t = seq(from = 0, to = 2*pi, length.out = frame_num+1)[frame_i], # 座標計算用のラジアン
  x = cos(t), 
  val_label = paste("x ==", round(x, digits = 3))
)
anim_point_df
# A tibble: 100 × 4
   frame_i      t     x val_label 
     <int>  <dbl> <dbl> <chr>     
 1       1 0      1     x == 1    
 2       2 0.0628 0.998 x == 0.998
 3       3 0.126  0.992 x == 0.992
 4       4 0.188  0.982 x == 0.982
 5       5 0.251  0.969 x == 0.969
 6       6 0.314  0.951 x == 0.951
 7       7 0.377  0.930 x == 0.93 
 8       8 0.440  0.905 x == 0.905
 9       9 0.503  0.876 x == 0.876
10      10 0.565  0.844 x == 0.844
# ℹ 90 more rows

 フレーム数 frame_num を指定して、変換を行う値を frame_nun 個作成する。


右と上の変換

 変換曲線の描画用のデータフレームを作成する。

# グラフサイズを指定
axis_size <- 1.5

# 変換曲線の座標を作成
arc_df <- tibble::tibble(
  t  = seq(from = 0, to = 0.5*pi, length.out = 91), # 座標計算用のラジアン
  x0 = -axis_size, 
  y0 = -axis_size, 
  r  = x_val + axis_size, 
  arc_x = x0 + r * cos(t), 
  arc_y = y0 + r * sin(t)
)
arc_df
# A tibble: 91 × 6
        t    x0    y0     r arc_x arc_y
    <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1 0       -1.5  -1.5   2.5 1     -1.5 
 2 0.0175  -1.5  -1.5   2.5 1.00  -1.46
 3 0.0349  -1.5  -1.5   2.5 0.998 -1.41
 4 0.0524  -1.5  -1.5   2.5 0.997 -1.37
 5 0.0698  -1.5  -1.5   2.5 0.994 -1.33
 6 0.0873  -1.5  -1.5   2.5 0.990 -1.28
 7 0.105   -1.5  -1.5   2.5 0.986 -1.24
 8 0.122   -1.5  -1.5   2.5 0.981 -1.20
 9 0.140   -1.5  -1.5   2.5 0.976 -1.15
10 0.157   -1.5  -1.5   2.5 0.969 -1.11
# ℹ 81 more rows

 中心点を  (x_0, y_0)、半径(中心点からの距離)を  r、ラジアン(弧度法の角度)を  t として、円弧の座標は  (x, y) = (x_0 + r \cos t, y_0 + r \sin t) で計算できる。 0 \leq t \leq \frac{\pi}{2} の範囲のラジアンを用いると、x軸線の正の部分を  0^{\circ} として、 0^{\circ} \leq t^{\circ} \leq 90^{\circ} の円弧になる。円周率  \pipi で扱える。
 グラフサイズの半分(原点  (0, 0) をグラフの中心として上下左右のサイズ)を  S として、中心点  (x_0, y_0) = (-S, -S) と半径  r = x_i + S を用いて円弧の座標を計算する。ただし、 x_i + S \lt 0 の範囲では円弧が原点に対して反転する。

 軸変換のグラフを作成する。

# 軸変換を作図
ggplot() + 
  geom_segment(mapping = aes(x = c(-Inf, 0), y = c(0, -Inf), 
                             xend = c(Inf, 0), yend = c(0, Inf)), 
               arrow = arrow(length = unit(10, units = "pt"), ends = "last")) + # x・y軸線
  geom_line(data = arc_df, 
            mapping = aes(x = arc_x, y = arc_y), 
            linewidth = 1, linetype = "dotted") + # 変換曲線
  geom_segment(data = point_df, 
               mapping = aes(x = x, y = -axis_size, xend = x, yend = -Inf), 
               linewidth = 1, linetype = "dotted") + # x軸の目盛線
  geom_segment(data = point_df, 
               mapping = aes(x = -axis_size, y = x, xend = -Inf, yend = x), 
               linewidth = 1, linetype = "dotted") + # y軸の目盛線
  geom_point(data = point_df, 
             mapping = aes(x = x, y = -Inf), 
             size = 4) + # x軸線上の点
  geom_point(data = point_df, 
             mapping = aes(x = -Inf, y = x), 
             size = 4) + # y軸線上の点
  coord_fixed(ratio = 1, clip = "off", 
              xlim = c(-axis_size, axis_size), 
              ylim = c(-axis_size, axis_size)) + 
  labs(title = "convert axis", 
       subtitle = parse(text = paste("x ==", x_val)), 
       x = expression(x), 
       y = expression(x))

円弧による軸の変換図

 coord_fixed() でグラフサイズを設定する場合、指定した値よりも一回り大きく描画される。その追加分の軌道を geom_segment() で線分として描画している。追加分の線分を描画せずに、点の座標を枠線上ではなくグラフサイズに( x, y 引数に -Inf, Inf ではなく -axis_size, axis_size を指定)してもよい。

・作図コード(クリックで展開)

 変換曲線の描画用のデータフレームを作成する。

# グラフサイズを指定
axis_size <- 1.5

# 変換曲線の座標を作成
anim_arc_df <- anim_point_df |> 
  dplyr::select(frame_i, x) |> 
  dplyr::reframe(
    t = seq(from = 0, to = 0.5*pi, length.out = 91), .by = dplyr::everything()
  ) |> # フレームごとにラジアンを作成
  dplyr::mutate(
    x0 = -axis_size, 
    y0 = -axis_size, 
    r  = x + axis_size, 
    arc_x = x0 + r * cos(t), 
    arc_y = y0 + r * sin(t)
  )
anim_arc_df
# A tibble: 9,100 × 8
   frame_i     x      t    x0    y0     r arc_x arc_y
     <int> <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1       1     1 0       -1.5  -1.5   2.5 1     -1.5 
 2       1     1 0.0175  -1.5  -1.5   2.5 1.00  -1.46
 3       1     1 0.0349  -1.5  -1.5   2.5 0.998 -1.41
 4       1     1 0.0524  -1.5  -1.5   2.5 0.997 -1.37
 5       1     1 0.0698  -1.5  -1.5   2.5 0.994 -1.33
 6       1     1 0.0873  -1.5  -1.5   2.5 0.990 -1.28
 7       1     1 0.105   -1.5  -1.5   2.5 0.986 -1.24
 8       1     1 0.122   -1.5  -1.5   2.5 0.981 -1.20
 9       1     1 0.140   -1.5  -1.5   2.5 0.976 -1.15
10       1     1 0.157   -1.5  -1.5   2.5 0.969 -1.11
# ℹ 9,090 more rows

 フレームごとにラジアンを reframe() で作成して、変換を行う値ごとに円弧の座標を計算する。

 軸変換のアニメーションを作成する。

# 軸変換のアニメーションを作図
anim <- ggplot() + 
  geom_segment(mapping = aes(x = c(-Inf, 0), y = c(0, -Inf), 
                             xend = c(Inf, 0), yend = c(0, Inf)), 
               arrow = arrow(length = unit(10, units = "pt"), ends = "last")) + # x・y軸線
  geom_line(data = anim_arc_df, 
            mapping = aes(x = arc_x, y = arc_y), 
            linewidth = 1, linetype = "dotted") + # 変換曲線
  geom_segment(data = anim_point_df, 
               mapping = aes(x = x, y = -axis_size, xend = x, yend = -Inf), 
               linewidth = 1, linetype = "dotted") + # x軸の目盛線
  geom_segment(data = anim_point_df, 
               mapping = aes(x = -axis_size, y = x, xend = -Inf, yend = x), 
               linewidth = 1, linetype = "dotted") + # y軸の目盛線
  geom_point(data = anim_point_df, 
             mapping = aes(x = x, y = -Inf), 
             size = 4) + # x軸線上の点
  geom_point(data = anim_point_df, 
             mapping = aes(x = -Inf, y = x), 
             size = 4) + # y軸線上の点
  geom_text(data = anim_point_df, 
            mapping = aes(x = -Inf, y = Inf, label = val_label), 
            parse = TRUE, hjust = 0, vjust = -1.1) + # 値ラベル
  gganimate::transition_manual(frames = frame_i) + # フレーム切替
  coord_fixed(ratio = 1, clip = "off", 
              xlim = c(-axis_size, axis_size), 
              ylim = c(-axis_size, axis_size)) + 
  labs(title = "convert axis", 
       subtitle = "", # ラベル表示用の空行
       x = "x", y = "y")

# gif画像を作成
gganimate::animate(plot = anim, nframes = frame_num, fps = 10, width = 500, height = 500)

円弧による軸の変換図

 縦軸と横軸の値を入れ替える軌道を曲線(グラフの左下を中心点とする円弧)で表現できる。

左と下の変換

 変換曲線の描画用のデータフレームを作成する。

# グラフサイズを指定
axis_size <- 1.5

# 変換曲線の座標を作成
arc_df <- tibble::tibble(
  t  = seq(from = pi, to = 1.5*pi, length.out = 91), # 座標計算用のラジアン
  x0 = axis_size, 
  y0 = axis_size, 
  r  = -(x_val - axis_size), 
  arc_x = x0 + r * cos(t), 
  arc_y = y0 + r * sin(t)
)
arc_df
# A tibble: 91 × 6
       t    x0    y0     r arc_x arc_y
   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1  3.14   1.5   1.5   0.5  1     1.5 
 2  3.16   1.5   1.5   0.5  1.00  1.49
 3  3.18   1.5   1.5   0.5  1.00  1.48
 4  3.19   1.5   1.5   0.5  1.00  1.47
 5  3.21   1.5   1.5   0.5  1.00  1.47
 6  3.23   1.5   1.5   0.5  1.00  1.46
 7  3.25   1.5   1.5   0.5  1.00  1.45
 8  3.26   1.5   1.5   0.5  1.00  1.44
 9  3.28   1.5   1.5   0.5  1.00  1.43
10  3.30   1.5   1.5   0.5  1.01  1.42
# ℹ 81 more rows

 中心点  (x_0, y_0) = (S, S)、半径  r = -(x_i - S)、ラジアン  \pi \leq t \leq \frac{3}{2} \pi を用いて円弧の座標を計算する。ただし、 x_i - S \gt 0 の範囲では円弧が原点に対して反転する。

 軸変換のグラフを作成する。

# 軸変換を作図
ggplot() + 
  geom_segment(mapping = aes(x = c(-Inf, 0), y = c(0, -Inf), 
                             xend = c(Inf, 0), yend = c(0, Inf)), 
               arrow = arrow(length = unit(10, units = "pt"), ends = "last")) + # x・y軸線
  geom_line(data = arc_df, 
            mapping = aes(x = arc_x, y = arc_y), 
            linewidth = 1, linetype = "dotted") + # 変換曲線
  geom_segment(data = point_df, 
               mapping = aes(x = x, y = axis_size, xend = x, yend = Inf), 
               linewidth = 1, linetype = "dotted") + # x軸の目盛線
  geom_segment(data = point_df, 
               mapping = aes(x = axis_size, y = x, xend = Inf, yend = x), 
               linewidth = 1, linetype = "dotted") + # y軸の目盛線
  geom_point(data = point_df, 
             mapping = aes(x = x, y = Inf), 
             size = 4) + # x軸線上の点
  geom_point(data = point_df, 
             mapping = aes(x = Inf, y = x), 
             size = 4) + # y軸線上の点
  coord_fixed(ratio = 1, clip = "off", 
              xlim = c(-axis_size, axis_size), 
              ylim = c(-axis_size, axis_size)) + 
  labs(title = "convert axis", 
       subtitle = parse(text = paste("x ==", x_val)), 
       x = expression(x), 
       y = expression(x))

円弧による軸の変換図


・作図コード(クリックで展開)

 変換曲線の描画用のデータフレームを作成する。

# グラフサイズを指定
axis_size <- 1.5

# 変換曲線の座標を作成
anim_arc_df <- anim_point_df |> 
  dplyr::select(frame_i, x) |> 
  dplyr::reframe(
    t = seq(from = pi, to = 1.5*pi, length.out = 91), .by = dplyr::everything()
  ) |> # フレームごとにラジアンを作成
  dplyr::mutate(
    x0 = axis_size, 
    y0 = axis_size, 
    r  = -(x - axis_size), 
    arc_x = x0 + r * cos(t), 
    arc_y = y0 + r * sin(t)
  )
anim_arc_df
# A tibble: 9,100 × 8
   frame_i     x     t    x0    y0     r arc_x arc_y
     <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1       1     1  3.14   1.5   1.5   0.5  1     1.5 
 2       1     1  3.16   1.5   1.5   0.5  1.00  1.49
 3       1     1  3.18   1.5   1.5   0.5  1.00  1.48
 4       1     1  3.19   1.5   1.5   0.5  1.00  1.47
 5       1     1  3.21   1.5   1.5   0.5  1.00  1.47
 6       1     1  3.23   1.5   1.5   0.5  1.00  1.46
 7       1     1  3.25   1.5   1.5   0.5  1.00  1.45
 8       1     1  3.26   1.5   1.5   0.5  1.00  1.44
 9       1     1  3.28   1.5   1.5   0.5  1.00  1.43
10       1     1  3.30   1.5   1.5   0.5  1.01  1.42
# ℹ 9,090 more rows

 フレーム(変換を行う値)ごとに円弧の座標を計算する。

 軸変換のアニメーションを作成する。

# 軸変換のアニメーションを作図
anim <- ggplot() + 
  geom_segment(mapping = aes(x = c(-Inf, 0), y = c(0, -Inf), 
                             xend = c(Inf, 0), yend = c(0, Inf)), 
               arrow = arrow(length = unit(10, units = "pt"), ends = "last")) + # x・y軸線
  geom_line(data = anim_arc_df, 
            mapping = aes(x = arc_x, y = arc_y), 
            linewidth = 1, linetype = "dotted") + # 変換曲線
  geom_segment(data = anim_point_df, 
               mapping = aes(x = x, y = axis_size, xend = x, yend = Inf), 
               linewidth = 1, linetype = "dotted") + # x軸の目盛線
  geom_segment(data = anim_point_df, 
               mapping = aes(x = axis_size, y = x, xend = Inf, yend = x), 
               linewidth = 1, linetype = "dotted") + # y軸の目盛線
  geom_point(data = anim_point_df, 
             mapping = aes(x = x, y = Inf), 
             size = 4) + # x軸線上の点
  geom_point(data = anim_point_df, 
             mapping = aes(x = Inf, y = x), 
             size = 4) + # y軸線上の点
  geom_text(data = anim_point_df, 
            mapping = aes(x = -Inf, y = Inf, label = val_label), 
            parse = TRUE, hjust = 0, vjust = -1.1) + # 値ラベル
  gganimate::transition_manual(frames = frame_i) + # フレーム切替
  coord_fixed(ratio = 1, clip = "off", 
              xlim = c(-axis_size, axis_size), 
              ylim = c(-axis_size, axis_size)) + 
  labs(title = "convert axis", 
       subtitle = "", # ラベル表示用の空行
       x = "x", y = "y")

# gif画像を作成
gganimate::animate(plot = anim, nframes = frame_num, fps = 10, width = 500, height = 500)

円弧による軸の変換図

 縦軸と横軸の値を入れ替える軌道を曲線(グラフの右上を中心点とする円弧)で表現できる。

 上から左や下から右に変化する図の場合は、値が正負が反転する。この記事では扱わない。

変換グリッド線

 変換曲線に対応する目盛線を描画する。

右と上の変換

 グリッド線の描画用のデータフレームを作成する。

# グラフサイズを指定
axis_size <- 1.5

# 変換軸の目盛間隔を設定
tick_major_val <- 1
tick_minor_val <- 0.5 * tick_major_val

# 変換軸のサイズを設定:(目盛間隔で切り上げ)
grid_size <- ceiling(axis_size / tick_minor_val) * tick_minor_val

# 変換軸のグリッド線の座標を作成
grid_df <- tidyr::expand_grid(
  x = seq(
    from = -grid_size+tick_minor_val, 
    #to   = grid_size, # (x・y軸目盛の範囲のみ描画する場合)
    to   = 2*grid_size*sqrt(2) - grid_size, # (対角線のサイズ分を加算)
    by   = tick_minor_val
  ), # 直交座標における目盛値
  t = seq(from = 0, to = 0.5*pi, length.out = 91) # 座標計算用のラジアン
) |> # 目盛線ごとにラジアンを作成
  dplyr::mutate(
    x0 = -grid_size, 
    y0 = -grid_size, 
    r  = grid_size + x, 
    arc_x = x0 + r * cos(t), 
    arc_y = y0 + r * sin(t), 
    grid = dplyr::if_else(
      x%%tick_major_val == 0, true = "major", false = "minor"
    ) # 主・補助目盛の書き分け用
  )
grid_df
# A tibble: 728 × 8
       x      t    x0    y0     r arc_x arc_y grid 
   <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
 1    -1 0       -1.5  -1.5   0.5 -1    -1.5  major
 2    -1 0.0175  -1.5  -1.5   0.5 -1.00 -1.49 major
 3    -1 0.0349  -1.5  -1.5   0.5 -1.00 -1.48 major
 4    -1 0.0524  -1.5  -1.5   0.5 -1.00 -1.47 major
 5    -1 0.0698  -1.5  -1.5   0.5 -1.00 -1.47 major
 6    -1 0.0873  -1.5  -1.5   0.5 -1.00 -1.46 major
 7    -1 0.105   -1.5  -1.5   0.5 -1.00 -1.45 major
 8    -1 0.122   -1.5  -1.5   0.5 -1.00 -1.44 major
 9    -1 0.140   -1.5  -1.5   0.5 -1.00 -1.43 major
10    -1 0.157   -1.5  -1.5   0.5 -1.01 -1.42 major
# ℹ 718 more rows

 直交座標における目盛の値を作成して、目盛線ごとにラジアンを expand_grid() で作成し、それぞれ円弧の座標を計算する。
 直交座標と変換曲線用の目盛線がズレないように、値を調整する必要がある。grid_size (の計算時の axis_size の部分の値によって)でグリッド線の描画範囲を設定できる。

 変換曲線用のグリッド線のグラフを作成する。

# 軸変換を作図
ggplot() + 
  geom_path(data = grid_df, 
            mapping = aes(x = arc_x, y = arc_y, group = r, linewidth = grid), 
            color = "white") + # グリッド線
  geom_segment(mapping = aes(x = c(-Inf, 0), y = c(0, -Inf), 
                             xend = c(Inf, 0), yend = c(0, Inf)), 
               arrow = arrow(length = unit(10, units = "pt"), ends = "last")) + # x・y軸線
  scale_linewidth_manual(breaks = c("major", "minor"), 
                         values = c(0.5, 0.25), guide = "none") + # 主・補助目盛線用
  #theme(panel.grid = element_blank()) + # 直交座標のグリッド線を非表示
  coord_fixed(ratio = 1, 
              xlim = c(-axis_size, axis_size), 
              ylim = c(-axis_size, axis_size)) + 
  labs(title = "convert axis", 
       x = "x", y = "y")

円弧による軸変換のグリッド線

 一定間隔で円弧を描画する。scale_linewidth_manual() で線幅を設定して、主目盛と補助目盛の線を描き分ける。

左と下の変換

 グリッド線の描画用のデータフレームを作成する。

# グラフサイズを指定
axis_size <- 1.5

# 変換軸の目盛間隔を設定
tick_major_val <- 1
tick_minor_val <- 0.5 * tick_major_val

# 変換軸のサイズを設定:(目盛間隔で切り上げ)
grid_size <- ceiling(axis_size / tick_minor_val) * tick_minor_val

# 変換軸のグリッド線の座標を作成
grid_df <- tidyr::expand_grid(
  x = seq(
    #from = -grid_size, # (x・y軸目盛の範囲のみ描画する場合)
    from = floor((-2*grid_size*sqrt(2) + grid_size) / tick_minor_val) * tick_minor_val, # (対角線のサイズ分を追加して切り下げ)
    to   = grid_size-tick_minor_val, 
    by   = tick_minor_val
  ), # 直交座標における目盛値
  t = seq(from = pi, to = 1.5*pi, length.out = 91) # 座標計算用のラジアン
) |> # 目盛線ごとにラジアンを作成
  dplyr::mutate(
    x0 = grid_size, 
    y0 = grid_size, 
    r  = grid_size - x, 
    arc_x = x0 + r * cos(t), 
    arc_y = y0 + r * sin(t), 
    grid = dplyr::if_else(
      x%%tick_major_val == 0, true = "major", false = "minor"
    ) # 主・補助目盛の書き分け用
  )
grid_df
# A tibble: 819 × 8
       x     t    x0    y0     r arc_x arc_y grid 
   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
 1    -3  3.14   1.5   1.5   4.5 -3    1.5   major
 2    -3  3.16   1.5   1.5   4.5 -3.00 1.42  major
 3    -3  3.18   1.5   1.5   4.5 -3.00 1.34  major
 4    -3  3.19   1.5   1.5   4.5 -2.99 1.26  major
 5    -3  3.21   1.5   1.5   4.5 -2.99 1.19  major
 6    -3  3.23   1.5   1.5   4.5 -2.98 1.11  major
 7    -3  3.25   1.5   1.5   4.5 -2.98 1.03  major
 8    -3  3.26   1.5   1.5   4.5 -2.97 0.952 major
 9    -3  3.28   1.5   1.5   4.5 -2.96 0.874 major
10    -3  3.30   1.5   1.5   4.5 -2.94 0.796 major
# ℹ 809 more rows

 目盛線(直交座標における値)ごとに円弧の座標を計算する。

 変換曲線用のグリッド線のグラフを作成する。

# 軸変換を作図
ggplot() + 
  geom_path(data = grid_df, 
            mapping = aes(x = arc_x, y = arc_y, group = r, linewidth = grid), 
            color = "white") + # グリッド線
  geom_segment(mapping = aes(x = c(-Inf, 0), y = c(0, -Inf), 
                             xend = c(Inf, 0), yend = c(0, Inf)), 
               arrow = arrow(length = unit(10, units = "pt"), ends = "last")) + # x・y軸線
  scale_linewidth_manual(breaks = c("major", "minor"), 
                         values = c(0.5, 0.25), guide = "none") + # 主・補助目盛線用
  #theme(panel.grid = element_blank()) + # 直交座標のグリッド線を非表示
  coord_fixed(ratio = 1, 
              xlim = c(-axis_size, axis_size), 
              ylim = c(-axis_size, axis_size)) + 
  labs(title = "convert axis", 
       x = "x", y = "y")

円弧による軸変換のグリッド線


利用例

 円弧による軸の変換を示す図を作成する。
 作図コードについては「convert_axis.R」を参照のこと。

・円周上の点の軸変換

円弧による円周上の点の軸の入れ替え

 x軸・y軸それぞれで変換する範囲のみにグリッド線を描画している。変換曲線も範囲内で変化し、範囲外では直線にしている。境界部分で点の間隔が変わったり連動しなかったりするのを避けるには、軌道全体の座標を1つのデータフレームに格納しておけばよいと思う。

・楕円周上の点の軸変換

円弧による円周上の点の軸の入れ替え


 この記事では、縦軸と横軸の変換を可視化した。

おわりに

 ここ1年ほどだったかと思いますが、このブログで多用した円弧による軸変換について年内最後に書き出しておくことにしました。(途中で上げて完成したのは年を越してからになりましたが。)
 つい先日思いついたというか扱った内容に直線による変換も登場したので、それも忘れない内に書いておこうというきっかけもありました。

 円周に対して楕円周でいいんですかね。円弧の中心点の呼び方も気になります。その他に、変数名というか英語がかなり怪しいので、この記事に限らず間違っていたら教えていただけるととても助かります。よろしくお願いします。

 2023年12月30日は、Juice=Juiceの現リーダー植村あかりさんの25歳のお誕生日です!

 元々は末っ子だったメンバーがリーダーになってこれからもまだまだ物語が続いていくのって良いですよね。卒業まで目一杯楽しんでください♬

【関連する内容】

www.anarchive-beta.com

 元々はこの記事のために必要になった内容です。