からっぽのしょこ

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

【R】csc関数の可視化

はじめに

 R言語で三角関数の定義や公式を可視化しようシリーズです。

 この記事では、csc関数のグラフを作成します。

【前の内容】

www.anarchive-beta.com

【他の記事一覧】

www.anarchive-beta.com

【この記事の内容】

csc関数の可視化

 三角関数(trigonometric functions)・円関数(circular functions)の1つであるcsc関数(余割関数・コセカント関数・cosecant function)をグラフで確認します。

 ggplot2パッケージなどを使って作図します。

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

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

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

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


定義式の確認

 まずは、csc関数の定義式を確認します。

 csc関数は、sin関数の逆数で定義されます。

 \displaystyle
\csc x
    = \frac{1}{\sin x}

  \sin x はサイン関数です。sin関数については「【R】sin関数の可視化 - からっぽのしょこ」を参照してください。
 ただし、 n を整数として  x = n \pi のとき、 \sin x = 0 なので、0除算になるため定義できません。 \pi は円周率で、変数  x は弧度法の角度(ラジアン)です。

csc関数の作図

 次に、csc関数のグラフを作成します。

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

 変数の値(ベクトル)を設定します。

# 関数曲線用のラジアンを指定
theta_vec <- seq(from = -2.5*pi, to = 2.5*pi, length.out = 1000)
head(theta_vec)
## [1] -7.853982 -7.838258 -7.822534 -7.806811 -7.791087 -7.775363

 曲線の座標計算に用いる変数(ラジアン)  \theta の範囲を指定してtheta_vecとします。円周率  \pipiで扱えます。

 csc関数の曲線を描画するためのデータフレームを作成します。

# 閾値を指定
threshold <- 4

# csc関数を計算
csc_df <- tibble::tibble(
  t = theta_vec, 
  sin_t = sin(theta_vec), 
  csc_t = 1/sin(theta_vec)
) |> 
  dplyr::mutate(
    csc_t = dplyr::if_else(
      condition = (csc_t >= -threshold & csc_t <= threshold), 
      true = csc_t, 
      false = NA_real_
    ) # 閾値外の値を欠損値に置換
  )
csc_df
## # A tibble: 1,000 × 3
##        t  sin_t csc_t
##    <dbl>  <dbl> <dbl>
##  1 -7.85 -1     -1   
##  2 -7.84 -1.00  -1.00
##  3 -7.82 -1.00  -1.00
##  4 -7.81 -0.999 -1.00
##  5 -7.79 -0.998 -1.00
##  6 -7.78 -0.997 -1.00
##  7 -7.76 -0.996 -1.00
##  8 -7.74 -0.994 -1.01
##  9 -7.73 -0.992 -1.01
## 10 -7.71 -0.990 -1.01
## # … with 990 more rows

  \theta の値と  \sin \theta, \csc \theta の値をデータフレームに格納します。cot関数はsin()を使って計算できます。sin関数の値は比較に使います。
  \theta = i \pi ( i は整数)付近で  -\infty または  \infty に近付くので、閾値thresholdを指定しておき、-threshold未満またはthresholdより大きい場合は(数値型の)欠損値NAに置き換えます。

 x軸目盛を設定するためのベクトルを作成します。装飾用の処理です。

# 半周期の目盛の数(分母の値)を指定
denom <- 2

# 目盛の通し番号(分子の値)を作成
numer_vec <- seq(
  from = floor(min(theta_vec) / pi * denom), 
  to = ceiling(max(theta_vec) / pi * denom), 
  by = 1
)

# 目盛ラベル用の文字列を作成
label_vec <- paste0(c("", "-")[(numer_vec < 0)+1], "frac(", abs(numer_vec), ", ", denom, ")~pi")
head(numer_vec); head(label_vec)
## [1] -5 -4 -3 -2 -1  0
## [1] "-frac(5, 2)~pi" "-frac(4, 2)~pi" "-frac(3, 2)~pi" "-frac(2, 2)~pi"
## [5] "-frac(1, 2)~pi" "frac(0, 2)~pi"

 角度  \theta に関する軸目盛ラベルを  i, n を整数として  \frac{i}{n} \pi の形で表示することにします。
  ndenomとして整数を指定します。 n は、半周期  \pi の範囲における目盛の数に対応します。
 theta_vecに対して、 \theta = \frac{\pi}{n} i i について整理した  i = \frac{n}{\pi} \theta を計算して、最小値(の小数部分をfloor()で切り捨てた値)から最大値(の小数部分をceiling()で切り上げた値)までの整数を作成してnumer_vecとします。

 numer_vec, denomを使って目盛ラベル用の文字列を作成します。
 ギリシャ文字などの記号や数式を表示する場合は、expression()の記法を用います。オブジェクト(プログラム上の変数)の値を使う場合は、文字列として作成しておきparse()text引数に渡します。"frac(分子, 分母)"で分数、"~"でスペースを表示します。

 漸近線を描画するためのベクトルを作成します。

# 漸近線用の値を作成
asymptote_vec <- seq(
  from = floor(min(theta_vec) / pi) + 1, 
  to = floor(max(theta_vec) / pi), 
  by = 1
) * pi
asymptote_vec; asymptote_vec*2/pi
## [1] -6.283185 -3.141593  0.000000  3.141593  6.283185
## [1] -4 -2  0  2  4

  \theta = i \pi ( \pi の倍数)のとき  \cot \theta が発散するので、theta_vecの範囲内の  i \pi の値を(上手いことして)作成します。

 csc関数のグラフを作成します。

# csc関数を作図
ggplot() + 
  geom_line(data = csc_df, 
            mapping = aes(x = t, y = csc_t, linetype = "csc"), 
            size = 1, na.rm = TRUE) + # csc曲線
  geom_line(data = csc_df, 
            mapping = aes(x = t, y = sin_t, linetype = "sin"), 
            size = 1) + # sin曲線
  geom_vline(xintercept = asymptote_vec, linetype = "dashed") + # 漸近線
  scale_x_continuous(breaks = numer_vec/denom*pi, 
                     labels = parse(text = label_vec)) + # 目盛ラベル
  scale_linetype_manual(breaks = c("csc", "sin"), 
                        values = c("solid", "dotted"), name = "function") + # (凡例表示用)
  coord_fixed(ratio = 1) + # アスペクト比
  labs(title = "cosecant function", 
       x = expression(theta), 
       y = expression(csc~theta))

csc関数のグラフ

 x軸を  \theta、y軸を  \csc \theta として、geom_line()でcsc関数の曲線を描画します。また、 \sin \theta の曲線を点線で描画します。
 x軸が  i \pi の点( 0 の前後  \pi 間隔)に、geom_vline()で漸近線を破線で描画します。
  \sin \theta = 0 となる  \theta が漸近線なのが分かります。


単位円の作図

 続いて、csc関数の可視化に利用する単位円(unit circle)のグラフを確認します。円やラジアン(弧度法の角度)については「【R】円周の作図 - からっぽのしょこ」を参照してください。

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

 単位円を描画するためのデータフレームを作成します。

# 半径を指定
r <- 1

# 円周の座標を計算
circle_df <- tibble::tibble(
  t = seq(from = 0, to = 2*pi, length.out = 601), # ラジアン
  x = r * cos(t), 
  y = r * sin(t)
)
circle_df
## # A tibble: 601 × 3
##         t     x      y
##     <dbl> <dbl>  <dbl>
##  1 0      1     0     
##  2 0.0105 1.00  0.0105
##  3 0.0209 1.00  0.0209
##  4 0.0314 1.00  0.0314
##  5 0.0419 0.999 0.0419
##  6 0.0524 0.999 0.0523
##  7 0.0628 0.998 0.0628
##  8 0.0733 0.997 0.0732
##  9 0.0838 0.996 0.0837
## 10 0.0942 0.996 0.0941
## # … with 591 more rows

 円周の座標計算用のラジアンとして  0 \leq \theta \leq 2 \pi の範囲の値を作成して、x軸の値  x = \cos \theta、y軸の値  y = \sin \theta を計算します。

 円周上に角度(ラジアン)目盛を描画するためのデータフレームを作成します。

# 半円の目盛の数(分母の値)を指定
denom <- 6

# 角度目盛ラベルの描画用
d <- 1.1
radian_lable_df <- tibble::tibble(
  nomer = seq(from = 0, to = 2*denom-1, by = 1), # 目盛の通し番号(分子の値)を作成
  t_deg = nomer / denom * 180, # 度数法
  t_rad = nomer / denom * pi,  # 弧度法
  x = r * cos(t_rad), 
  y = r * sin(t_rad), 
  label_x = d * x, 
  label_y = d * y, 
  rad_label = paste0("frac(", nomer, ", ", denom, ")~pi"), # ラジアンラベル
  h = 1 - (x * 0.5 + 0.5), 
  v = 1 - (y * 0.5 + 0.5)
)
radian_lable_df
## # A tibble: 12 × 10
##    nomer t_deg t_rad         x         y   label_x   label_y rad_label         h
##    <dbl> <dbl> <dbl>     <dbl>     <dbl>     <dbl>     <dbl> <chr>         <dbl>
##  1     0     0 0      1   e+ 0  0         1.1 e+ 0  0        frac(0, 6)~… 0     
##  2     1    30 0.524  8.66e- 1  5   e- 1  9.53e- 1  5.5 e- 1 frac(1, 6)~… 0.0670
##  3     2    60 1.05   5   e- 1  8.66e- 1  5.5 e- 1  9.53e- 1 frac(2, 6)~… 0.25  
##  4     3    90 1.57   6.12e-17  1   e+ 0  6.74e-17  1.1 e+ 0 frac(3, 6)~… 0.5   
##  5     4   120 2.09  -5   e- 1  8.66e- 1 -5.5 e- 1  9.53e- 1 frac(4, 6)~… 0.75  
##  6     5   150 2.62  -8.66e- 1  5   e- 1 -9.53e- 1  5.5 e- 1 frac(5, 6)~… 0.933 
##  7     6   180 3.14  -1   e+ 0  1.22e-16 -1.1 e+ 0  1.35e-16 frac(6, 6)~… 1     
##  8     7   210 3.67  -8.66e- 1 -5   e- 1 -9.53e- 1 -5.5 e- 1 frac(7, 6)~… 0.933 
##  9     8   240 4.19  -5.00e- 1 -8.66e- 1 -5.50e- 1 -9.53e- 1 frac(8, 6)~… 0.75  
## 10     9   270 4.71  -1.84e-16 -1   e+ 0 -2.02e-16 -1.1 e+ 0 frac(9, 6)~… 0.5   
## 11    10   300 5.24   5   e- 1 -8.66e- 1  5.5 e- 1 -9.53e- 1 frac(10, 6)… 0.25  
## 12    11   330 5.76   8.66e- 1 -5.00e- 1  9.53e- 1 -5.50e- 1 frac(11, 6)… 0.0670
## # … with 1 more variable: v <dbl>

 目盛指示線や目盛グリッド用の座標をx, y列、目盛ラベル用の座標をlabel_x, label_y列とします。ラベルの表示位置をdで調整します。

 円周と角度目盛のグラフを作成します。

# グラフサイズ用の値を指定
axis_size <- 1.4

# 単位円を作図
ggplot() + 
  geom_path(data = circle_df, 
            mapping = aes(x = x, y = y), 
            size = 1) + # 円周
  geom_text(data = radian_lable_df, 
            mapping = aes(x = label_x, y = label_y, label = rad_label, hjust = h, vjust = v), parse = TRUE) + # 角度目盛ラベル
  geom_text(data = radian_lable_df, 
            mapping = aes(x = x, y = y, angle = t_deg+90), 
            label = "|", size = 2) + # 角度目盛指示線
  geom_segment(data = radian_lable_df, 
               mapping = aes(x = 0, y = 0, xend = x, yend = y), 
               linetype = "dotted") + # 角度目盛グリッド
  coord_fixed(ratio = 1, 
              xlim = c(-axis_size, axis_size), ylim = c(-axis_size, axis_size)) + # 描画領域
  labs(title = "unit circle", 
       subtitle = parse(text = paste0("r==", r)), 
       x = expression(x == r~cos~theta), 
       y = expression(y == r~sin~theta))

単位円のグラフ

 このグラフ上に三角関数の値を直線として描画します。

単位円上のcsc関数の可視化

 次は、単位円上における三角関数(csc・sin・cos・cot)のグラフを作成します。

グラフの作成

 変数を固定したcsc関数をグラフで確認します。

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

 変数の値(スカラ)を設定します。

# 円周上の点用のラジアンを指定
theta <- 2/6 * pi
theta
## [1] 1.047198

 円周上の点の座標計算に用いる変数(ラジアン)  \thetathetaとして値を指定します。ただし、theta0のとき計算結果にInfが含まれるため意図しないグラフになります。発散時の対策については「アニメーションの作成」を参照してください。

 円周上の点を描画するためのデータフレームを作成します。

# 単位円上の点の座標を計算
point_df <- tibble::tibble(
  t = theta, 
  sin_t = sin(theta), 
  cos_t = cos(theta)
)
point_df
## # A tibble: 1 × 3
##       t sin_t cos_t
##   <dbl> <dbl> <dbl>
## 1  1.05 0.866   0.5

  \theta の値と  \sin \theta, \cos \theta の値をデータフレームに格納します。

 角マークを描画するためのデータフレームを作成します。

# 角マークの座標を計算
d <- 0.15
angle_mark_df <- tibble::tibble(
  t = seq(from = 0, to = theta, length.out = 100), 
  x = d * cos(t), 
  y = d * sin(t)
)
angle_mark_df
## # A tibble: 100 × 3
##         t     x       y
##     <dbl> <dbl>   <dbl>
##  1 0      0.15  0      
##  2 0.0106 0.150 0.00159
##  3 0.0212 0.150 0.00317
##  4 0.0317 0.150 0.00476
##  5 0.0423 0.150 0.00634
##  6 0.0529 0.150 0.00793
##  7 0.0635 0.150 0.00951
##  8 0.0740 0.150 0.0111 
##  9 0.0846 0.149 0.0127 
## 10 0.0952 0.149 0.0143 
## # … with 90 more rows

 2つの線分のなす角  \theta を示す角マークを描画するために、 0 から  \theta までのラジアンを作成して、円弧の座標を計算します。サイズの調整用の値(半径)をdとします。

 角ラベルを描画するためのデータフレームを作成します。

# 角ラベルの座標を計算
d <- 0.21
angle_label_df <- tibble::tibble(
  t = 0.5 * theta, 
  x = d * cos(t), 
  y = d * sin(t)
)
angle_label_df
## # A tibble: 1 × 3
##       t     x     y
##   <dbl> <dbl> <dbl>
## 1 0.524 0.182 0.105

 角マークの中点に角ラベルを配置するために、 \frac{\theta}{2} のラジアンを作成して、円弧上の点の座標を計算します。表示位置の調整用の値(原点からのノルム)をdとします。

 ここまでは、共通の処理です。ここからは、3つの方法で図示します。

パターン1

 1つ目の方法では、x軸線から伸びる直線としてシンプルにcsc関数を可視化します。ただし、csc関数の絶対値と線分の長さが対応しますが、csc関数の正負と座標が対応しません。

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

 半径を示す線分を描画するためのデータフレームを作成します。

# 半径の線分の座標を格納
radius_df <- tibble::tibble(
  x_from = c(0, 0, 1/tan(theta)), 
  y_from = c(0, 0, 0), 
  x_to = c(1, cos(theta), 1/tan(theta)), 
  y_to = c(0, sin(theta), 1), 
  width = c("normal", "normal", "thin") # 太さ用
)
radius_df
## # A tibble: 3 × 5
##   x_from y_from  x_to  y_to width 
##    <dbl>  <dbl> <dbl> <dbl> <chr> 
## 1  0          0 1     0     normal
## 2  0          0 0.5   0.866 normal
## 3  0.577      0 0.577 1     thin

 原点と点  (1, 0) を結ぶ線分(x軸線の正の部分)と、原点と円周上の点  (\cos \theta, \sin \theta) を結ぶ線分を描画するために、2つの線分の座標を格納します。
 また、関数直線の補助線として、長さが半径と同じ線分の座標を(次のデータフレームの座標を睨めっこして)格納します。
 なす角用の線分と補助線を、線の太さで描き分けることにします。type列として、それぞれの線を区別するための文字列を指定します。文字列の内容は自由です。

 三角関数を直線として描画するためのデータフレームを作成します。

# 関数ラベルのレベルを指定
fnc_level_vec <- c("csc", "sin", "cos", "cot")

# 関数直線の線分の座標を格納
function_line_df <- tibble::tibble(
  fnc = c("csc", "sin", "cos", "cot") |> 
    factor(levels = fnc_level_vec), # 色用
  x_from = c(
    0, 
    cos(theta), 
    0, 
    0
  ), 
  y_from = c(
    0, 
    0, 
    0, 
    0
  ), 
  x_to = c(
    1/tan(theta), 
    cos(theta), 
    cos(theta), 
    1/tan(theta)
  ), 
  y_to = c(
    1, 
    sin(theta), 
    0, 
    0
  ), 
  width = c("normal", "normal", "bold", "thin") # 太さ用
)
function_line_df
## # A tibble: 4 × 6
##   fnc   x_from y_from  x_to  y_to width 
##   <fct>  <dbl>  <dbl> <dbl> <dbl> <chr> 
## 1 csc      0        0 0.577 1     normal
## 2 sin      0.5      0 0.5   0.866 normal
## 3 cos      0        0 0.5   0     bold  
## 4 cot      0        0 0.577 0     thin

 関数を区別するためのfnc列の因子レベルをfnc_level_vecとして指定しておきます。因子レベルは、線分の描画順(重なり順)や色付け順に影響します。
 各線分の始点の座標をx_from, y_from列、終点の座標をx_to, y_to列として、完成図を見ながら頑張って指定します。
 線が重なる対策として、下の(先に描画される)線分を太く、上の(後に描画される)線分を細く描画することにします。

 関数名をラベルとして描画するためのデータフレームを作成します。

# 関数ラベルの座標を格納
function_label_df <- tibble::tibble(
  fnc = c("csc", "sin", "cos", "cot") |> 
    factor(levels = fnc_level_vec), # 色用
  x = c(
    0.5 / tan(theta), 
    cos(theta), 
    0.5 * cos(theta), 
    0.5 / tan(theta)
  ), 
  y = c(
    0.5, 
    0.5 * sin(theta), 
    0, 
    0
  ), 
  angle = c(0, 90, 0, 0), 
  h = c(1.1, 0.5, 0.5, 0.5), 
  v = c(0.5, -0.5, -0.5, 1), 
  fnc_label = c(
    ifelse(test = cos(theta) >= 0, yes = "csc~theta", no = "-csc~theta"), 
    "sin~theta", 
    "cos~theta", 
    "cot~theta"
  ) # 関数ラベル
)
function_label_df
## # A tibble: 4 × 7
##   fnc       x     y angle     h     v fnc_label
##   <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>    
## 1 csc   0.289 0.5       0   1.1   0.5 csc~theta
## 2 sin   0.5   0.433    90   0.5  -0.5 sin~theta
## 3 cos   0.25  0         0   0.5  -0.5 cos~theta
## 4 cot   0.289 0         0   0.5   1   cot~theta

 この例では、関数を示す線分の中点に関数名を表示するため、中点の座標とラベル用の文字列などを格納します。
 ただし、 \frac{\pi}{2} \lt \theta \lt \frac{3 \pi}{2} の範囲でcsc直線が直感的でない座標になるので、 \cos \theta \lt 0 のときマイナスの符号を付けて表示することにします。
 ラベルの表示角度をangle列、表示角度に応じた左右の表示位置をh列、上下の表示位置をv列として値を指定します。

 変数と関数の値を表示するための文字列を作成します。

# 変数ラベル用の文字列を作成
variable_label <- paste0(
  "list(", 
  "theta==", round(theta/pi, digits = 2), "*pi", 
  ", csc~theta==", round(1/sin(theta), digits = 2), 
  ", sin~theta==", round(sin(theta), digits = 2), 
  ", cos~theta==", round(cos(theta), digits = 2), 
  ", cot~theta==", round(1/tan(theta), digits = 2), 
  ")"
)
variable_label
## [1] "list(theta==0.33*pi, csc~theta==1.15, sin~theta==0.87, cos~theta==0.5, cot~theta==0.58)"

 "=="で等号、"list(変数1, 変数2)"で複数の(数式上の)変数を並べて表示します。(プログラム上の)変数の値を使う場合は、文字列として作成しておきparse()text引数に渡します。

 単位円上に三角関数の直線を重ねたグラフを作成します。

# グラフサイズ用の値を設定
y_size <- 1.3
x_min <- min(-y_size, 1/tan(theta))
x_max <- max(y_size, 1/tan(theta))

# 単位円上の三角関数直線を作図
ggplot() + 
  geom_path(data = circle_df, 
            mapping = aes(x = x, y = y), 
            size = 1) + # 円周
  geom_segment(data = radian_lable_df, 
               mapping = aes(x = 0, y = 0, xend = x, yend = y), 
               color = "white") + # 角度目盛グリッド
  geom_text(data = radian_lable_df, 
            mapping = aes(x = x, y = y, angle = t_deg+90), label = "|", 
            size = 2) + # 角度目盛指示線
  geom_text(data = radian_lable_df, 
            mapping = aes(x = label_x, y = label_y, label = rad_label, hjust = h, vjust = v), parse = TRUE) + # 角度目盛ラベル
  geom_hline(yintercept = 1, linetype = "dashed") + # csc直線用の補助線
  geom_point(data = point_df, 
             mapping = aes(x = cos_t, y = sin_t), 
             size = 4) + # 円周上の点
  geom_segment(data = radius_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, size = width)) + # 半径直線
  geom_path(data = angle_mark_df, 
            mapping = aes(x = x, y = y), 
            size = 0.5) + # 角マーク
  geom_text(data = angle_label_df, 
            mapping = aes(x = x, y = y), label = "theta", parse = TRUE, 
            size = 5) + # 角ラベル
  geom_segment(data = function_line_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                             color = fnc, size = width)) + # 関数直線
  geom_text(data = function_label_df, 
            mapping = aes(x = x, y = y, label = fnc_label, color = fnc, 
                          hjust = h, vjust = v, angle = angle), parse = TRUE, show.legend = FALSE) + # 関数ラベル
  scale_size_manual(breaks = c("normal", "bold", "thin"), 
                    values = c(1, 1.6, 0.8), guide = "none") + # (線が重なる対策)
  coord_fixed(ratio = 1, 
              xlim = c(x_min, x_max), ylim = c(-y_size, y_size)) + # 描画領域
  labs(title = "circular functions", 
       subtitle = parse(text = variable_label), 
       color = "function", 
       x = "x", y = "y")

 geom_segment()で線分を描画して、各関数の値を直線で示します。
 geom_label()でラベル(文字列)を描画します。

単位円上の点とcsc関数の関係

 csc関数の定義式  \csc \theta = \frac{1}{\sin \theta} やこの図から、 \sin \theta : 1 = 1 : \csc \theta なのが分かります。csc関数の値は、「原点と点  (\cos \theta, \sin \theta) を通る直線」と「 y = 1 の直線(破線)」の交点  (\frac{1}{\tan \theta}, 1) と原点を結ぶ線分の長さです。ただし、 \pi \lt \theta \lt 2 \pi の範囲では符号が反転します。

パターン2

 2つ目の方法では、x軸線から伸びる直線としてcsc関数の正負とxっ軸の正負が対応するように可視化します。

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

 半径を示す線分を描画するためのデータフレームを作成します。

# 変換フラグを設定
cos_flg <- cos(theta) >= 0

# 半径の線分の座標を格納
radius_df <- tibble::tibble(
  x_from = c(
    0, 0, 
    1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
  ), 
  y_from = c(
    0, 0, 
    0, ifelse(test = cos_flg, yes = NA, no = 0)
  ), 
  x_to = c(
    1, cos(theta), 
    1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
  ), 
  y_to = c(
    0, sin(theta), 
    1, ifelse(test = cos_flg, yes = NA, no = 1)
  ), 
  width = c("normal", "normal", "thin", "thin") # 太さ用
)
radius_df
## # A tibble: 4 × 5
##   x_from y_from   x_to   y_to width 
##    <dbl>  <dbl>  <dbl>  <dbl> <chr> 
## 1  0          0  1      0     normal
## 2  0          0  0.5    0.866 normal
## 3  0.577      0  0.577  1     thin  
## 4 NA         NA NA     NA     thin

 「パターン1」の座標に加えて、符号を反転させた際の線分に対応する補助線の座標も格納します。

 三角関数を直線として描画するためのデータフレームを作成します。

# 関数ラベルのレベルを指定
fnc_level_vec <- c("csc", "sin", "cos", "cot")

# 関数直線の線分の座標を格納
function_line_df <- tibble::tibble(
  fnc = c(
    "csc", "csc", 
    "sin", 
    "cos", 
    "cot", "cot"
  ) |> 
    factor(levels = fnc_level_vec), # 色用
  x_from = c(
    0, ifelse(test = cos_flg, yes = NA, no = 0), 
    cos(theta), 
    0, 
    0, ifelse(test = cos_flg, yes = NA, no = 0)
  ), 
  y_from = c(
    0, ifelse(test = cos_flg, yes = NA, no = 0), 
    0, 
    0, 
    0, ifelse(test = cos_flg, yes = NA, no = 0)
  ), 
  x_to = c(
    ifelse(test = cos_flg, yes = 1/tan(theta), no = -1/tan(theta)), ifelse(test = cos_flg, yes = NA, no = 1/tan(theta)), 
    cos(theta), 
    cos(theta), 
    1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
  ), 
  y_to = c(
    1, ifelse(test = cos_flg, yes = NA, no = 1), 
    sin(theta), 
    0, 
    0, ifelse(test = cos_flg, yes = NA, no = 0)
  ), 
  type = c(
    "main", "sub", 
    "main", 
    "main", 
    "main", "sub"
  ), # 線タイプ用
  width = c(
    "normal", "normal", 
    "normal", 
    "bold", 
    "thin", "thin"
  ) # 太さ用
)
function_line_df
## # A tibble: 6 × 7
##   fnc   x_from y_from   x_to   y_to type  width 
##   <fct>  <dbl>  <dbl>  <dbl>  <dbl> <chr> <chr> 
## 1 csc      0        0  0.577  1     main  normal
## 2 csc     NA       NA NA     NA     sub   normal
## 3 sin      0.5      0  0.5    0.866 main  normal
## 4 cos      0        0  0.5    0     main  bold  
## 5 cot      0        0  0.577  0     main  thin  
## 6 cot     NA       NA NA     NA     sub   thin

 「パターン1」の座標に加えて、 \frac{\pi}{2} \lt \theta \lt \frac{3 \pi}{2} の範囲でも直感的な座標になるように、符号を反転させた線分の座標を格納します。
 元の関数(線分)と符号を反転させた関数(線分)を、線の種類で描き分けることにします。type列として、それぞれの線を区別するための文字列を指定します。文字列の内容は自由です。

 関数名をラベルとして描画するためのデータフレームを作成します。

# 関数ラベルの座標を格納
function_label_df <- tibble::tibble(
  fnc = c("csc", "csc", "sin", "cos", "cot", "cot") |> 
    factor(levels = fnc_level_vec), # 色用
  x = c(
    0.5 / ifelse(test = cos_flg, yes = tan(theta), no = -tan(theta)), ifelse(test = cos_flg, yes = NA, no = 0.5/tan(theta)), 
    cos(theta), 
    0.5 * cos(theta), 
    0.5 / tan(theta), ifelse(test = cos_flg, yes = NA, no = -0.5/tan(theta))
  ), 
  y = c(
    0.5, ifelse(test = cos_flg, yes = NA, no = 0.5), 
    0.5 * sin(theta), 
    0, 
    0, ifelse(test = cos_flg, yes = NA, no = 0)
  ), 
  angle = c(0, 0, 90, 0, 0, 0), 
  h = c(1.1, -0.1, 0.5, 0.5, 0.5, 0.5), 
  v = c(0.5, 0.5, -0.5, -0.5, 1, 1), 
  fnc_label = c("csc~theta", "-csc~theta", "sin~theta", "cos~theta", "cot~theta", "-cot~theta") # 関数ラベル
)
function_label_df
## # A tibble: 6 × 7
##   fnc        x      y angle     h     v fnc_label 
##   <fct>  <dbl>  <dbl> <dbl> <dbl> <dbl> <chr>     
## 1 csc    0.289  0.5       0   1.1   0.5 csc~theta 
## 2 csc   NA     NA         0  -0.1   0.5 -csc~theta
## 3 sin    0.5    0.433    90   0.5  -0.5 sin~theta 
## 4 cos    0.25   0         0   0.5  -0.5 cos~theta 
## 5 cot    0.289  0         0   0.5   1   cot~theta 
## 6 cot   NA     NA         0   0.5   1   -cot~theta

 線分の中点の座標とラベル用の文字列などを格納します。

 単位円上に三角関数の直線を重ねたグラフを作成します。

# グラフサイズ用の値を設定
y_size <- 1.3
x_size <- max(y_size, abs(1/tan(theta)))

# 単位円上の三角関数直線を作図
ggplot() + 
  geom_path(data = circle_df, 
            mapping = aes(x = x, y = y), 
            size = 1) + # 円周
  geom_segment(data = radian_lable_df, 
               mapping = aes(x = 0, y = 0, xend = x, yend = y), 
               color = "white") + # 角度目盛グリッド
  geom_text(data = radian_lable_df, 
            mapping = aes(x = x, y = y, angle = t_deg+90), label = "|", 
            size = 2) + # 角度目盛指示線
  geom_text(data = radian_lable_df, 
            mapping = aes(x = label_x, y = label_y, label = rad_label, hjust = h, vjust = v), parse = TRUE) + # 角度目盛ラベル
  geom_hline(yintercept = 1, linetype = "dashed") + # csc直線用の補助線
  geom_point(data = point_df, 
             mapping = aes(x = cos_t, y = sin_t), 
             size = 4) + # 円周上の点
  geom_segment(data = radius_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                             size = width), 
               na.rm = TRUE) + # 半径直線
  geom_path(data = angle_mark_df, 
            mapping = aes(x = x, y = y), 
            size = 0.5) + # 角マーク
  geom_text(data = angle_label_df, 
            mapping = aes(x = x, y = y), label = "theta", parse = TRUE, 
            size = 5) + # 角ラベル
  geom_segment(data = function_line_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                             color = fnc, size = width, linetype = type), 
               na.rm = TRUE) + # 関数直線
  geom_text(data = function_label_df, 
            mapping = aes(x = x, y = y, label = fnc_label, color = fnc, 
                          hjust = h, vjust = v, angle = angle), 
            parse = TRUE, na.rm = TRUE, show.legend = FALSE) + # 関数ラベル
  scale_size_manual(breaks = c("normal", "bold", "thin"), 
                    values = c(1, 1.6, 0.8), guide = "none") + # (線が重なる対策)
  scale_linetype_manual(breaks = c("main", "sub"), 
                        values = c("solid", "twodash"), guide = "none") + # (補助線用)
  coord_fixed(ratio = 1, 
              xlim = c(-x_size, x_size), ylim = c(-y_size, y_size)) + # 描画領域
  labs(title = "circular functions", 
       subtitle = parse(text = variable_label), 
       color = "function", 
       x = "x", y = "y")

単位円上の点とcsc関数の関係

  \frac{\pi}{2} \lt \theta \lt \frac{3 \pi}{2} のとき  \cos \theta \lt 0 であり、 \cot \theta = \frac{\cos \theta}{\sin \theta} なので、原点と  (- \cot \theta, 1) を結ぶ線分の長さです。csc関数の符号はx軸の値の符号と対応します。

パターン3

 3つ目の方法では、円周上の点から伸びる直線としてcsc関数を可視化します。

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

 半径を示す線分を描画するためのデータフレームを作成します。

# 半径の線分の座標を格納
radius_df <- tibble::tibble(
  x_to = c(1, cos(theta)), 
  y_to = c(0, sin(theta))
)
radius_df
## # A tibble: 2 × 2
##    x_to  y_to
##   <dbl> <dbl>
## 1   1   0    
## 2   0.5 0.866

 原点と点  (1, 0) を結ぶ線分(x軸線の正の部分)と、原点と円周上の点  (\cos \theta, \sin \theta) を結ぶ線分を描画するために、2点の座標を格納します。原点の座標は、作図時に値を引数に指定します。

 三角関数を直線として描画するためのデータフレームを作成します。

# 関数直線の線分の座標を格納
function_line_df <- tibble::tibble(
  fnc = c("csc", "sin", "sin", "cos", "cos", "cot") |> 
    factor(levels = fnc_level_vec), # 色用
  x_from = c(
    0, 
    0, 0, 
    0, 0, 
    cos(theta)
  ), 
  y_from = c(
    0, 
    0, 0, 
    sin(theta), ifelse(sin(theta) >= 0, yes = 1, no = -1), 
    sin(theta)
  ), 
  x_to = c(
    0, 
    0, abs(sin(theta))*cos(theta), 
    cos(theta), abs(sin(theta))*cos(theta), 
    0
  ), 
  y_to = c(
    1/sin(theta), 
    sin(theta), abs(sin(theta))*sin(theta), 
    sin(theta), abs(sin(theta))*sin(theta), 
    1/sin(theta)
  ), 
  width = c("bold", "thin", "normal", "normal", "normal", "normal") # 太さ用
)
function_line_df
## # A tibble: 6 × 6
##   fnc   x_from y_from  x_to  y_to width 
##   <fct>  <dbl>  <dbl> <dbl> <dbl> <chr> 
## 1 csc      0    0     0     1.15  bold  
## 2 sin      0    0     0     0.866 thin  
## 3 sin      0    0     0.433 0.75  normal
## 4 cos      0    0.866 0.5   0.866 normal
## 5 cos      0    1     0.433 0.75  normal
## 6 cot      0.5  0.866 0     1.15  normal

 先ほどの様に、線分の座標を格納します。

 関数名をラベルとして描画するためのデータフレームを作成します。

# 関数ラベルの座標を格納
function_label_df <- tibble::tibble(
  fnc = c("csc", "sin", "cos", "cot") |> 
    factor(levels = fnc_level_vec), # 色用
  x = c(
    0, 
    0, 
    0.5 * cos(theta), 
    0.5 * cos(theta)
  ), 
  y = c(
    0.5 / sin(theta), 
    0.5 * sin(theta), 
    sin(theta), 
    0.5 * (1/sin(theta) + sin(theta))
  ), 
  angle = c(90, 90, 0, 0), 
  h = c(0.5, 0.5, 0.5, -0.2), 
  v = c(1, -0.5, 1, 0.5), 
  fnc_label = c("csc~theta", "sin~theta", "cos~theta", "cot~theta") # 関数ラベル
)
function_label_df
## # A tibble: 4 × 7
##   fnc       x     y angle     h     v fnc_label
##   <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>    
## 1 csc    0    0.577    90   0.5   1   csc~theta
## 2 sin    0    0.433    90   0.5  -0.5 sin~theta
## 3 cos    0.25 0.866     0   0.5   1   cos~theta
## 4 cot    0.25 1.01      0  -0.2   0.5 cot~theta

 線分の中点の座標とラベル用の文字列などを格納します。

 単位円上に三角関数の直線を重ねたグラフを作成します。

# グラフサイズ用の値を設定
x_size <- 1.3
y_min <- min(-x_size, 1/sin(theta))
y_max <- max(x_size, 1/sin(theta))

# 単位円上の三角関数直線を作図
ggplot() + 
  geom_path(data = circle_df, 
            mapping = aes(x = x, y = y), 
            size = 1) + # 円周
  geom_segment(data = radian_lable_df, 
               mapping = aes(x = 0, y = 0, xend = x, yend = y), 
               color = "white") + # 角度目盛グリッド
  geom_text(data = radian_lable_df, 
            mapping = aes(x = x, y = y, angle = t_deg+90), label = "|", 
            size = 2) + # 角度目盛指示線
  geom_text(data = radian_lable_df, 
            mapping = aes(x = label_x, y = label_y, label = rad_label, hjust = h, vjust = v), parse = TRUE) + # 角度目盛ラベル
  geom_vline(xintercept = 0, linetype = "dashed") + # csc直線用の補助線
  geom_point(data = point_df, 
             mapping = aes(x = cos_t, y = sin_t), 
             size = 4) + # 円周上の点
  geom_segment(data = radius_df, 
               mapping = aes(x = 0, y = 0, xend = x_to, yend = y_to), 
               size = 1) + # 半径直線
  geom_path(data = angle_mark_df, 
            mapping = aes(x = x, y = y), 
            size = 0.5) + # 角マーク
  geom_text(data = angle_label_df, 
            mapping = aes(x = x, y = y), label = "theta", parse = TRUE, 
            size = 5) + # 角ラベル
  geom_segment(data = function_line_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                             color = fnc, size = width)) + # 関数直線
  geom_text(data = function_label_df, 
            mapping = aes(x = x, y = y, label = fnc_label, color = fnc, 
                          hjust = h, vjust = v, angle = angle), parse = TRUE, show.legend = FALSE) + # 関数ラベル
  scale_size_manual(breaks = c("normal", "bold", "thin"), 
                    values = c(1, 1.6, 0.8), guide = "none") + # (線が重なる対策)
  coord_fixed(ratio = 1, 
              xlim = c(-x_size, x_size), ylim = c(y_min, y_max)) + # 描画領域
  labs(title = "circular functions", 
       subtitle = parse(text = variable_label), 
       color = "function", 
       x = "x", y = "y")

単位円上の点とcsc関数の関係

 こちらの図は、原点と点  (\cos \theta, \sin \theta) を結ぶ線分を底辺、y軸線の一部を斜辺としたときのパターン1の図と言えます。文字通り首を捻って見てください。
 csc関数の値は、「原点と点  (\cos \theta, \sin \theta) を通る直線」に対する「点  (\cos \theta, \sin \theta) を通る垂線」と「 x = 0 の直線(破線)」の交点  (\csc, 0) のy軸の値です。

アニメーションの作成

 続いて、変数の値を変化させたcsc関数をアニメーションで確認します。

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

 フレーム数を指定して、変数として用いる値を作成します。

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

# 変数の値を作成
theta_i <- seq(from = -2*pi, to = 2*pi, length.out = frame_num+1)[1:frame_num]
head(theta_i)
## [1] -6.283185 -6.199410 -6.115634 -6.031858 -5.948082 -5.864306

 フレーム数frame_numを指定して、円周上の点の座標計算に用いる変数(ラジアン)  \theta の値を等間隔にframe_num個作成します。範囲を  2 n \pi にしてframe_num + 1個の等間隔の値を作成して最後の値を除くと、最後のフレームと最初のフレームがスムーズに繋がります。

 フレーム切替用のラベルとして用いる文字列ベクトルを作成します。

# 変数ラベル用の文字列を作成
frame_label_vec <- paste0(
  "θ = ", round(theta_i/pi, digits = 2), " π", 
  ", csc θ = ", round(1/cos(theta_i), digits = 2), 
  ", sin θ = ", round(sin(theta_i), digits = 2), 
  ", cos θ = ", round(cos(theta_i), digits = 2), 
  ", cot θ = ", round(1/tan(theta_i), digits = 2)
)
head(frame_label_vec)
## [1] "θ = -2 π, csc θ = 1, sin θ = 0, cos θ = 1, cot θ = 4082809838298843"
## [2] "θ = -1.97 π, csc θ = 1, sin θ = 0.08, cos θ = 1, cot θ = 11.91"     
## [3] "θ = -1.95 π, csc θ = 1.01, sin θ = 0.17, cos θ = 0.99, cot θ = 5.91"
## [4] "θ = -1.92 π, csc θ = 1.03, sin θ = 0.25, cos θ = 0.97, cot θ = 3.89"
## [5] "θ = -1.89 π, csc θ = 1.06, sin θ = 0.33, cos θ = 0.94, cot θ = 2.87"
## [6] "θ = -1.87 π, csc θ = 1.09, sin θ = 0.41, cos θ = 0.91, cot θ = 2.25"

 この例では、フレームごとの変数と関数の値をグラフに表示するために、theta_iを用いた文字列をフレーム切替用のラベル列として使います。フレーム番号として、通し番号を用いても作図できます。

 円周上の点を描画するためのデータフレームを作成します。

# 曲線上の点の描画用
anim_point_df <- tibble::tibble(
  t = theta_i, 
  sin_t = sin(theta_i), 
  cos_t = cos(theta_i), 
  frame_label = factor(frame_label_vec, levels = frame_label_vec) # フレーム切替用ラベル
)
anim_point_df
## # A tibble: 150 × 4
##        t    sin_t cos_t frame_label                                        
##    <dbl>    <dbl> <dbl> <fct>                                              
##  1 -6.28 2.45e-16 1     θ = -2 π, csc θ = 1, sin θ = 0, cos θ = 1, cot θ … 
##  2 -6.20 8.37e- 2 0.996 θ = -1.97 π, csc θ = 1, sin θ = 0.08, cos θ = 1, c…
##  3 -6.12 1.67e- 1 0.986 θ = -1.95 π, csc θ = 1.01, sin θ = 0.17, cos θ = 0…
##  4 -6.03 2.49e- 1 0.969 θ = -1.92 π, csc θ = 1.03, sin θ = 0.25, cos θ = 0…
##  5 -5.95 3.29e- 1 0.944 θ = -1.89 π, csc θ = 1.06, sin θ = 0.33, cos θ = 0…
##  6 -5.86 4.07e- 1 0.914 θ = -1.87 π, csc θ = 1.09, sin θ = 0.41, cos θ = 0…
##  7 -5.78 4.82e- 1 0.876 θ = -1.84 π, csc θ = 1.14, sin θ = 0.48, cos θ = 0…
##  8 -5.70 5.53e- 1 0.833 θ = -1.81 π, csc θ = 1.2, sin θ = 0.55, cos θ = 0.…
##  9 -5.61 6.21e- 1 0.784 θ = -1.79 π, csc θ = 1.28, sin θ = 0.62, cos θ = 0…
## 10 -5.53 6.85e- 1 0.729 θ = -1.76 π, csc θ = 1.37, sin θ = 0.68, cos θ = 0…
## # … with 140 more rows

  \theta の値と  \sin \theta, \cos \theta の値をフレーム切替用のラベルとあわせて格納します。

 角マークを描画するためのデータフレームを作成します。

# フレームごとの角マークの座標を計算
d <- 0.15
anim_angle_mark_df <- tibble::tibble(
  frame_i = 1:frame_num, # フレーム番号
  frame_label = factor(frame_label_vec, levels = frame_label_vec), # フレーム切替用ラベル
) |> 
  dplyr::group_by(frame_i, frame_label) |> # ラジアンの作成用
  dplyr::summarise(
    t = seq(from = 0, to = theta_i[frame_i], length.out = 100), .groups = "drop"
  ) |> # なす角以下のラジアンを作成
  dplyr::mutate(
    x = d * cos(t), 
    y = d * sin(t)
  )
anim_angle_mark_df
## # A tibble: 15,000 × 5
##    frame_i frame_label                                     t     x        y
##      <int> <fct>                                       <dbl> <dbl>    <dbl>
##  1       1 θ = -2 π, csc θ = 1, sin θ = 0, cos θ = …  0      0.15   0      
##  2       1 θ = -2 π, csc θ = 1, sin θ = 0, cos θ = … -0.0635 0.150 -0.00951
##  3       1 θ = -2 π, csc θ = 1, sin θ = 0, cos θ = … -0.127  0.149 -0.0190 
##  4       1 θ = -2 π, csc θ = 1, sin θ = 0, cos θ = … -0.190  0.147 -0.0284 
##  5       1 θ = -2 π, csc θ = 1, sin θ = 0, cos θ = … -0.254  0.145 -0.0377 
##  6       1 θ = -2 π, csc θ = 1, sin θ = 0, cos θ = … -0.317  0.143 -0.0468 
##  7       1 θ = -2 π, csc θ = 1, sin θ = 0, cos θ = … -0.381  0.139 -0.0557 
##  8       1 θ = -2 π, csc θ = 1, sin θ = 0, cos θ = … -0.444  0.135 -0.0645 
##  9       1 θ = -2 π, csc θ = 1, sin θ = 0, cos θ = … -0.508  0.131 -0.0729 
## 10       1 θ = -2 π, csc θ = 1, sin θ = 0, cos θ = … -0.571  0.126 -0.0811 
## # … with 14,990 more rows

 フレーム列でグループ化してフレーム(変数の値)ごとに、summarise()を使って0から各フレームの角度theta_n[frame_i]までの値を作成して、円弧の座標を計算します。

 角ラベルを描画するためのデータフレームを作成します。

# フレームごとの角ラベルの座標を計算
d <- 0.21
anim_angle_label_df <- tibble::tibble(
  frame_i = 1:frame_num, # フレーム番号
  t = 0.5 * theta_i, 
  x = d * cos(t), 
  y = d * sin(t), 
  frame_label = factor(frame_label_vec, levels = frame_label_vec) # フレーム切替用ラベル
)
anim_angle_label_df
## # A tibble: 150 × 5
##    frame_i     t      x         y frame_label                               
##      <int> <dbl>  <dbl>     <dbl> <fct>                                     
##  1       1 -3.14 -0.21  -2.57e-17 θ = -2 π, csc θ = 1, sin θ = 0, cos θ = … 
##  2       2 -3.10 -0.210 -8.79e- 3 θ = -1.97 π, csc θ = 1, sin θ = 0.08, cos…
##  3       3 -3.06 -0.209 -1.76e- 2 θ = -1.95 π, csc θ = 1.01, sin θ = 0.17, …
##  4       4 -3.02 -0.208 -2.63e- 2 θ = -1.92 π, csc θ = 1.03, sin θ = 0.25, …
##  5       5 -2.97 -0.207 -3.50e- 2 θ = -1.89 π, csc θ = 1.06, sin θ = 0.33, …
##  6       6 -2.93 -0.205 -4.37e- 2 θ = -1.87 π, csc θ = 1.09, sin θ = 0.41, …
##  7       7 -2.89 -0.203 -5.22e- 2 θ = -1.84 π, csc θ = 1.14, sin θ = 0.48, …
##  8       8 -2.85 -0.201 -6.07e- 2 θ = -1.81 π, csc θ = 1.2, sin θ = 0.55, c…
##  9       9 -2.81 -0.198 -6.91e- 2 θ = -1.79 π, csc θ = 1.28, sin θ = 0.62, …
## 10      10 -2.76 -0.195 -7.73e- 2 θ = -1.76 π, csc θ = 1.37, sin θ = 0.68, …
## # … with 140 more rows

 フレームごとの角マークの中点に角ラベルを配置するために、 \frac{\theta}{2} のラジアンを作成して、円弧上の点の座標を計算します。

 ここまでは、共通の処理です。ここからは、「グラフの作成」のときと同様に3つの方法で図示します。

パターン1

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

 半径を示す線分を描画するためのデータフレームを作成します。

# 半径の線分の座標を格納
anim_radius_df <- tibble::tibble(
  x_from = c(
    rep(0, times = frame_num), 
    rep(0, times = frame_num), 
    1/tan(theta_i)
  ), 
  y_from = c(
    rep(0, times = frame_num), 
    rep(0, times = frame_num), 
    rep(0, times = frame_num)
  ), 
  x_to = c(
    rep(1, times = frame_num), 
    cos(theta_i), 
    1/tan(theta_i)
  ), 
  y_to =  c(
    rep(0, times = frame_num), 
    sin(theta_i), 
    rep(1, times = frame_num)
  ), 
  type = c("normal", "normal", "thin") |> 
    rep(each = frame_num), # 太さ用
  frame_label = frame_label_vec |> 
    rep(times = 3) |> # (3は線分の数)
    factor(levels = frame_label_vec) # フレーム切替用ラベル
) |> 
  dplyr::mutate(
    x_from = dplyr::if_else(condition = is.infinite(x_from), true = NA_real_, false = x_from), 
    x_to   = dplyr::if_else(condition = is.infinite(x_to), true = NA_real_, false = x_to)
  ) # 発散した場合は欠損値に置換
anim_radius_df
## # A tibble: 450 × 6
##    x_from y_from  x_to  y_to type   frame_label                             
##     <dbl>  <dbl> <dbl> <dbl> <chr>  <fct>                                   
##  1      0      0     1     0 normal θ = -2 π, csc θ = 1, sin θ = 0, cos θ … 
##  2      0      0     1     0 normal θ = -1.97 π, csc θ = 1, sin θ = 0.08, c…
##  3      0      0     1     0 normal θ = -1.95 π, csc θ = 1.01, sin θ = 0.17…
##  4      0      0     1     0 normal θ = -1.92 π, csc θ = 1.03, sin θ = 0.25…
##  5      0      0     1     0 normal θ = -1.89 π, csc θ = 1.06, sin θ = 0.33…
##  6      0      0     1     0 normal θ = -1.87 π, csc θ = 1.09, sin θ = 0.41…
##  7      0      0     1     0 normal θ = -1.84 π, csc θ = 1.14, sin θ = 0.48…
##  8      0      0     1     0 normal θ = -1.81 π, csc θ = 1.2, sin θ = 0.55,…
##  9      0      0     1     0 normal θ = -1.79 π, csc θ = 1.28, sin θ = 0.62…
## 10      0      0     1     0 normal θ = -1.76 π, csc θ = 1.37, sin θ = 0.68…
## # … with 440 more rows

 「グラフの作成」のときと同様に、フレーム数分の原点と点  (0, 1) の座標と、フレームごとの点  (\cos \theta, \sin \theta) の座標、また補助線用の線分の座標を格納します。

 三角関数を直線として描画するためのデータフレームを作成します。

# 関数ラベルのレベルを指定
fnc_level_vec <- c("csc", "sin", "cos", "cot")

# 関数直線の線分の座標を格納
anim_function_line_df <- tibble::tibble(
  fnc = c("csc", "sin", "cos", "cot") |> 
    rep(each = frame_num) |> 
    factor(levels = fnc_level_vec), # 色用
  x_from = c(
    rep(0, times = frame_num), 
    cos(theta_i), 
    rep(0, times = frame_num), 
    rep(0, times = frame_num)
  ), 
  y_from = c(
    rep(0, times = frame_num), 
    rep(0, times = frame_num), 
    rep(0, times = frame_num), 
    rep(0, times = frame_num)
  ), 
  x_to = c(
    1/tan(theta_i), 
    cos(theta_i), 
    cos(theta_i), 
    1/tan(theta_i)
  ), 
  y_to = c(
    rep(1, times = frame_num), 
    sin(theta_i), 
    rep(0, times = frame_num), 
    rep(0, times = frame_num)
  ), 
  type = c("normal", "normal", "bold", "thin") |> 
    rep(each = frame_num), # 太さ用
  frame_label = frame_label_vec |> 
    rep(times = 4) |> # (4は線分の数)
    factor(levels = frame_label_vec) # フレーム切替用ラベル
) |> 
  dplyr::mutate(
    x_to = dplyr::if_else(condition = is.infinite(x_to), true = NA_real_, false = x_to)
  ) # 発散した場合は欠損値に置換
anim_function_line_df
## # A tibble: 600 × 7
##    fnc   x_from y_from    x_to  y_to type   frame_label                     
##    <fct>  <dbl>  <dbl>   <dbl> <dbl> <chr>  <fct>                           
##  1 csc        0      0 4.08e15     1 normal θ = -2 π, csc θ = 1, sin θ = 0,…
##  2 csc        0      0 1.19e 1     1 normal θ = -1.97 π, csc θ = 1, sin θ =…
##  3 csc        0      0 5.91e 0     1 normal θ = -1.95 π, csc θ = 1.01, sin …
##  4 csc        0      0 3.89e 0     1 normal θ = -1.92 π, csc θ = 1.03, sin …
##  5 csc        0      0 2.87e 0     1 normal θ = -1.89 π, csc θ = 1.06, sin …
##  6 csc        0      0 2.25e 0     1 normal θ = -1.87 π, csc θ = 1.09, sin …
##  7 csc        0      0 1.82e 0     1 normal θ = -1.84 π, csc θ = 1.14, sin …
##  8 csc        0      0 1.51e 0     1 normal θ = -1.81 π, csc θ = 1.2, sin θ…
##  9 csc        0      0 1.26e 0     1 normal θ = -1.79 π, csc θ = 1.28, sin …
## 10 csc        0      0 1.06e 0     1 normal θ = -1.76 π, csc θ = 1.37, sin …
## # … with 590 more rows

 線分ごとにframe_num個の座標を格納します。

 関数名をラベルとして描画するためのデータフレームを作成します。

# 関数ラベルの座標を計算
anim_function_label_df <- anim_function_line_df |> 
  dplyr::group_by(fnc, frame_label) |> # 中点の計算用
  dplyr::summarise(
    x = median(c(x_from, x_to)), 
    y = median(c(y_from, y_to)), .groups = "drop"
  ) |> # 線分の中点に配置
  tibble::add_column(
    angle = c(0, 90, 0, 0) |> 
      rep(each = frame_num), 
    h = c(1.1, 0.5, 0.5, 0.5) |> 
      rep(each = frame_num), 
    v = c(0.5, -0.5, -0.5, 1) |> 
      rep(each = frame_num), 
    fnc_label = c(
      ifelse(test = cos(theta_i) >= 0, yes = "csc~theta", no = "-csc~theta"), 
      rep("sin~theta", times = frame_num), 
      rep("cos~theta", times = frame_num), 
      rep("cot~theta", times = frame_num)
    ) # 関数ラベル
  )
anim_function_label_df
## # A tibble: 600 × 8
##    fnc   frame_label                      x     y angle     h     v fnc_label
##    <fct> <fct>                        <dbl> <dbl> <dbl> <dbl> <dbl> <chr>    
##  1 csc   θ = -2 π, csc θ = 1, sin… 2.04e+15   0.5     0   1.1   0.5 csc~theta
##  2 csc   θ = -1.97 π, csc θ = 1, … 5.95e+ 0   0.5     0   1.1   0.5 csc~theta
##  3 csc   θ = -1.95 π, csc θ = 1.0… 2.96e+ 0   0.5     0   1.1   0.5 csc~theta
##  4 csc   θ = -1.92 π, csc θ = 1.0… 1.95e+ 0   0.5     0   1.1   0.5 csc~theta
##  5 csc   θ = -1.89 π, csc θ = 1.0… 1.44e+ 0   0.5     0   1.1   0.5 csc~theta
##  6 csc   θ = -1.87 π, csc θ = 1.0… 1.12e+ 0   0.5     0   1.1   0.5 csc~theta
##  7 csc   θ = -1.84 π, csc θ = 1.1… 9.09e- 1   0.5     0   1.1   0.5 csc~theta
##  8 csc   θ = -1.81 π, csc θ = 1.2… 7.53e- 1   0.5     0   1.1   0.5 csc~theta
##  9 csc   θ = -1.79 π, csc θ = 1.2… 6.31e- 1   0.5     0   1.1   0.5 csc~theta
## 10 csc   θ = -1.76 π, csc θ = 1.3… 5.32e- 1   0.5     0   1.1   0.5 csc~theta
## # … with 590 more rows

 anim_function_line_dfからlabel_flag列がTRUEの行(線分)を取り出して、fnc, frame_label列でグループ化して関数(線分)とフレームごとに、中点の座標をmedian()で計算します。
 また、ラベル用の文字列などの列を追加します。

 単位円上に三角関数の直線を重ねたアニメーションを作成します。

# グラフサイズ用の値を指定
x_size <- 2
y_size <- 1.3

# 単位円上の三角関数直線のアニメーションを作図
anim <- ggplot() + 
  geom_path(data = circle_df, 
            mapping = aes(x = x, y = y), 
            size = 1) + # 円周
  geom_segment(data = radian_lable_df, 
               mapping = aes(x = 0, y = 0, xend = x, yend = y), 
               color = "white") + # 角度目盛グリッド
  geom_text(data = radian_lable_df, 
            mapping = aes(x = x, y = y, angle = t_deg+90), label = "|", 
            size = 2) + # 角度目盛指示線
  geom_text(data = radian_lable_df, 
            mapping = aes(x = label_x, y = label_y, label = rad_label, hjust = h, vjust = v), parse = TRUE) + # 角度目盛ラベル
  geom_hline(yintercept = 1, linetype = "dashed") + # csc直線用の補助線
  geom_point(data = anim_point_df, 
             mapping = aes(x = cos_t, y = sin_t), 
             size = 4) + # 円周上の点
  geom_segment(data = anim_radius_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                             size = type), na.rm = TRUE) + # 半径直線
  geom_path(data = anim_angle_mark_df, 
            mapping = aes(x = x, y = y), 
            size = 0.5) + # 角マーク
  geom_text(data = anim_angle_label_df, 
            mapping = aes(x = x, y = y), label = "theta", parse = TRUE, na.rm = TRUE, 
            size = 5) + # 角ラベル
  geom_segment(data = anim_function_line_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                             color = fnc, size = type), na.rm = TRUE) + # 関数直線
  geom_text(data = anim_function_label_df, 
            mapping = aes(x = x, y = y, label = fnc_label, color = fnc, 
                          hjust = h, vjust = v, angle = angle), 
            parse = TRUE, na.rm = TRUE, show.legend = FALSE) + # 関数ラベル
  gganimate::transition_manual(frames = frame_label) + # フレーム
  scale_size_manual(breaks = c("normal", "bold", "thin"), 
                    values = c(1, 1.6, 0.8), guide = "none") + # (線が重なる対策)
  coord_fixed(ratio = 1, 
              xlim = c(-x_size, x_size), ylim = c(-y_size, y_size)) + # 描画領域
  labs(title = "circular functions", 
       subtitle = "{current_frame}", 
       color = "function", 
       x = "x", y = "y")

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

 gganimateパッケージを利用して、アニメーション(gif画像)を作成します。
 transition_manual()のフレーム制御の引数framesにフレーム(変数)ラベル列frame_labelを指定して、グラフを作成します。
 animate()plot引数にグラフオブジェクト、nframes引数にフレーム数frame_numを指定して、gif画像を作成します。また、fps引数に1秒当たりのフレーム数を指定できます。

単位円におけるなす角とcsc関数の関係

  \theta = 0, \pi のとき  \sin \theta = 0 なので、原点と円周上の点を結ぶ線分が水平になり直線  y = 1 と平行なため交点ができず、 \csc \theta を描画(定義)できないのが分かります。

パターン2

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

 半径を示す線分を描画するためのデータフレームを作成します。

# 変換フラグを設定
cos_flg_i <- cos(theta_i) >= 0

# 半径の線分の座標を格納
anim_radius_df <- tibble::tibble(
  x_from = c(
    rep(0, times = frame_num), rep(0, times = frame_num), 
    1/tan(theta_i), ifelse(test = cos_flg_i, yes = NA, no = -1/tan(theta_i))
  ), 
  y_from = c(
    rep(0, times = frame_num), rep(0, times = frame_num), 
    rep(0, times = frame_num), ifelse(test = cos_flg_i, yes = NA, no = 0)
  ), 
  x_to = c(
    rep(1, times = frame_num), cos(theta_i), 
    1/tan(theta_i), ifelse(test = cos_flg_i, yes = NA, no = -1/tan(theta_i))
  ), 
  y_to =  c(
    rep(0, times = frame_num), sin(theta_i), 
    rep(1, times = frame_num), ifelse(test = cos_flg_i, yes = NA, no = 1)
  ), 
  width = c("normal", "normal", "thin", "thin") |> 
    rep(each = frame_num), # 太さ用
  frame_label = frame_label_vec |> 
    rep(times = 4) |> # (4は線分の数)
    factor(levels = frame_label_vec) # フレーム切替用ラベル
) |> 
  dplyr::mutate(
    x_from = dplyr::if_else(condition = is.infinite(x_from), true = NA_real_, false = x_from), 
    x_to   = dplyr::if_else(condition = is.infinite(x_to), true = NA_real_, false = x_to)
  ) # 発散した場合は欠損値に置換
anim_radius_df
## # A tibble: 600 × 6
##    x_from y_from  x_to  y_to width  frame_label                             
##     <dbl>  <dbl> <dbl> <dbl> <chr>  <fct>                                   
##  1      0      0     1     0 normal θ = -2 π, csc θ = 1, sin θ = 0, cos θ … 
##  2      0      0     1     0 normal θ = -1.97 π, csc θ = 1, sin θ = 0.08, c…
##  3      0      0     1     0 normal θ = -1.95 π, csc θ = 1.01, sin θ = 0.17…
##  4      0      0     1     0 normal θ = -1.92 π, csc θ = 1.03, sin θ = 0.25…
##  5      0      0     1     0 normal θ = -1.89 π, csc θ = 1.06, sin θ = 0.33…
##  6      0      0     1     0 normal θ = -1.87 π, csc θ = 1.09, sin θ = 0.41…
##  7      0      0     1     0 normal θ = -1.84 π, csc θ = 1.14, sin θ = 0.48…
##  8      0      0     1     0 normal θ = -1.81 π, csc θ = 1.2, sin θ = 0.55,…
##  9      0      0     1     0 normal θ = -1.79 π, csc θ = 1.28, sin θ = 0.62…
## 10      0      0     1     0 normal θ = -1.76 π, csc θ = 1.37, sin θ = 0.68…
## # … with 590 more rows

 「グラフの作成」のときと同様に、フレーム数分の原点と点  (0, 1) の座標と、フレームごとの点  (\cos \theta, \sin \theta) の座標、また補助線用の線分の座標を格納します。

 三角関数を直線として描画するためのデータフレームを作成します。

# 関数直線の線分の座標を格納
anim_function_line_df <- tibble::tibble(
  fnc = c(
    "csc", "csc", 
    "sin", 
    "cos", 
    "cot", "cot"
  ) |> 
    rep(each = frame_num) |> 
    factor(levels = fnc_level_vec), # 色用
  x_from = c(
    rep(0, times = frame_num), ifelse(test = cos_flg_i, yes = NA, no = 0), 
    cos(theta_i), 
    rep(0, times = frame_num), 
    rep(0, times = frame_num), ifelse(test = cos_flg_i, yes = NA, no = 0)
  ), 
  y_from = c(
    rep(0, times = frame_num), ifelse(test = cos_flg_i, yes = NA, no = 0), 
    rep(0, times = frame_num), 
    rep(0, times = frame_num), 
    rep(0, times = frame_num), ifelse(test = cos_flg_i, yes = NA, no = 0)
  ), 
  x_to = c(
    ifelse(test = cos_flg_i, yes = 1/tan(theta_i), no = -1/tan(theta_i)), ifelse(test = cos_flg_i, yes = NA, no = 1/tan(theta_i)), 
    cos(theta_i), 
    cos(theta_i), 
    1/tan(theta_i), ifelse(test = cos_flg_i, yes = NA, no = -1/tan(theta_i))
  ), 
  y_to = c(
    rep(1, times = frame_num), ifelse(test = cos_flg_i, yes = NA, no = 1), 
    sin(theta_i), 
    rep(0, times = frame_num), 
    rep(0, times = frame_num), ifelse(test = cos_flg_i, yes = NA, no = 0)
  ), 
  type = c(
    "main", "sub", 
    "main", 
    "main", 
    "main", "sub"
  ) |> 
    rep(each = frame_num), # 線タイプ用
  width = c(
    "normal", "normal", 
    "normal", 
    "bold", 
    "thin", "thin"
  ) |> 
    rep(each = frame_num), # 太さ用
  frame_label = frame_label_vec |> 
    rep(times = 6) |> # (6は線分の数)
    factor(levels = frame_label_vec) # フレーム切替用ラベル
) |> 
  dplyr::mutate(
    x_to   = dplyr::if_else(condition = is.infinite(x_to), true = NA_real_, false = x_to)
  ) # 発散した場合は欠損値に置換
anim_function_line_df
## # A tibble: 900 × 8
##    fnc   x_from y_from    x_to  y_to type  width  frame_label                
##    <fct>  <dbl>  <dbl>   <dbl> <dbl> <chr> <chr>  <fct>                      
##  1 csc        0      0 4.08e15     1 main  normal θ = -2 π, csc θ = 1, sin … 
##  2 csc        0      0 1.19e 1     1 main  normal θ = -1.97 π, csc θ = 1, si…
##  3 csc        0      0 5.91e 0     1 main  normal θ = -1.95 π, csc θ = 1.01,…
##  4 csc        0      0 3.89e 0     1 main  normal θ = -1.92 π, csc θ = 1.03,…
##  5 csc        0      0 2.87e 0     1 main  normal θ = -1.89 π, csc θ = 1.06,…
##  6 csc        0      0 2.25e 0     1 main  normal θ = -1.87 π, csc θ = 1.09,…
##  7 csc        0      0 1.82e 0     1 main  normal θ = -1.84 π, csc θ = 1.14,…
##  8 csc        0      0 1.51e 0     1 main  normal θ = -1.81 π, csc θ = 1.2, …
##  9 csc        0      0 1.26e 0     1 main  normal θ = -1.79 π, csc θ = 1.28,…
## 10 csc        0      0 1.06e 0     1 main  normal θ = -1.76 π, csc θ = 1.37,…
## # … with 890 more rows

 線分ごとにframe_num個の座標を格納します。

 関数名をラベルとして描画するためのデータフレームを作成します。

# 関数ラベルの座標を計算
anim_function_label_df <- anim_function_line_df |> 
  dplyr::filter(type == "main") |> # ラベル付けする線分を抽出
  dplyr::group_by(fnc, frame_label) |> # 中点の計算用
  dplyr::summarise(
    x = median(c(x_from, x_to)), 
    y = median(c(y_from, y_to)), .groups = "drop"
  ) |> # 線分の中点に配置
  tibble::add_column(
    angle = c(0, 90, 0, 0) |> 
      rep(each = frame_num), 
    h = c(1.1, 0.5, 0.5, 0.5) |> 
      rep(each = frame_num), 
    v = c(0.5, -0.5, -0.5, 1) |> 
      rep(each = frame_num), 
    fnc_label = c("csc~theta", "sin~theta", "cos~theta", "cot~theta") |> 
      rep(each = frame_num) # 関数ラベル
  )
anim_function_label_df
## # A tibble: 600 × 8
##    fnc   frame_label                      x     y angle     h     v fnc_label
##    <fct> <fct>                        <dbl> <dbl> <dbl> <dbl> <dbl> <chr>    
##  1 csc   θ = -2 π, csc θ = 1, sin… 2.04e+15   0.5     0   1.1   0.5 csc~theta
##  2 csc   θ = -1.97 π, csc θ = 1, … 5.95e+ 0   0.5     0   1.1   0.5 csc~theta
##  3 csc   θ = -1.95 π, csc θ = 1.0… 2.96e+ 0   0.5     0   1.1   0.5 csc~theta
##  4 csc   θ = -1.92 π, csc θ = 1.0… 1.95e+ 0   0.5     0   1.1   0.5 csc~theta
##  5 csc   θ = -1.89 π, csc θ = 1.0… 1.44e+ 0   0.5     0   1.1   0.5 csc~theta
##  6 csc   θ = -1.87 π, csc θ = 1.0… 1.12e+ 0   0.5     0   1.1   0.5 csc~theta
##  7 csc   θ = -1.84 π, csc θ = 1.1… 9.09e- 1   0.5     0   1.1   0.5 csc~theta
##  8 csc   θ = -1.81 π, csc θ = 1.2… 7.53e- 1   0.5     0   1.1   0.5 csc~theta
##  9 csc   θ = -1.79 π, csc θ = 1.2… 6.31e- 1   0.5     0   1.1   0.5 csc~theta
## 10 csc   θ = -1.76 π, csc θ = 1.3… 5.32e- 1   0.5     0   1.1   0.5 csc~theta
## # … with 590 more rows

 線分の中点の座標とラベル用の文字列などを格納します。

 単位円上に三角関数の直線を重ねたアニメーションを作成します。

# グラフサイズ用の値を指定
x_size <- 2
y_size <- 1.3

# 単位円上の三角関数直線のアニメーションを作図
anim <- ggplot() + 
  geom_path(data = circle_df, 
            mapping = aes(x = x, y = y), 
            size = 1) + # 円周
  geom_segment(data = radian_lable_df, 
               mapping = aes(x = 0, y = 0, xend = x, yend = y), 
               color = "white") + # 角度目盛グリッド
  geom_text(data = radian_lable_df, 
            mapping = aes(x = x, y = y, angle = t_deg+90), label = "|", 
            size = 2) + # 角度目盛指示線
  geom_text(data = radian_lable_df, 
            mapping = aes(x = label_x, y = label_y, label = rad_label, hjust = h, vjust = v), parse = TRUE) + # 角度目盛ラベル
  geom_hline(yintercept = 1, linetype = "dashed") + # csc直線用の補助線
  geom_point(data = anim_point_df, 
             mapping = aes(x = cos_t, y = sin_t), 
             size = 4) + # 円周上の点
  geom_segment(data = anim_radius_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                             size = width), na.rm = TRUE) + # 半径直線
  geom_path(data = anim_angle_mark_df, 
            mapping = aes(x = x, y = y), 
            size = 0.5) + # 角マーク
  geom_text(data = anim_angle_label_df, 
            mapping = aes(x = x, y = y), label = "theta", parse = TRUE, 
            size = 5) + # 角ラベル
  geom_segment(data = anim_function_line_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                             color = fnc, size = width, linetype = type), 
               na.rm = TRUE) + # 関数直線
  geom_text(data = anim_function_label_df, 
            mapping = aes(x = x, y = y, label = fnc_label, color = fnc, 
                          hjust = h, vjust = v, angle = angle), 
            parse = TRUE, na.rm = TRUE, show.legend = FALSE) + # 関数ラベル
  gganimate::transition_manual(frames = frame_label) + # フレーム
  scale_size_manual(breaks = c("normal", "bold", "thin"), 
                    values = c(1, 1.6, 0.8), guide = "none") + # (線が重なる対策)
  scale_linetype_manual(breaks = c("main", "sub"), 
                        values = c("solid", "twodash"), guide = "none") + # (補助線用)
  coord_fixed(ratio = 1, 
              xlim = c(-x_size, x_size), ylim = c(-y_size, y_size)) + # 描画領域
  labs(title = "circular functions", 
       subtitle = "{current_frame}", 
       color = "function", 
       x = "x", y = "y")

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

単位円におけるなす角とcsc関数の関係


パターン3

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

 半径を示す線分を描画するためのデータフレームを作成します。

# 半径の線分の座標を格納
anim_radius_df <- tibble::tibble(
  x_to = c(
    rep(1, times = frame_num), 
    cos(theta_i)
  ), 
  y_to =  c(
    rep(0, times = frame_num), 
    sin(theta_i)
  ), 
  frame_label = frame_label_vec |> 
    rep(times = 2) |> # (2は線分の数)
    factor(levels = frame_label_vec) # フレーム切替用ラベル
)
anim_radius_df
## # A tibble: 300 × 3
##     x_to  y_to frame_label                                                   
##    <dbl> <dbl> <fct>                                                         
##  1     1     0 θ = -2 π, csc θ = 1, sin θ = 0, cos θ = 1, cot θ = 4082809…   
##  2     1     0 θ = -1.97 π, csc θ = 1, sin θ = 0.08, cos θ = 1, cot θ = 11.91
##  3     1     0 θ = -1.95 π, csc θ = 1.01, sin θ = 0.17, cos θ = 0.99, cot …  
##  4     1     0 θ = -1.92 π, csc θ = 1.03, sin θ = 0.25, cos θ = 0.97, cot …  
##  5     1     0 θ = -1.89 π, csc θ = 1.06, sin θ = 0.33, cos θ = 0.94, cot …  
##  6     1     0 θ = -1.87 π, csc θ = 1.09, sin θ = 0.41, cos θ = 0.91, cot …  
##  7     1     0 θ = -1.84 π, csc θ = 1.14, sin θ = 0.48, cos θ = 0.88, cot …  
##  8     1     0 θ = -1.81 π, csc θ = 1.2, sin θ = 0.55, cos θ = 0.83, cot …   
##  9     1     0 θ = -1.79 π, csc θ = 1.28, sin θ = 0.62, cos θ = 0.78, cot …  
## 10     1     0 θ = -1.76 π, csc θ = 1.37, sin θ = 0.68, cos θ = 0.73, cot …  
## # … with 290 more rows

 フレーム数分の点  (0, 1) の座標と、フレームごとの点  (\cos \theta, \sin \theta) の座標を格納します。

 三角関数を直線として描画するためのデータフレームを作成します。

# 関数直線の線分の座標を格納
anim_function_line_df <- tibble::tibble(
  fnc = c("csc", "sin", "sin", "cos", "cos", "cot") |> 
    rep(each = frame_num) |> 
    factor(levels = fnc_level_vec), # 色用
  x_from = c(
    rep(0, times = frame_num), 
    rep(0, times = frame_num), rep(0, times = frame_num), 
    rep(0, times = frame_num), rep(0, times = frame_num), 
    cos(theta_i)
  ), 
  y_from = c(
    rep(0, times = frame_num), 
    rep(0, times = frame_num), rep(0, times = frame_num), 
    sin(theta_i), ifelse(sin(theta_i) >= 0, yes = 1, no = -1), 
    sin(theta_i)
  ), 
  x_to = c(
    rep(0, times = frame_num), 
    rep(0, times = frame_num), abs(sin(theta_i))*cos(theta_i), 
    cos(theta_i), abs(sin(theta_i))*cos(theta_i), 
    rep(0, times = frame_num)
  ), 
  y_to = c(
    1/sin(theta_i), 
    sin(theta_i), abs(sin(theta_i))*sin(theta_i), 
    sin(theta_i), abs(sin(theta_i))*sin(theta_i), 
    1/sin(theta_i)
  ), 
  type = c("bold", "thin", "normal", "normal", "normal", "normal") |> 
    rep(each = frame_num), # 太さ用
  label_flag = c(TRUE, TRUE, FALSE, TRUE, FALSE, TRUE) |> 
    rep(each = frame_num), # # 関数ラベル用
  frame_label = frame_label_vec |> 
    rep(times = 6) |> # (6は線分の数)
    factor(levels = frame_label_vec) # フレーム切替用ラベル
)
anim_function_line_df
## # A tibble: 900 × 8
##    fnc   x_from y_from  x_to    y_to type  label_flag frame_label            
##    <fct>  <dbl>  <dbl> <dbl>   <dbl> <chr> <lgl>      <fct>                  
##  1 csc        0      0     0 4.08e15 bold  TRUE       θ = -2 π, csc θ = 1, s…
##  2 csc        0      0     0 1.20e 1 bold  TRUE       θ = -1.97 π, csc θ = 1…
##  3 csc        0      0     0 6.00e 0 bold  TRUE       θ = -1.95 π, csc θ = 1…
##  4 csc        0      0     0 4.02e 0 bold  TRUE       θ = -1.92 π, csc θ = 1…
##  5 csc        0      0     0 3.04e 0 bold  TRUE       θ = -1.89 π, csc θ = 1…
##  6 csc        0      0     0 2.46e 0 bold  TRUE       θ = -1.87 π, csc θ = 1…
##  7 csc        0      0     0 2.08e 0 bold  TRUE       θ = -1.84 π, csc θ = 1…
##  8 csc        0      0     0 1.81e 0 bold  TRUE       θ = -1.81 π, csc θ = 1…
##  9 csc        0      0     0 1.61e 0 bold  TRUE       θ = -1.79 π, csc θ = 1…
## 10 csc        0      0     0 1.46e 0 bold  TRUE       θ = -1.76 π, csc θ = 1…
## # … with 890 more rows

 先ほどと同様に、線分の座標を格納します。

 関数名をラベルとして描画するためのデータフレームを作成します。

# 関数ラベルの座標を計算
anim_function_label_df <- anim_function_line_df |> 
  dplyr::filter(label_flag) |> # ラベル付けする線分を抽出
  dplyr::group_by(fnc, frame_label) |> # 中点の計算用
  dplyr::summarise(
    x = median(c(x_from, x_to)), 
    y = median(c(y_from, y_to)), .groups = "drop"
  ) |> # 線分の中点に配置
  tibble::add_column(
    angle = c(90, 90, 0, 0) |> 
      rep(each = frame_num), 
    h = c(0.5, 0.5, 0.5, -0.2) |> 
      rep(each = frame_num), 
    v = c(1, -0.5, 1, 0.5) |> 
      rep(each = frame_num), 
    fnc_label = c("csc~theta", "sin~theta", "cos~theta", "cot~theta") |> 
      rep(each = frame_num) # 関数ラベル
  )
anim_function_label_df
## # A tibble: 600 × 8
##    fnc   frame_label                   x        y angle     h     v fnc_label
##    <fct> <fct>                     <dbl>    <dbl> <dbl> <dbl> <dbl> <chr>    
##  1 csc   θ = -2 π, csc θ = 1, sin…     0 2.04e+15    90   0.5     1 csc~theta
##  2 csc   θ = -1.97 π, csc θ = 1, …     0 5.98e+ 0    90   0.5     1 csc~theta
##  3 csc   θ = -1.95 π, csc θ = 1.0…     0 3.00e+ 0    90   0.5     1 csc~theta
##  4 csc   θ = -1.92 π, csc θ = 1.0…     0 2.01e+ 0    90   0.5     1 csc~theta
##  5 csc   θ = -1.89 π, csc θ = 1.0…     0 1.52e+ 0    90   0.5     1 csc~theta
##  6 csc   θ = -1.87 π, csc θ = 1.0…     0 1.23e+ 0    90   0.5     1 csc~theta
##  7 csc   θ = -1.84 π, csc θ = 1.1…     0 1.04e+ 0    90   0.5     1 csc~theta
##  8 csc   θ = -1.81 π, csc θ = 1.2…     0 9.04e- 1    90   0.5     1 csc~theta
##  9 csc   θ = -1.79 π, csc θ = 1.2…     0 8.05e- 1    90   0.5     1 csc~theta
## 10 csc   θ = -1.76 π, csc θ = 1.3…     0 7.30e- 1    90   0.5     1 csc~theta
## # … with 590 more rows

 ラベルを表示する線分の中点の座標を計算して、ラベル用の文字列などを格納します。

 単位円上に三角関数の直線を重ねたアニメーションを作成します。

# グラフサイズ用の値を指定
x_size <- 1.3
y_size <- 2

# 単位円上の三角関数直線のアニメーションを作図
anim <- ggplot() + 
  geom_path(data = circle_df, 
            mapping = aes(x = x, y = y), 
            size = 1) + # 円周
  geom_segment(data = radian_lable_df, 
               mapping = aes(x = 0, y = 0, xend = x, yend = y), 
               color = "white") + # 角度目盛グリッド
  geom_text(data = radian_lable_df, 
            mapping = aes(x = x, y = y, angle = t_deg+90), label = "|", 
            size = 2) + # 角度目盛指示線
  geom_text(data = radian_lable_df, 
            mapping = aes(x = label_x, y = label_y, label = rad_label, hjust = h, vjust = v), parse = TRUE) + # 角度目盛ラベル
  geom_vline(xintercept = 0, linetype = "dashed") + # cot直線用の補助線
  geom_point(data = anim_point_df, 
             mapping = aes(x = cos_t, y = sin_t), 
             size = 4) + # 円周上の点
  geom_segment(data = anim_radius_df, 
               mapping = aes(x = 0, y = 0, xend = x_to, yend = y_to), 
               size = 1) + # 半径直線
  geom_path(data = anim_angle_mark_df, 
            mapping = aes(x = x, y = y), 
            size = 0.5) + # 角マーク
  geom_text(data = anim_angle_label_df, 
            mapping = aes(x = x, y = y), label = "theta", parse = TRUE, 
            size = 5) + # 角ラベル
  geom_segment(data = anim_function_line_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                             color = fnc, size = type)) + # 関数直線
  geom_text(data = anim_function_label_df, 
            mapping = aes(x = x, y = y, label = fnc_label, color = fnc, 
                          hjust = h, vjust = v, angle = angle), parse = TRUE, show.legend = FALSE) + # 関数ラベル
  gganimate::transition_manual(frames = frame_label) + # フレーム
  scale_size_manual(breaks = c("normal", "bold", "thin"), 
                    values = c(1, 1.6, 0.8), guide = "none") + # (線が重なる対策)
  coord_fixed(ratio = 1, 
              xlim = c(-x_size, x_size), ylim = c(-y_size, y_size)) + # 描画領域
  labs(title = "circular functions", 
       subtitle = "{current_frame}", 
       color = "function", 
       x = "x", y = "y")

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

単位円におけるなす角とcsc関数の関係

 こちらの図だと、原点と円周上の点を結ぶ線分が水平になり、その垂線が直線  x = 0 と平行なため交点ができず、 \csc \theta を描画(定義)できないのが分かります。

単位円上の点とcsc関数曲線の関係の可視化

 最後は、単位円上におけるcsc関数の値(直線)と、csc関数の曲線の関係をグラフで確認します。

グラフの作成

 変数を固定したcsc関数をグラフで確認します。

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

 変数の値(スカラ)を設定します。

# 単位円上の点用のラジアンを指定
theta <- 5/4 * pi

# 曲線上の点の座標を計算
point_df <- tibble::tibble(
  t = theta, 
  sin_t = sin(theta), 
  cos_t = cos(theta), 
  csc_t = 1/sin(theta)
)
point_df
## # A tibble: 1 × 4
##       t  sin_t  cos_t csc_t
##   <dbl>  <dbl>  <dbl> <dbl>
## 1  3.93 -0.707 -0.707 -1.41

 曲線上の点の座標計算に用いる変数(ラジアン)  \thetathetaとして値を指定します。ただし、theta0のとき計算結果にInfが含まれるため意図しないグラフになります。発散時の対策については「アニメーションの作成」を参照してください。

 「単位円上のcsc関数の可視化」のコードで3つのデータフレームを作成します。

 ここまでは、共通の処理です。ここからは、2つの方法で図示します。

パターン1

 1つ目の方法では、単位円の図上で横軸を縦軸に変換してcsc関数を可視化します。

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

 三角関数を直線として描画するためのデータフレームを作成します。

# 関数ラベルのレベルを指定
fnc_level_vec <- c("csc", "sin", "cos", "cot")

# 変換フラグを設定
cos_flg <- cos(theta) >= 0

# 関数直線の線分の座標を格納
function_line_df <- tibble::tibble(
  fnc = c(
    "csc", "csc", "csc", 
    "sin", 
    "cos", 
    "cot", "cot"
  ) |> 
    factor(levels = fnc_level_vec), # 色用
  x_from = c(
    0, ifelse(test = cos_flg, yes = NA, no = 0), 0, 
    cos(theta), 
    0, 
    0, ifelse(test = cos_flg, yes = NA, no = 0)
  ), 
  y_from = c(
    0, ifelse(test = cos_flg, yes = NA, no = 0), 0, 
    0, 
    0, 
    0, ifelse(test = cos_flg, yes = NA, no = 0)
  ), 
  x_to = c(
    ifelse(test = cos_flg, yes = 1/tan(theta), no = -1/tan(theta)), ifelse(test = cos_flg, yes = NA, no = 1/tan(theta)), 0, 
    cos(theta), 
    cos(theta), 
    1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
  ), 
  y_to = c(
    1, ifelse(test = cos_flg, yes = NA, no = 1), 1/sin(theta), 
    sin(theta), 
    0, 
    0, ifelse(test = cos_flg, yes = NA, no = 0)
  ), 
  type = c(
    "main", "sub", "sub", 
    "main", 
    "main", 
    "main", "sub"
  ), # 線タイプ用
  width = c(
    "normal", "normal", "normal", 
    "normal", 
    "bold", 
    "thin", "thin"
  ) # 太さ用
)
function_line_df
## # A tibble: 7 × 7
##   fnc   x_from y_from   x_to   y_to type  width 
##   <fct>  <dbl>  <dbl>  <dbl>  <dbl> <chr> <chr> 
## 1 csc    0          0 -1      1     main  normal
## 2 csc    0          0  1      1     sub   normal
## 3 csc    0          0  0     -1.41  sub   normal
## 4 sin   -0.707      0 -0.707 -0.707 main  normal
## 5 cos    0          0 -0.707  0     main  bold  
## 6 cot    0          0  1      0     main  thin  
## 7 cot    0          0 -1      0     sub   thin

 「単位円上のcsc関数の可視化」のときのコードに、csc直線の1つを垂直線に回転した線分の座標を格納します。

 関数名をラベルとして描画するためのデータフレームを作成します。

# 関数ラベルの座標を格納
function_label_df <- tibble::tibble(
  fnc = c("csc", "sin", "cos", "cot") |> 
    factor(levels = fnc_level_vec), # 色用
  x = c(
    0.5 / ifelse(test = cos_flg, yes = tan(theta), no = -tan(theta)), 
    cos(theta), 
    0.5 * cos(theta), 
    0.5 / tan(theta)
  ), 
  y = c(
    0.5, 
    0.5 * sin(theta), 
    0, 
    0
  ), 
  angle = c(0, 90, 0, 0), 
  h = c(1.1, 0.5, 0.5, 0.5), 
  v = c(0.5, -0.5, -0.5, 1), 
  fnc_label = c("csc~theta", "sin~theta", "cos~theta", "cot~theta") # 関数ラベル
)
function_label_df
## # A tibble: 4 × 7
##   fnc        x      y angle     h     v fnc_label
##   <fct>  <dbl>  <dbl> <dbl> <dbl> <dbl> <chr>    
## 1 csc   -0.5    0.5       0   1.1   0.5 csc~theta
## 2 sin   -0.707 -0.354    90   0.5  -0.5 sin~theta
## 3 cos   -0.354  0         0   0.5  -0.5 cos~theta
## 4 cot    0.5    0         0   0.5   1   cot~theta

 (図がゴチャゴチャするので)符号を反転させたラベルは描画しないことにします。

 軸の変換前後の点を描画するためのデータフレームを作成します。

# 変換曲線の先端の座標を格納
adapt_point_df <- tibble::tibble(
  x = c(ifelse(test = cos_flg, yes = 1/tan(theta), no = -1/tan(theta)), 0), 
  y = c(1, 1/sin(theta))
)
adapt_point_df
## # A tibble: 2 × 2
##       x     y
##   <dbl> <dbl>
## 1    -1  1   
## 2     0 -1.41

 原点から伸びるcsc直線の座標について、直線  y = 1 上の点  (\pm \frac{1}{\tan \theta}, 1) と直線  x = 0 上の点  (0, \csc \theta) を格納します。

 垂直線になるように直線を回転する軌道を描画するためのデータフレームを作成します。

# csc直線の角度を設定
if(sin(theta) >= 0) {
  tmp_theta <- asin(sin(theta))
} else {
  tmp_theta <- pi + asin(sin(theta))
}

# 軸変換曲線の描画用
adapt_line_df <- tibble::tibble(
  rad = seq(
    from = tmp_theta, 
    to = ifelse(test = sin(theta) >= 0, yes = 0.5*pi, no = 1.5*pi), 
    length.out = 100
  ), 
  x = abs(1/sin(theta)) * cos(rad), 
  y = abs(1/sin(theta)) * sin(rad)
)
adapt_line_df
## # A tibble: 100 × 3
##      rad     x     y
##    <dbl> <dbl> <dbl>
##  1  2.36 -1    1    
##  2  2.38 -1.02 0.976
##  3  2.40 -1.05 0.951
##  4  2.43 -1.07 0.926
##  5  2.45 -1.09 0.900
##  6  2.48 -1.11 0.874
##  7  2.50 -1.13 0.848
##  8  2.52 -1.15 0.820
##  9  2.55 -1.17 0.793
## 10  2.57 -1.19 0.765
## # … with 90 more rows

 軸を変換する軌道として、半径が  |\csc \theta| の弧を描画します。全体値  |x|abs()で計算できます。

 任意の範囲で設定したラジアン  \theta 0 \leq \alpha \leq \pi の範囲のラジアンに変換します。コサイン関数  \cos x の逆関数(逆コサイン関数)  \arccos x を使って、  \alpha = \arccos(\cos \theta) で計算します。逆コサイン関数はacos()で計算できます。

  \csc \theta \geq 0 のとき( \sin \theta \geq 0 のとき)第1象限からy軸の正の部分への変化を示すため  \alpha \leq t \leq \frac{\pi}{2} のラジアン、 \csc \theta \lt 0 のとき( \sin \theta \lt 0 のとき)第2象限からy軸の負の部分への変化を示すため  \alpha \leq t \leq \frac{3 \pi}{2} のラジアンを用いて、弧のx軸の値  x = |\csc \theta| \cos t とy軸の値  y = |\csc \theta| \sin t を計算します。

 単位円における点とcsc曲線上の点を結ぶ補助線(の半分)を描画するためのデータフレームを作成します。

# グラフサイズ用の値を設定
size_min  <- 2
size_max  <- 5
x_size <- ceiling(abs(1/tan(theta))) |> 
  max(size_min) |> 
  min(size_max)
y_size <- ceiling(abs(1/sin(theta))) |> 
  max(size_min) |> 
  min(size_max)

# csc曲線との対応線の座標を格納
l <- 0.5
segment_circle_df <- tibble::tibble(
  x = 0, 
  y = 1/sin(theta), 
  x_to = x_size+l, 
  y_to = 1/sin(theta)
)
segment_circle_df
## # A tibble: 1 × 4
##       x     y  x_to  y_to
##   <dbl> <dbl> <dbl> <dbl>
## 1     0 -1.41   2.5 -1.41

 単位円における点からy軸の反対側へ水平線を引くように座標を指定します。

 単位円上に三角関数の直線を重ねたグラフを作成します。

# 変数ラベル用の文字列を作成
variable_label <- paste0(
  "list(", 
  "theta==", round(theta/pi, digits = 2), "*pi", 
  ", csc~theta==", round(1/sin(theta), digits = 2), 
  ", sin~theta==", round(sin(theta), digits = 2), 
  ", cos~theta==", round(cos(theta), digits = 2), 
  ", cot~theta==", round(1/tan(theta), digits = 2), 
  ")"
)

# 単位円上の三角関数直線を作図
circle_graph <- ggplot() + 
  geom_path(data = circle_df, 
            mapping = aes(x = x, y = y), 
            size = 1) + # 円周
  geom_segment(data = radian_lable_df, 
               mapping = aes(x = 0, y = 0, xend = x, yend = y), 
               color = "white") + # 角度目盛グリッド
  geom_text(data = radian_lable_df, 
            mapping = aes(x = x, y = y, angle = t_deg+90), label = "|", 
            size = 2) + # 角度目盛指示線
  geom_text(data = radian_lable_df, 
            mapping = aes(x = label_x, y = label_y, label = rad_label, hjust = h, vjust = v), parse = TRUE) + # 角度目盛ラベル
  geom_hline(yintercept = 1, linetype = "dashed") + # csc直線用の補助線
  geom_point(data = point_df, 
             mapping = aes(x = cos_t, y = sin_t), 
             size = 4) + # 円周上の点
  geom_point(data = adapt_point_df, 
             mapping = aes(x = x, y = y), 
             size = 4) + # csc関数の点
  geom_segment(data = radius_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, size = width)) + # 半径直線
  geom_path(data = angle_mark_df, 
            mapping = aes(x = x, y = y), 
            size = 0.5) + # 角マーク
  geom_text(data = angle_label_df, 
            mapping = aes(x = x, y = y), label = "theta", parse = TRUE, 
            size = 5) + # 角ラベル
  geom_segment(data = function_line_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                             color = fnc, size = width, linetype = type), 
               na.rm = TRUE) + # 関数直線
  geom_text(data = function_label_df, 
            mapping = aes(x = x, y = y, label = fnc_label, color = fnc, 
                          hjust = h, vjust = v, angle = angle), 
            parse = TRUE, na.rm = TRUE, show.legend = FALSE) + # 関数ラベル
  geom_path(data = adapt_line_df, 
            mapping = aes(x = x, y = y), 
            size = 1, linetype = "dotted") + # 変換曲線
  geom_segment(data = segment_circle_df, 
               mapping = aes(x = x, y = y, xend = x_to, yend = y_to), 
               size = 1, linetype = "dotted") + # csc曲線との対応線
  scale_size_manual(breaks = c("normal", "bold", "thin"), 
                    values = c(1, 1.6, 0.8), guide = "none") + # (線が重なる対策)
  scale_linetype_manual(breaks = c("main", "sub"), 
                        values = c("solid", "twodash"), guide = "none") + # (補助線用)
  coord_fixed(ratio = 1, clip = "off", 
              xlim = c(-x_size, x_size), ylim = c(-y_size, y_size)) + # 描画領域
  theme(legend.position = "left") + # 凡例の位置
  labs(title = "circular functions", 
       subtitle = parse(text = variable_label), 
       color = "function", 
       x = "x", y = "y")
circle_graph

単位円におけるcsc関数

 「単位円上のcsc関数の可視化」のときと同様に、作図します。

 csc関数の曲線を描画するためのデータフレームを作成します。

# csc関数を計算
csc_df <- tibble::tibble(
  t = seq(from = 0, to = 2*pi, length.out = 1000), 
  csc_t = 1/sin(t)
) |> 
  dplyr::mutate(
    csc_t = dplyr::if_else(
      condition = (csc_t >= -y_size & csc_t <= y_size), 
      true = csc_t, 
      false = NA_real_
    ) # 閾値外の値を欠損値に置換
  )
csc_df
## # A tibble: 1,000 × 2
##          t csc_t
##      <dbl> <dbl>
##  1 0          NA
##  2 0.00629    NA
##  3 0.0126     NA
##  4 0.0189     NA
##  5 0.0252     NA
##  6 0.0314     NA
##  7 0.0377     NA
##  8 0.0440     NA
##  9 0.0503     NA
## 10 0.0566     NA
## # … with 990 more rows

 「csc関数の作図」のときと同様にして、曲線の座標を計算します。

 csc曲線上の点と単位円における点を結ぶ補助線(の半分)を描画するためのデータフレームを作成します。

# csc直線との対応線の座標を格納
l <- 0.7
d <- 1.1
segment_csc_df <- tibble::tibble(
  x = c(theta, theta), 
  y = c(1/sin(theta), 1/sin(theta)), 
  x_to = c(theta, -l), 
  y_to = c(-y_size*d, 1/sin(theta))
)
segment_csc_df
## # A tibble: 2 × 4
##       x     y  x_to  y_to
##   <dbl> <dbl> <dbl> <dbl>
## 1  3.93 -1.41  3.93 -2.2 
## 2  3.93 -1.41 -0.7  -1.41

 曲線上の点からx軸とy軸へ垂線と水平線を引くように座標を指定します。

 x軸目盛を設定するためのベクトルを作成します。

# 半周期の目盛の数(分母の値)を指定
denom <- 6

# 目盛の通し番号(分子の値)を作成
numer_vec <- seq(from = 0, to = 2*pi / pi * denom, by = 1)

# 目盛ラベル用の文字列を作成
label_vec <- paste0(c("", "-")[(numer_vec < 0)+1], "frac(", abs(numer_vec), ", ", denom, ")~pi")
head(numer_vec); head(label_vec)
## [1] 0 1 2 3 4 5
## [1] "frac(0, 6)~pi" "frac(1, 6)~pi" "frac(2, 6)~pi" "frac(3, 6)~pi"
## [5] "frac(4, 6)~pi" "frac(5, 6)~pi"

 「csc関数の作図」のときと同様にして、目盛ラベル用の値と文字列を作成します。

 csc関数曲線のグラフを作成します。

# 関数ラベル用の文字列を作成
csc_label <- paste0(
  "list(", 
  "theta==", round(theta/pi, digits = 2), "*pi", 
  ", csc~theta==", round(1/sin(theta), digits = 2), 
  ")"
)

# csc関数曲線を作図
csc_graph <- ggplot() + 
  geom_line(data = csc_df, 
            mapping = aes(x = t, y = csc_t), 
            size = 1, na.rm = TRUE) + # csc曲線
  geom_point(data = point_df, 
             mapping = aes(x = t, y = csc_t), 
             size = 4) + # 曲線上の点
  geom_segment(data = segment_csc_df, 
               mapping = aes(x = x, y = y, xend = x_to, yend = y_to), 
               size = 1, linetype = "dotted") + # csc直線との対応線
  scale_x_continuous(breaks = numer_vec/denom*pi, 
                     labels = parse(text = label_vec)) + # 角度目盛ラベル
  coord_fixed(ratio = 1, clip = "off", 
              xlim = c(0, 2*pi), ylim = c(-x_size, x_size)) + # 描画領域
  labs(title = "cosecant function", 
       subtitle = parse(text = csc_label), 
       x = expression(theta), 
       y = expression(csc~theta))
csc_graph

csc関数曲線上の点

 「csc関数の作図」のときと同様に、作図します。

 2つのグラフを並べて描画します。

# 並べて描画
patchwork::wrap_plots(circle_graph, csc_graph)

 patchworkパッケージのwrap_plots()を使ってグラフを並べます。

単位円におけるsec関数と曲線上の点の関係

 2つのグラフで、単位円における点の値とcsc曲線上の点のy軸の値、なす角の値とx軸の値がそれぞれ一致するのが分かります。

パターン2

 2つ目の方法では、横軸を縦軸に変換する図を挟んでcsc関数を可視化します。

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

 三角関数を直線として描画するためのデータフレームを作成します。

# 関数ラベルのレベルを指定
fnc_level_vec <- c("csc", "sin", "cos", "cot")

# 変換フラグを設定
cos_flg <- cos(theta) >= 0

# 関数直線の線分の座標を格納
function_line_df <- tibble::tibble(
  fnc = c(
    "csc", "csc", "csc", 
    "sin", 
    "cos", 
    "cot", "cot"
  ) |> 
    factor(levels = fnc_level_vec), # 色用
  x_from = c(
    0, ifelse(test = cos_flg, yes = NA, no = 0), 0, 
    cos(theta), 
    0, 
    0, ifelse(test = cos_flg, yes = NA, no = 0)
  ), 
  y_from = c(
    0, ifelse(test = cos_flg, yes = NA, no = 0), 0, 
    0, 
    0, 
    0, ifelse(test = cos_flg, yes = NA, no = 0)
  ), 
  x_to = c(
    ifelse(test = cos_flg, yes = 1/tan(theta), no = -1/tan(theta)), ifelse(test = cos_flg, yes = NA, no = 1/tan(theta)), 1/sin(theta), 
    cos(theta), 
    cos(theta), 
    1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
  ), 
  y_to = c(
    1, ifelse(test = cos_flg, yes = NA, no = 1), 0, 
    sin(theta), 
    0, 
    0, ifelse(test = cos_flg, yes = NA, no = 0)
  ), 
  type = c(
    "main", "sub", "sub", 
    "main", 
    "main", 
    "main", "sub"
  ), # 線タイプ用
  width = c(
    "normal", "normal", "bold", 
    "normal", 
    "normal", 
    "thin", "thin"
  ) # 太さ用
)
function_line_df
## # A tibble: 7 × 7
##   fnc   x_from y_from   x_to   y_to type  width 
##   <fct>  <dbl>  <dbl>  <dbl>  <dbl> <chr> <chr> 
## 1 csc    0          0 -1      1     main  normal
## 2 csc    0          0  1      1     sub   normal
## 3 csc    0          0 -1.41   0     sub   bold  
## 4 sin   -0.707      0 -0.707 -0.707 main  normal
## 5 cos    0          0 -0.707  0     main  normal
## 6 cot    0          0  1      0     main  thin  
## 7 cot    0          0 -1      0     sub   thin

 「単位円上のcsc関数の可視化」のときのコードに、csc直線の1つを垂直線に回転した線分の座標を格納します。

 「パターン1」のときのコードで、関数名をラベルとして描画するためのデータフレームを作成します。

 軸の変換前後の点を描画するためのデータフレームを作成します。

# 変換曲線の先端の座標を格納
adapt_point_df <- tibble::tibble(
  x = c(ifelse(test = cos_flg, yes = 1/tan(theta), no = -1/tan(theta)), 1/sin(theta)), 
  y = c(1, 0)
)
adapt_point_df
## # A tibble: 2 × 2
##       x     y
##   <dbl> <dbl>
## 1 -1        1
## 2 -1.41     0

 原点から伸びるcsc直線の座標について、直線  y = 1 上の点  (\pm \frac{1}{\tan \theta}, 1) と直線  x = 0 上の点  (0, \csc \theta) を格納します。

 水平線になるように直線を回転する軌道を描画するためのデータフレームを作成します。

# csc直線の角度を設定
if(sin(theta) >= 0) {
  tmp_theta <- asin(sin(theta))
} else {
  tmp_theta <- pi + asin(sin(theta))
}

# 軸変換曲線の描画用
adapt_line_df <- tibble::tibble(
  rad = seq(
    from = tmp_theta, 
    to = ifelse(test = sin(theta) >= 0, yes = 0, no = pi), 
    length.out = 100
  ), 
  x = abs(1/sin(theta)) * cos(rad), 
  y = abs(1/sin(theta)) * sin(rad)
)
adapt_line_df
## # A tibble: 100 × 3
##      rad     x     y
##    <dbl> <dbl> <dbl>
##  1  2.36 -1    1    
##  2  2.36 -1.01 0.992
##  3  2.37 -1.02 0.984
##  4  2.38 -1.02 0.976
##  5  2.39 -1.03 0.968
##  6  2.40 -1.04 0.960
##  7  2.40 -1.05 0.951
##  8  2.41 -1.05 0.943
##  9  2.42 -1.06 0.935
## 10  2.43 -1.07 0.926
## # … with 90 more rows

  \csc \theta \geq 0 のとき( \sin \theta \geq 0 のとき)第1象限からx軸の正の部分への変化を示すため  0 \leq t \leq \alpha のラジアン、 \csc \theta \lt 0 のとき( \sin \theta \lt 0 のとき)第2象限からx軸の負の部分への変化を示すため  \alpha \leq t \leq \pi のラジアンを用いて、弧のx軸の値  x = |\sec \theta| \cos t とy軸の値  y = |\sec \theta| \sin t を計算します。

 単位円における点と軸の変換図上の点を結ぶ補助線(の半分)を描画するためのデータフレームを作成します。

# グラフサイズ用の値を設定
x_min  <- 2
x_max  <- 5
x_size <- ceiling(abs(1/sin(theta))) |> 
  max(x_min) |> 
  min(x_max)
y_size <- 1.5

# 軸変換曲線との対応線の座標を格納
l <- 0.8
segment_circle_df <- tibble::tibble(
  x = 1/sin(theta), 
  y = 0, 
  x_to = 1/sin(theta), 
  y_to = -y_size-l
)
segment_circle_df
## # A tibble: 1 × 4
##       x     y  x_to  y_to
##   <dbl> <dbl> <dbl> <dbl>
## 1 -1.41     0 -1.41  -2.3

 単位円における点からx軸へ垂直線を引くように座標を指定します。

 単位円上に三角関数の直線を重ねたグラフを作成します。

### 資料作成用:(再掲)

# 単位円上の三角関数直線を作図
circle_graph <- ggplot() + 
  geom_path(data = circle_df, 
            mapping = aes(x = x, y = y), 
            size = 1) + # 円周
  geom_segment(data = radian_lable_df, 
               mapping = aes(x = 0, y = 0, xend = x, yend = y), 
               color = "white") + # 角度目盛グリッド
  geom_text(data = radian_lable_df, 
            mapping = aes(x = x, y = y, angle = t_deg+90), label = "|", 
            size = 2) + # 角度目盛指示線
  geom_text(data = radian_lable_df, 
            mapping = aes(x = label_x, y = label_y, label = rad_label, hjust = h, vjust = v), parse = TRUE) + # 角度目盛ラベル
  geom_hline(yintercept = 1, linetype = "dashed") + # csc直線用の補助線
  geom_point(data = point_df, 
             mapping = aes(x = cos_t, y = sin_t), 
             size = 4) + # 円周上の点
  geom_point(data = adapt_point_df, 
             mapping = aes(x = x, y = y), 
             size = 4) + # csc関数の点
  geom_segment(data = radius_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, size = width)) + # 半径直線
  geom_path(data = angle_mark_df, 
            mapping = aes(x = x, y = y), 
            size = 0.5) + # 角マーク
  geom_text(data = angle_label_df, 
            mapping = aes(x = x, y = y), label = "theta", parse = TRUE, 
            size = 5) + # 角ラベル
  geom_segment(data = function_line_df, 
               mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                             color = fnc, size = width, linetype = type), 
               na.rm = TRUE) + # 関数直線
  geom_text(data = function_label_df, 
            mapping = aes(x = x, y = y, label = fnc_label, color = fnc, 
                          hjust = h, vjust = v, angle = angle), 
            parse = TRUE, na.rm = TRUE, show.legend = FALSE) + # 関数ラベル
  geom_path(data = adapt_line_df, 
            mapping = aes(x = x, y = y), 
            size = 1, linetype = "dotted") + # 変換曲線
  geom_segment(data = segment_circle_df, 
               mapping = aes(x = x, y = y, xend = x_to, yend = y_to), 
               size = 1, linetype = "dotted") + # csc曲線との対応線
  scale_size_manual(breaks = c("normal", "bold", "thin"), 
                    values = c(1, 1.6, 0.8), guide = "none") + # (線が重なる対策)
  scale_linetype_manual(breaks = c("main", "sub"), 
                        values = c("solid", "twodash"), guide = "none") + # (補助線用)
  coord_fixed(ratio = 1, clip = "off", 
              xlim = c(-x_size, x_size), ylim = c(-y_size, y_size)) + # 描画領域
  theme(legend.position = "left") + # 凡例の位置
  labs(title = "circular functions", 
       subtitle = parse(text = variable_label), 
       color = "function", 
       x = "x", y = "y")
circle_graph

単位円におけるcsc関数

 「単位円上のcsc関数の可視化」のときと同様に、作図します。

 x軸の値を90度回転する線を描画するためのデータフレームを作成します。

# csc関数の軸変換曲線の座標を計算
adapt_line_df <- tibble::tibble(
  rad = seq(from = pi, to = 1.5*pi, length.out = 100), 
  x = x_size + (x_size-1/sin(theta)) * cos(rad), 
  y = x_size + (x_size-1/sin(theta)) * sin(rad)
)
adapt_line_df
## # A tibble: 100 × 3
##      rad     x     y
##    <dbl> <dbl> <dbl>
##  1  3.14 -1.41  2   
##  2  3.16 -1.41  1.95
##  3  3.17 -1.41  1.89
##  4  3.19 -1.41  1.84
##  5  3.21 -1.41  1.78
##  6  3.22 -1.40  1.73
##  7  3.24 -1.40  1.68
##  8  3.25 -1.39  1.62
##  9  3.27 -1.39  1.57
## 10  3.28 -1.38  1.51
## # … with 90 more rows

 グラフのサイズをaxis_sizeの2倍としました。axis_size S で表します。軸を変換する軌道として、中心の座標が  (S, S) で半径が  r = S - \csc \theta の弧を描画します。また、弧の中心が図の右上隅になるようにします。
  \pi \leq t \leq \frac{3 \pi}{2} を用いて、弧のx軸の値  x = S + r \cos t とy軸の値  y = S + r \sin t を計算します。
 円の座標計算については「円周の作図」を参照してください。

 軸の変換図のグリッド線を描画するためのデータフレームを作成します。

# 軸変換図のグリッド線の描画用
d <- 0.5
adapt_grid_df <- tidyr::expand_grid(
  ds = seq(from = d, to = 2*x_size, by = d), # グリッド線の位置を指定
  rad = seq(from = pi, to = 1.5*pi, length.out = 100)
) |> # グリッド線の数に応じてラジアンを複製
  dplyr::mutate(
    x = x_size + ds * cos(rad), 
    y = x_size + ds * sin(rad)
  )
adapt_grid_df
## # A tibble: 800 × 4
##       ds   rad     x     y
##    <dbl> <dbl> <dbl> <dbl>
##  1   0.5  3.14  1.5   2   
##  2   0.5  3.16  1.50  1.99
##  3   0.5  3.17  1.50  1.98
##  4   0.5  3.19  1.50  1.98
##  5   0.5  3.21  1.50  1.97
##  6   0.5  3.22  1.50  1.96
##  7   0.5  3.24  1.50  1.95
##  8   0.5  3.25  1.50  1.94
##  9   0.5  3.27  1.50  1.94
## 10   0.5  3.28  1.51  1.93
## # … with 790 more rows

 軸の変換曲線と同様に、グリッド線として、等間隔の半径の複数の曲線を描画します。
 半径の間隔dを指定して、半径列ds、ラジアン列radを作成します。ds, rad列の全ての組み合わせをexpand_grid()で作成することで、半径ごとに曲線用のラジアンを複製します。
 弧の座標を  x = S + d \cos t y = S + d \sin t で計算します。

 軸の変換図上の点とcsc曲線上の点・単位円上の点を結ぶ補助線(の半分)を描画するためのデータフレームを作成します。

# csc曲線・直線との対応線の座標を格納
l <- 0.8
segment_adapt_df <- tibble::tibble(
  x = c(1/sin(theta), x_size), 
  y = c(x_size, 1/sin(theta)), 
  x_to = c(1/sin(theta), x_size+l), 
  y_to = c(x_size+l, 1/sin(theta))
)
segment_adapt_df
## # A tibble: 2 × 4
##       x     y  x_to  y_to
##   <dbl> <dbl> <dbl> <dbl>
## 1 -1.41  2    -1.41  2.8 
## 2  2    -1.41  2.8  -1.41

 曲線の両端からx軸とy軸の反対側へ水平線と垂直線を引くように座標を指定します。

 軸の変換図を作成します。

# 軸の変換曲線を作図
adapt_graph <- ggplot() + 
  geom_line(data = adapt_grid_df, 
            mapping = aes(x = x, y = y, group = ds), 
            color = "white") + # グリッド線
  geom_line(data = adapt_line_df, 
            mapping = aes(x = x, y = y), 
            size = 1, linetype = "dotted") + # 軸変換曲線
  geom_point(data = segment_adapt_df, 
             mapping = aes(x = x, y = y), 
             size = 4) + # csc関数の点
  geom_segment(data = segment_adapt_df, 
               mapping = aes(x = x, y = y, xend = x_to, yend = y_to), 
               size = 1, linetype = "dotted") + # csc直線・曲線との対応線
  #theme(panel.grid = element_blank()) + # 元のグリッド線を非表示
  coord_fixed(ratio = 1, clip = "off", 
              xlim = c(-x_size, x_size), ylim = c(-x_size, x_size)) + # 描画領域
  labs(x = "x", y = "x")
adapt_graph

軸変換図

 軸の変換曲線とグリッド線をそれぞれgeom_line()で描画します。

 csc関数曲線のグラフを作成します。

# csc関数を計算
csc_df <- tibble::tibble(
  t = seq(from = 0, to = 2*pi, length.out = 1000), 
  csc_t = 1/sin(t)
) |> 
  dplyr::mutate(
    csc_t = dplyr::if_else(
      condition = (csc_t >= -x_size & csc_t <= x_size), 
      true = csc_t, 
      false = NA_real_
    ) # 閾値外の値を欠損値に置換
  )

# csc直線との対応線の座標を格納
l <- 1.2
d <- 1.1
segment_csc_df <- tibble::tibble(
  x = c(theta, theta), 
  y = c(1/sin(theta), 1/sin(theta)), 
  x_to = c(theta, -l), 
  y_to = c(-x_size*d, 1/sin(theta))
)

# csc関数曲線を作図
csc_graph <- ggplot() + 
  geom_line(data = csc_df, 
            mapping = aes(x = t, y = csc_t), 
            size = 1, na.rm = TRUE) + # csc曲線
  geom_point(data = point_df, 
             mapping = aes(x = t, y = csc_t), 
             size = 4) + # 曲線上の点
  geom_segment(data = segment_csc_df, 
               mapping = aes(x = x, y = y, xend = x_to, yend = y_to), 
               size = 1, linetype = "dotted") + # csc直線との対応線
  scale_x_continuous(breaks = numer_vec/denom*pi, 
                     labels = parse(text = label_vec)) + # 角度目盛ラベル
  coord_fixed(ratio = 1, clip = "off", 
              xlim = c(0, 2*pi), ylim = c(-x_size, x_size)) + # 描画領域
  labs(title = "cosecant function", 
       subtitle = parse(text = csc_label), 
       x = expression(theta), 
       y = expression(csc~theta))
csc_graph

csc関数曲線上の点

 y軸方向の描画範囲をx_sizeを用いて設定して、作図します。

 3つのグラフを並べて描画します。

# 並べて描画
patchwork::wrap_plots(
  circle_graph, patchwork::plot_spacer(), 
  adapt_graph, csc_graph, 
  nrow = 2, ncol = 2, 
  widths = c(1, pi/x_size), heights = c(1, x_size/y_size)
)

 グラフを配置しない位置をplot_spacer()で指定します。

単位円におけるcsc関数と曲線上の点の関係

 分かりやすい方の図を参考にしてください。

アニメーションの作成

 続いて、変数の値を変化させたアニメーションで確認します。sin関数の作図については「【R】sin関数の可視化 - からっぽのしょこ」を参照してください。

1周期

 円周上を1周した際のcsc関数の直線と曲線上の点の関係を可視化します。

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

 フレーム数を指定して、変数として用いる値を作成します。

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

# 変数の値を作成
theta_i <- seq(from = 0, to = 2*pi, length.out = frame_num+1)[1:frame_num]
head(theta_i)
## [1] 0.0000000 0.1047198 0.2094395 0.3141593 0.4188790 0.5235988

 フレーム数frame_numを指定して、円周上と曲線上の点の座標計算に用いるの変数(ラジアン)として  0 \leq \theta \leq 2 \pi の範囲でframe_num個の等間隔の値を作成します。


パターン1

 1つ目の方法では、csc関数のみを可視化します。

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

 theta_iから順番に値を取り出してグラフを作成し、画像ファイルとして書き出す処理を繰り返します。

# 一時保存フォルダを指定
dir_path <- "tmp_folder"

# 関数ラベルのレベルを指定
fnc_level_vec <- c("csc", "sin", "cos", "cot")

# グラフサイズ用の値を設定
x_size <- 1.5
y_size <- 2.5

# csc関数を計算
csc_df <- tibble::tibble(
  t = seq(from = 0, to = 2*pi, length.out = 1000), 
  csc_t = 1/sin(t)
) |> 
  dplyr::mutate(
    csc_t = dplyr::if_else(
      condition = (csc_t >= -y_size & csc_t <= y_size), 
      true = csc_t, 
      false = NA_real_
    ) # 閾値外の値を欠損値に置換
  )

# 目盛ラベル用の文字列を作成
denom <- 6
numer_vec <- seq(from = 0, to = 2*pi / pi * denom, by = 1)
label_vec <- paste0(c("", "-")[(numer_vec < 0)+1], "frac(", abs(numer_vec), ", ", denom, ")~pi")

# 変数ごとに作図
for(i in 1:frame_num) {
  
  # i番目の値を取得
  theta <- theta_i[i]
  
  # 曲線上の点の座標を計算
  point_df <- tibble::tibble(
    t = theta, 
    sin_t = sin(theta), 
    cos_t = cos(theta), 
    csc_t = 1/sin(theta)
  ) |> 
  dplyr::mutate(
    csc_t = dplyr::if_else(condition = is.infinite(csc_t), true = NA_real_, false = csc_t)
  ) # 発散した場合は欠損値に置換
  
  ## 単位円上の関数直線の作図処理
  
  # 角マークの座標を計算
  d <- 0.15
  angle_mark_df <- tibble::tibble(
    t = seq(from = 0, to = theta, length.out = 100), 
    x = d * cos(t), 
    y = d * sin(t)
  )
  
  # 角ラベルの座標を計算
  d <- 0.21
  angle_label_df <- tibble::tibble(
    t = 0.5 * theta, 
    x = d * cos(t), 
    y = d * sin(t)
  )
  
  # 変換フラグを設定
  cos_flg <- cos(theta) >= 0
  
  # 半径の線分の座標を格納
  radius_df <- tibble::tibble(
    x_from = c(
      0, 0, 
      1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
    ), 
    y_from = c(
      0, 0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    x_to = c(
      1, cos(theta), 
      1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
    ), 
    y_to = c(
      0, sin(theta), 
      1, ifelse(test = cos_flg, yes = NA, no = 1)
    ), 
    width = c("normal", "normal", "thin", "thin") # 太さ用
  ) |> 
  dplyr::mutate(
    x_to = dplyr::if_else(condition = is.infinite(x_to), true = NA_real_, false = x_to), 
    y_to = dplyr::if_else(condition = is.infinite(y_to), true = NA_real_, false = y_to)
  ) # 発散した場合は欠損値に置換
  
  # 関数直線の線分の座標を格納
  function_line_df <- tibble::tibble(
    fnc = c(
      "csc", "csc", "csc", 
      "sin", 
      "cos", 
      "cot", "cot"
    ) |> 
      factor(levels = fnc_level_vec), # 色用
    x_from = c(
      0, ifelse(test = cos_flg, yes = NA, no = 0), 0, 
      cos(theta), 
      0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    y_from = c(
      0, ifelse(test = cos_flg, yes = NA, no = 0), 0, 
      0, 
      0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    x_to = c(
      ifelse(test = cos_flg, yes = 1/tan(theta), no = -1/tan(theta)), ifelse(test = cos_flg, yes = NA, no = 1/tan(theta)), 0, 
      cos(theta), 
      cos(theta), 
      1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
    ), 
    y_to = c(
      1, ifelse(test = cos_flg, yes = NA, no = 1), 1/sin(theta), 
      sin(theta), 
      0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    type = c(
      "main", "sub", "sub", 
      "main", 
      "main", 
      "main", "sub"
    ), # 線タイプ用
    width = c(
      "normal", "normal", "normal", 
      "normal", 
      "bold", 
      "thin", "thin"
    ) # 太さ用
  ) |> 
  dplyr::mutate(
    x_to = dplyr::if_else(condition = is.infinite(x_to), true = NA_real_, false = x_to), 
    y_to = dplyr::if_else(condition = is.infinite(y_to), true = NA_real_, false = y_to)
  ) # 発散した場合は欠損値に置換
  
  # 関数ラベルの座標を格納
  function_label_df <- tibble::tibble(
    fnc = c("csc", "sin", "cos", "cot") |> 
      factor(levels = fnc_level_vec), # 色用
    x = c(
      0.5 / ifelse(test = cos_flg, yes = tan(theta), no = -tan(theta)), 
      cos(theta), 
      0.5 * cos(theta), 
      0.5 / tan(theta)
    ), 
    y = c(
      0.5, 
      0.5 * sin(theta), 
      0, 
      0
    ), 
    angle = c(0, 90, 0, 0), 
    h = c(1.1, 0.5, 0.5, 0.5), 
    v = c(0.5, -0.5, -0.5, 1), 
    fnc_label = c("csc~theta", "sin~theta", "cos~theta", "cot~theta") # 関数ラベル
  ) |> 
  dplyr::mutate(
    x = dplyr::if_else(condition = is.infinite(x), true = NA_real_, false = x), 
    y = dplyr::if_else(condition = is.infinite(y), true = NA_real_, false = y)
  ) # 発散した場合は欠損値に置換
  
  # 変換曲線の先端の座標を格納
  adapt_point_df <- tibble::tibble(
    x = c(ifelse(test = cos_flg, yes = 1/tan(theta), no = -1/tan(theta)), 0), 
    y = c(1, 1/sin(theta))
  ) |> 
  dplyr::mutate(
    x = dplyr::if_else(condition = is.infinite(x), true = NA_real_, false = x), 
    y = dplyr::if_else(condition = is.infinite(y), true = NA_real_, false = y)
  ) # 発散した場合は欠損値に置換
  
  # csc直線の角度を設定
  if(sin(theta) >= 0) {
    tmp_theta <- asin(sin(theta))
  } else {
    tmp_theta <- pi + asin(sin(theta))
  }
  
  # 軸変換曲線の描画用
  adapt_line_df <- tibble::tibble(
    rad = seq(
      from = tmp_theta, 
      to = ifelse(test = sin(theta) >= 0, yes = 0.5*pi, no = 1.5*pi), 
      length.out = 100
    ), 
    x = abs(1/sin(theta)) * cos(rad), 
    y = abs(1/sin(theta)) * sin(rad)
  )
  
  # csc曲線との対応線の座標を格納
  l <- 0.5
  segment_circle_df <- tibble::tibble(
    x = 0, 
    y = 1/sin(theta), 
    x_to = x_size+l, 
    y_to = 1/sin(theta)
  ) |> 
  dplyr::mutate(
    y    = dplyr::if_else(condition = is.infinite(y), true = NA_real_, false = y), 
    y_to = dplyr::if_else(condition = is.infinite(y_to), true = NA_real_, false = y_to)
  ) # 発散した場合は欠損値に置換
  
  # 変数ラベル用の文字列を作成
  variable_label <- paste0(
    "list(", 
    "theta==", round(theta/pi, digits = 2), "*pi", 
    #", csc~theta==", round(1/sin(theta), digits = 2), 
    ", sin~theta==", round(sin(theta), digits = 2), 
    ", cos~theta==", round(cos(theta), digits = 2), 
    ", cot~theta==", round(1/tan(theta), digits = 2), 
    ")"
  )
  
  # 単位円上の三角関数直線を作図
  circle_graph <- ggplot() + 
    geom_path(data = circle_df, 
              mapping = aes(x = x, y = y), 
              size = 1) + # 円周
    geom_segment(data = radian_lable_df, 
                 mapping = aes(x = 0, y = 0, xend = x, yend = y), 
                 color = "white") + # 角度目盛グリッド
    geom_text(data = radian_lable_df, 
              mapping = aes(x = x, y = y, angle = t_deg+90), label = "|", 
              size = 2) + # 角度目盛指示線
    geom_text(data = radian_lable_df, 
              mapping = aes(x = label_x, y = label_y, label = rad_label, hjust = h, vjust = v), parse = TRUE) + # 角度目盛ラベル
    geom_hline(yintercept = 1, linetype = "dashed") + # csc直線用の補助線
    geom_point(data = point_df, 
               mapping = aes(x = cos_t, y = sin_t), 
               size = 4) + # 円周上の点
    geom_point(data = adapt_point_df, 
               mapping = aes(x = x, y = y), na.rm = TRUE, 
               size = 4) + # csc関数の点
    geom_segment(data = radius_df, 
                 mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, size = width), na.rm = TRUE) + # 半径直線
    geom_path(data = angle_mark_df, 
              mapping = aes(x = x, y = y), 
              size = 0.5) + # 角マーク
    geom_text(data = angle_label_df, 
              mapping = aes(x = x, y = y), label = "theta", parse = TRUE, 
              size = 5) + # 角ラベル
    geom_segment(data = function_line_df, 
                 mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                               color = fnc, size = width, linetype = type), na.rm = TRUE) + # 関数直線
    geom_text(data = function_label_df, 
              mapping = aes(x = x, y = y, label = fnc_label, color = fnc, 
                            hjust = h, vjust = v, angle = angle), 
              parse = TRUE, na.rm = TRUE, show.legend = FALSE) + # 関数ラベル
    geom_path(data = adapt_line_df, 
              mapping = aes(x = x, y = y), na.rm = TRUE, 
              size = 1, linetype = "dotted") + # 変換曲線
    geom_segment(data = segment_circle_df, 
                 mapping = aes(x = x, y = y, xend = x_to, yend = y_to), na.rm = TRUE, 
                 size = 1, linetype = "dotted") + # csc曲線との対応線
    scale_size_manual(breaks = c("normal", "bold", "thin"), 
                      values = c(1, 1.6, 0.8), guide = "none") + # (線が重なる対策)
    scale_linetype_manual(breaks = c("main", "sub"), 
                          values = c("solid", "twodash"), guide = "none") + # (補助線用)
    coord_fixed(ratio = 1, clip = "off", 
                xlim = c(-x_size, x_size), ylim = c(-y_size, y_size)) + # 描画領域
    theme(legend.position = "left") + # 凡例の位置
    labs(title = "circular functions", 
         subtitle = parse(text = variable_label), 
         color = "function", 
         x = "x", y = "y")
  
  ## csc関数曲線の作図処理
  
  # csc直線との対応線の座標を格納
  l <- 0.7
  d <- 1.1
  segment_csc_df <- tibble::tibble(
    x = c(theta, theta), 
    y = c(1/sin(theta), 1/sin(theta)), 
    x_to = c(theta, -l), 
    y_to = c(-y_size*d, 1/sin(theta))
  ) |> 
  dplyr::mutate(
    y    = dplyr::if_else(condition = is.infinite(y), true = NA_real_, false = y), 
    y_to = dplyr::if_else(condition = is.infinite(y_to), true = NA_real_, false = y_to)
  ) # 発散した場合は欠損値に置換
  
  # 関数ラベル用の文字列を作成
  csc_label <- paste0(
    "list(", 
    "theta==", round(theta/pi, digits = 2), "*pi", 
    ", csc~theta==", round(1/sin(theta), digits = 2), 
    ")"
  )
  
  # csc関数曲線を作図
  csc_graph <- ggplot() + 
    geom_line(data = csc_df, 
              mapping = aes(x = t, y = csc_t), na.rm = TRUE, 
              size = 1) + # csc曲線
    geom_point(data = point_df, 
               mapping = aes(x = t, y = csc_t), na.rm = TRUE, 
               size = 4) + # 曲線上の点
    geom_segment(data = segment_csc_df, 
                 mapping = aes(x = x, y = y, xend = x_to, yend = y_to), na.rm = TRUE, 
                 size = 1, linetype = "dotted") + # csc直線との対応線
    scale_x_continuous(breaks = numer_vec/denom*pi, 
                       labels = parse(text = label_vec)) + # 角度目盛ラベル
    coord_fixed(ratio = 1, clip = "off", 
                xlim = c(0, 2*pi), ylim = c(-y_size, y_size)) + # 描画領域
    labs(title = "cosecant function", 
         subtitle = parse(text = csc_label), 
         x = expression(theta), 
         y = expression(csc~theta))
  
  # 並べて描画
  graph <- patchwork::wrap_plots(circle_graph, csc_graph)
  
  # ファイルを書き出し
  file_path <- paste0(dir_path, "/", stringr::str_pad(i, width = nchar(frame_num), pad = "0"), ".png")
  ggplot2::ggsave(filename = file_path, plot = graph, width = 1500, height = 1000, units = "px", dpi = 100)
  
  # 途中経過を表示
  message("\r", i, " / ", frame_num, appendLF = FALSE)
}

 変数の値ごとに「グラフの作成」のときと同様に処理します。作成したグラフをggsave()で保存します。

 csc関数のアニメーションを作成します。

# gif画像を作成
paste0(dir_path, "/", stringr::str_pad(1:frame_num, width = nchar(frame_num), pad = "0"), ".png") |> # ファイルパスを作成
  magick::image_read() |> # 画像ファイルを読込
  magick::image_animate(fps = 1, dispose = "previous") |> # gif画像を作成
  magick::image_write_gif(path = "curves/csc_1cycle.gif", delay = 0.1) -> tmp_path # gifファイル書き出し

 全てのファイルパスを作成して、image_read()で画像ファイルを読み込んで、image_animate()でgif画像に変換して、image_write_gif()でgifファイルとして書き出します。delay引数に1秒当たりのフレーム数の逆数を指定します。

単位円におけるなす角とcsc関数の関係

  \sin \theta = 0 となる  \theta = 0, \pi, 2 \pi とき、csc関数の線分の方向( \csc \theta の符号)が変わり、csc関数の曲線が不連続になるのが分かります。

パターン2

 2つ目の方法では、csc関数とsin関数を並べて可視化します。

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

 theta_iから順番に値を取り出してグラフを作成し、画像ファイルとして書き出す処理を繰り返します。

# 一時保存フォルダを指定
dir_path <- "tmp_folder"

# 関数ラベルのレベルを指定
fnc_level_vec <- c("csc", "sin", "cos", "cot")

# グラフサイズ用の値を設定
x_size <- 2.5
y_size <- 1.5

# sin・csc関数を計算
curve_df <- tibble::tibble(
  t = seq(from = 0, to = 2*pi, length.out = 1000), 
  sin_t = sin(t), 
  csc_t = 1/sin(t)
) |> 
  dplyr::mutate(
    csc_t = dplyr::if_else(
      condition = (csc_t >= -x_size & csc_t <= x_size), 
      true = csc_t, 
      false = NA_real_
    ) # 閾値外の値を欠損値に置換
  )

# 目盛ラベル用の文字列を作成
denom <- 6
numer_vec <- seq(from = 0, to = 2*pi / pi * denom, by = 1)
label_vec <- paste0(c("", "-")[(numer_vec < 0)+1], "frac(", abs(numer_vec), ", ", denom, ")~pi")

# 軸変換図のグリッド線の描画用
d <- 0.5
adapt_grid_df <- tidyr::expand_grid(
  ds = seq(from = d, to = 2*x_size, by = d), # グリッド線の位置を指定
  rad = seq(from = pi, to = 1.5*pi, length.out = 100)
) |> # グリッド線の数に応じてラジアンを複製
  dplyr::mutate(
    x = x_size + ds * cos(rad), 
    y = x_size + ds * sin(rad)
  )

# 変数ごとに作図
for(i in 1:frame_num) {
  
  # i番目の値を取得
  theta <- theta_i[i]
  
  # 曲線上の点の座標を計算
  point_df <- tibble::tibble(
    t = theta, 
    sin_t = sin(theta), 
    cos_t = cos(theta), 
    csc_t = 1/sin(theta)
  ) |> 
  dplyr::mutate(
    csc_t = dplyr::if_else(condition = is.infinite(csc_t), true = NA_real_, false = csc_t)
  ) # 発散した場合は欠損値に置換
  
  ## 単位円上の関数直線の作図処理
  
  # 角マークの座標を計算
  d <- 0.15
  angle_mark_df <- tibble::tibble(
    t = seq(from = 0, to = theta, length.out = 100), 
    x = d * cos(t), 
    y = d * sin(t)
  )
  
  # 角ラベルの座標を計算
  d <- 0.21
  angle_label_df <- tibble::tibble(
    t = 0.5 * theta, 
    x = d * cos(t), 
    y = d * sin(t)
  )
  
  # 変換フラグを設定
  cos_flg <- cos(theta) >= 0
  
  # 半径の線分の座標を格納
  radius_df <- tibble::tibble(
    x_from = c(
      0, 0, 
      1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
    ), 
    y_from = c(
      0, 0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    x_to = c(
      1, cos(theta), 
      1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
    ), 
    y_to = c(
      0, sin(theta), 
      1, ifelse(test = cos_flg, yes = NA, no = 1)
    ), 
    width = c("normal", "normal", "thin", "thin") # 太さ用
  ) |> 
  dplyr::mutate(
    x_to = dplyr::if_else(condition = is.infinite(x_to), true = NA_real_, false = x_to), 
    y_to = dplyr::if_else(condition = is.infinite(y_to), true = NA_real_, false = y_to)
  ) # 発散した場合は欠損値に置換
  
  # 関数直線の線分の座標を格納
  function_line_df <- tibble::tibble(
    fnc = c(
      "csc", "csc", "csc", 
      "sin", 
      "cos", 
      "cot", "cot"
    ) |> 
      factor(levels = fnc_level_vec), # 色用
    x_from = c(
      0, ifelse(test = cos_flg, yes = NA, no = 0), 0, 
      cos(theta), 
      0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    y_from = c(
      0, ifelse(test = cos_flg, yes = NA, no = 0), 0, 
      0, 
      0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    x_to = c(
      ifelse(test = cos_flg, yes = 1/tan(theta), no = -1/tan(theta)), ifelse(test = cos_flg, yes = NA, no = 1/tan(theta)), 1/sin(theta), 
      cos(theta), 
      cos(theta), 
      1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
    ), 
    y_to = c(
      1, ifelse(test = cos_flg, yes = NA, no = 1), 0, 
      sin(theta), 
      0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    type = c(
      "main", "sub", "sub", 
      "main", 
      "main", 
      "main", "sub"
    ), # 線タイプ用
    width = c(
      "normal", "normal", "bold", 
      "normal", 
      "normal", 
      "thin", "thin"
    ) # 太さ用
  ) |> 
  dplyr::mutate(
    x_to = dplyr::if_else(condition = is.infinite(x_to), true = NA_real_, false = x_to), 
    y_to = dplyr::if_else(condition = is.infinite(y_to), true = NA_real_, false = y_to)
  ) # 発散した場合は欠損値に置換
  
  # 関数ラベルの座標を格納
  function_label_df <- tibble::tibble(
    fnc = c("csc", "sin", "cos", "cot") |> 
      factor(levels = fnc_level_vec), # 色用
    x = c(
      0.5 / ifelse(test = cos_flg, yes = tan(theta), no = -tan(theta)), 
      cos(theta), 
      0.5 * cos(theta), 
      0.5 / tan(theta)
    ), 
    y = c(
      0.5, 
      0.5 * sin(theta), 
      0, 
      0
    ), 
    angle = c(0, 90, 0, 0), 
    h = c(1.1, 0.5, 0.5, 0.5), 
    v = c(0.5, -0.5, -0.5, 1), 
    fnc_label = c("csc~theta", "sin~theta", "cos~theta", "cot~theta") # 関数ラベル
  ) |> 
  dplyr::mutate(
    x = dplyr::if_else(condition = is.infinite(x), true = NA_real_, false = x), 
    y = dplyr::if_else(condition = is.infinite(y), true = NA_real_, false = y)
  ) # 発散した場合は欠損値に置換
  
  # 変換曲線の先端の座標を格納
  adapt_point_df <- tibble::tibble(
    x = c(ifelse(test = cos_flg, yes = 1/tan(theta), no = -1/tan(theta)), 1/sin(theta)), 
    y = c(1, 0)
  ) |> 
  dplyr::mutate(
    x = dplyr::if_else(condition = is.infinite(x), true = NA_real_, false = x), 
    y = dplyr::if_else(condition = is.infinite(y), true = NA_real_, false = y)
  ) # 発散した場合は欠損値に置換
  
  # csc直線の角度を設定
  if(sin(theta) >= 0) {
    tmp_theta <- asin(sin(theta))
  } else {
    tmp_theta <- pi + asin(sin(theta))
  }
  
  # 軸変換曲線の描画用
  adapt_line_df <- tibble::tibble(
    rad = seq(
      from = tmp_theta, 
      to = ifelse(test = sin(theta) >= 0, yes = 0, no = pi), 
      length.out = 100
    ), 
    x = abs(1/sin(theta)) * cos(rad), 
    y = abs(1/sin(theta)) * sin(rad)
  )
  
  # csc・sin曲線との対応線の座標を格納
  l <- 0.5
  segment_circle_df <- tibble::tibble(
    x = c(1/sin(theta), cos(theta)), 
    y = c(0, sin(theta)), 
    x_to = c(1/sin(theta), x_size+l), 
    y_to = c(-y_size-l, sin(theta))
  ) |> 
  dplyr::mutate(
    x    = dplyr::if_else(condition = is.infinite(x), true = NA_real_, false = x), 
    x_to = dplyr::if_else(condition = is.infinite(x_to), true = NA_real_, false = x_to)
  ) # 発散した場合は欠損値に置換
  
  # 変数ラベル用の文字列を作成
  variable_label <- paste0(
    "list(", 
    "theta==", round(theta/pi, digits = 2), "*pi", 
    ", csc~theta==", round(1/sin(theta), digits = 2), 
    ", sin~theta==", round(sin(theta), digits = 2), 
    ", cos~theta==", round(cos(theta), digits = 2), 
    ", cot~theta==", round(1/tan(theta), digits = 2), 
    ")"
  )
  
  # 単位円上の三角関数直線を作図
  circle_graph <- ggplot() + 
    geom_path(data = circle_df, 
              mapping = aes(x = x, y = y), 
              size = 1) + # 円周
    geom_segment(data = radian_lable_df, 
                 mapping = aes(x = 0, y = 0, xend = x, yend = y), 
                 color = "white") + # 角度目盛グリッド
    geom_text(data = radian_lable_df, 
              mapping = aes(x = x, y = y, angle = t_deg+90), label = "|", 
              size = 2) + # 角度目盛指示線
    geom_text(data = radian_lable_df, 
              mapping = aes(x = label_x, y = label_y, label = rad_label, hjust = h, vjust = v), parse = TRUE) + # 角度目盛ラベル
    geom_hline(yintercept = 1, linetype = "dashed") + # csc直線用の補助線
    geom_point(data = point_df, 
               mapping = aes(x = cos_t, y = sin_t), 
               size = 4) + # 円周上の点
    geom_point(data = adapt_point_df, 
               mapping = aes(x = x, y = y), na.rm = TRUE, 
               size = 4) + # csc関数の点
    geom_segment(data = radius_df, 
                 mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, size = width), na.rm = TRUE) + # 半径直線
    geom_path(data = angle_mark_df, 
              mapping = aes(x = x, y = y), 
              size = 0.5) + # 角マーク
    geom_text(data = angle_label_df, 
              mapping = aes(x = x, y = y), label = "theta", parse = TRUE, 
              size = 5) + # 角ラベル
    geom_segment(data = function_line_df, 
                 mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                               color = fnc, size = width, linetype = type), na.rm = TRUE) + # 関数直線
    geom_text(data = function_label_df, 
              mapping = aes(x = x, y = y, label = fnc_label, color = fnc, 
                            hjust = h, vjust = v, angle = angle), 
              parse = TRUE, na.rm = TRUE, show.legend = FALSE) + # 関数ラベル
    geom_path(data = adapt_line_df, 
              mapping = aes(x = x, y = y), na.rm = TRUE, 
              size = 1, linetype = "dotted") + # 変換曲線
    geom_segment(data = segment_circle_df, 
                 mapping = aes(x = x, y = y, xend = x_to, yend = y_to), na.rm = TRUE, 
                 size = 1, linetype = "dotted") + # csc曲線との対応線
    scale_size_manual(breaks = c("normal", "bold", "thin"), 
                      values = c(1, 1.6, 0.8), guide = "none") + # (線が重なる対策)
    scale_linetype_manual(breaks = c("main", "sub"), 
                          values = c("solid", "twodash"), guide = "none") + # (補助線用)
    coord_fixed(ratio = 1, clip = "off", 
                xlim = c(-x_size, x_size), ylim = c(-y_size, y_size)) + # 描画領域
    theme(legend.position = "left") + # 凡例の位置
    labs(title = "circular functions", 
         subtitle = parse(text = variable_label), 
         color = "function", 
         x = "x", y = "y")
  
  ## 軸の変換図の作図処理
  
  # csc関数の軸変換曲線の座標を計算
  adapt_line_df <- tibble::tibble(
    rad = seq(from = pi, to = 1.5*pi, length.out = 100), 
    x = x_size + (x_size-1/sin(theta)) * cos(rad), 
    y = x_size + (x_size-1/sin(theta)) * sin(rad)
  ) |> 
    dplyr::mutate(
      x = dplyr::if_else(condition = x <= x_size, true = x, false = NA_real_), 
      y = dplyr::if_else(condition = y <= x_size, true = y, false = NA_real_)
    ) # 領域外の場合は欠損値に置換
  
  # csc曲線・直線との対応線の座標を格納
  l <- 1.2
  segment_adapt_df <- tibble::tibble(
    x = c(1/sin(theta), x_size), 
    y = c(x_size, 1/sin(theta)), 
    x_to = c(1/sin(theta), x_size+l), 
    y_to = c(x_size+l, 1/sin(theta))
  ) |> 
    dplyr::mutate(
      x = dplyr::if_else(condition = x <= x_size, true = x, false = NA_real_), 
      y = dplyr::if_else(condition = y <= x_size, true = y, false = NA_real_)
    ) # 領域外の場合は欠損値に置換
  
  # 軸の変換曲線を作図
  adapt_graph <- ggplot() + 
    geom_line(data = adapt_grid_df, 
              mapping = aes(x = x, y = y, group = ds), 
              color = "white") + # グリッド線
    geom_line(data = adapt_line_df, 
              mapping = aes(x = x, y = y), na.rm = TRUE, 
              size = 1, linetype = "dotted") + # 軸変換曲線
    geom_point(data = segment_adapt_df, na.rm = TRUE, 
               mapping = aes(x = x, y = y), 
               size = 4) + # csc関数の点
    geom_segment(data = segment_adapt_df, 
                 mapping = aes(x = x, y = y, xend = x_to, yend = y_to), na.rm = TRUE, 
                 size = 1, linetype = "dotted") + # csc直線・曲線との対応線
    #theme(panel.grid = element_blank()) + # 元のグリッド線を非表示
    coord_fixed(ratio = 1, clip = "off", 
                xlim = c(-x_size, x_size), ylim = c(-x_size, x_size)) + # 描画領域
    labs(x = "x", y = "x")
  
  ## csc関数曲線の作図処理
  
  # csc直線との対応線の座標を格納
  lx <- 1
  ly <- 0.5
  d <- 1.1
  segment_csc_df <- tibble::tibble(
    x = c(theta, theta), 
    y = c(1/sin(theta), x_size*d), 
    x_to = c(-lx, theta), 
    y_to = c(1/sin(theta), x_size*d+ly)
  ) |> 
    dplyr::mutate(
      y    = dplyr::if_else(condition = y <= x_size, true = y, false = NA_real_), 
      y_to = dplyr::if_else(condition = y_to <= x_size, true = y_to, false = NA_real_)
    ) # 領域外の場合は欠損値に置換
  
  # 関数ラベル用の文字列を作成
  csc_label <- paste0(
    "list(", 
    "theta==", round(theta/pi, digits = 2), "*pi", 
    ", csc~theta==", round(1/sin(theta), digits = 2), 
    ")"
  )
  
  # csc関数曲線を作図
  csc_graph <- ggplot() + 
    geom_line(data = curve_df, 
              mapping = aes(x = t, y = csc_t), na.rm = TRUE, 
              size = 1) + # csc曲線
    geom_point(data = point_df, 
               mapping = aes(x = t, y = csc_t), na.rm = TRUE, 
               size = 4) + # 曲線上の点
    geom_segment(data = segment_csc_df, 
                 mapping = aes(x = x, y = y, xend = x_to, yend = y_to), na.rm = TRUE, 
                 size = 1, linetype = "dotted") + # csc直線との対応線
    geom_vline(xintercept = theta, size = 1, linetype = "dotted") + # x軸との対応線
    scale_x_continuous(breaks = numer_vec/denom*pi, 
                       labels = parse(text = label_vec)) + # 角度目盛ラベル
    coord_fixed(ratio = 1, clip = "off", 
                xlim = c(0, 2*pi), ylim = c(-x_size, x_size)) + # 描画領域
    labs(title = "cosecant function", 
         subtitle = parse(text = csc_label), 
         x = expression(theta), 
         y = expression(csc~theta))
  
  ## sin曲線の作図処理
  
  # sin直線との対応線の座標を格納
  l <- 1.1
  d <- 1.1
  segment_sin_df <- tibble::tibble(
    x = c(theta, theta), 
    y = c(sin(theta), -y_size*d), 
    x_to = c(-l, theta), 
    y_to = c(sin(theta), -y_size*d-l)
  )
  
  # 関数ラベル用の文字列を作成
  sin_label <- paste0(
    "list(", 
    "theta==", round(theta/pi, digits = 2), "*pi", 
    ", sin~theta==", round(sin(theta), digits = 2), 
    ")"
  )
  
  # sin関数曲線を作図
  sin_graph <- ggplot() + 
    geom_line(data = curve_df, 
              mapping = aes(x = t, y = sin_t), 
              size = 1) + # sin曲線
    geom_point(data = point_df, 
               mapping = aes(x = t, y = sin_t), 
               size = 4) + # 曲線上の点
    geom_segment(data = segment_sin_df, 
                 mapping = aes(x = x, y = y, xend = x_to, yend = y_to), 
                 size = 1, linetype = "dotted") + # 変換曲線との対応線
    geom_vline(xintercept = theta, size = 1, linetype = "dotted") + # x軸との対応線
    scale_x_continuous(breaks = numer_vec/denom*pi, 
                       labels = parse(text = label_vec)) + # 角度目盛ラベル
    coord_fixed(ratio = 1, clip = "off", 
                xlim = c(0, 2*pi), ylim = c(-y_size, y_size)) + # 描画領域
    labs(title = "sine function", 
         subtitle = parse(text = sin_label), 
         x = expression(theta), 
         y = expression(sin~theta))
  
  # 並べて描画
  graph <- patchwork::wrap_plots(
    circle_graph, sin_graph, 
    adapt_graph, csc_graph, 
    nrow = 2, ncol = 2, 
    widths  = c(1, pi/x_size), 
    heights = c(1, x_size/y_size)
  )
  
  # ファイルを書き出し
  file_path <- paste0(dir_path, "/", stringr::str_pad(i, width = nchar(frame_num), pad = "0"), ".png")
  ggplot2::ggsave(filename = file_path, plot = graph, width = 1600, height = 1200, units = "px", dpi = 100)
  
  # 途中経過を表示
  message("\r", i, " / ", frame_num, appendLF = FALSE)
}

 先ほどと同様に処理します。

 「パターン1」のときのコードで、csc関数とsin関数のアニメーションを作成します。

単位円におけるなす角とcsc関数の関係

  \sin \theta = 0 のときcot関数の曲線が不連続になるのが分かります。

n周期

 円周上を複数回周回した際のcsc関数の直線と曲線上の点の関係を可視化することで、周期性を確認します。

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

 フレーム数を指定して、変数として用いる値を作成します。

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

# 変数の値を作成
theta_i <- seq(from = -2*pi, to = 2*pi, length.out = frame_num+1)[1:frame_num]
head(theta_i)
## [1] -6.283185 -6.178466 -6.073746 -5.969026 -5.864306 -5.759587

 フレーム数frame_numを指定して、frame_num個の  \theta の値を作成します。theta_iの範囲が  2 \pi の倍数だと、アニメーションの最後と最初のフレームの繋がりが良くなります。


 「グラフの作成」のときと同様に、2つの方法で図示します。

パターン1

 1つ目の方法では、csc関数のみを可視化します。

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

 theta_iから順番に値を取り出してグラフを作成し、画像ファイルとして書き出す処理を繰り返します。

# 一時保存フォルダを指定
dir_path <- "tmp_folder"

# 関数ラベルのレベルを指定
fnc_level_vec <- c("csc", "sin", "cos", "cot")

# グラフサイズ用の値を設定
x_size <- 1.5
y_size <- 2.5

# 目盛ラベル用の文字列を作成
denom <- 6
numer_vec <- seq(from = 0, to = 2*pi / pi * denom, by = 1)
label_vec <- paste0(c("", "-")[(numer_vec < 0)+1], "frac(", abs(numer_vec), ", ", denom, ")~pi")

# 変数ごとに作図
for(i in 1:frame_num) {
  
  # i番目の値を取得
  theta <- theta_i[i]
  
  # 曲線上の点の座標を計算
  point_df <- tibble::tibble(
    t = theta, 
    sin_t = sin(theta), 
    cos_t = cos(theta), 
    csc_t = 1/sin(theta)
  ) |> 
  dplyr::mutate(
    csc_t = dplyr::if_else(condition = is.infinite(csc_t), true = NA_real_, false = csc_t)
  ) # 発散した場合は欠損値に置換
  
  ## 単位円上の関数直線の作図処理
  
  # 角マークの座標を計算
  d <- 0.15
  angle_mark_df <- tibble::tibble(
    t = seq(from = 0, to = theta, length.out = 100), 
    x = d * cos(t), 
    y = d * sin(t)
  )
  
  # 角ラベルの座標を計算
  d <- 0.21
  angle_label_df <- tibble::tibble(
    t = 0.5 * theta, 
    x = d * cos(t), 
    y = d * sin(t)
  )
  
  # 変換フラグを設定
  cos_flg <- cos(theta) >= 0
  
  # 半径の線分の座標を格納
  radius_df <- tibble::tibble(
    x_from = c(
      0, 0, 
      1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
    ), 
    y_from = c(
      0, 0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    x_to = c(
      1, cos(theta), 
      1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
    ), 
    y_to = c(
      0, sin(theta), 
      1, ifelse(test = cos_flg, yes = NA, no = 1)
    ), 
    width = c("normal", "normal", "thin", "thin") # 太さ用
  ) |> 
  dplyr::mutate(
    x_to = dplyr::if_else(condition = is.infinite(x_to), true = NA_real_, false = x_to), 
    y_to = dplyr::if_else(condition = is.infinite(y_to), true = NA_real_, false = y_to)
  ) # 発散した場合は欠損値に置換
  
  # 関数直線の線分の座標を格納
  function_line_df <- tibble::tibble(
    fnc = c(
      "csc", "csc", "csc", 
      "sin", 
      "cos", 
      "cot", "cot"
    ) |> 
      factor(levels = fnc_level_vec), # 色用
    x_from = c(
      0, ifelse(test = cos_flg, yes = NA, no = 0), 0, 
      cos(theta), 
      0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    y_from = c(
      0, ifelse(test = cos_flg, yes = NA, no = 0), 0, 
      0, 
      0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    x_to = c(
      ifelse(test = cos_flg, yes = 1/tan(theta), no = -1/tan(theta)), ifelse(test = cos_flg, yes = NA, no = 1/tan(theta)), 0, 
      cos(theta), 
      cos(theta), 
      1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
    ), 
    y_to = c(
      1, ifelse(test = cos_flg, yes = NA, no = 1), 1/sin(theta), 
      sin(theta), 
      0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    type = c(
      "main", "sub", "sub", 
      "main", 
      "main", 
      "main", "sub"
    ), # 線タイプ用
    width = c(
      "normal", "normal", "normal", 
      "normal", 
      "bold", 
      "thin", "thin"
    ) # 太さ用
  ) |> 
  dplyr::mutate(
    x_to = dplyr::if_else(condition = is.infinite(x_to), true = NA_real_, false = x_to), 
    y_to = dplyr::if_else(condition = is.infinite(y_to), true = NA_real_, false = y_to)
  ) # 発散した場合は欠損値に置換
  
  # 関数ラベルの座標を格納
  function_label_df <- tibble::tibble(
    fnc = c("csc", "sin", "cos", "cot") |> 
      factor(levels = fnc_level_vec), # 色用
    x = c(
      0.5 / ifelse(test = cos_flg, yes = tan(theta), no = -tan(theta)), 
      cos(theta), 
      0.5 * cos(theta), 
      0.5 / tan(theta)
    ), 
    y = c(
      0.5, 
      0.5 * sin(theta), 
      0, 
      0
    ), 
    angle = c(0, 90, 0, 0), 
    h = c(1.1, 0.5, 0.5, 0.5), 
    v = c(0.5, -0.5, -0.5, 1), 
    fnc_label = c("csc~theta", "sin~theta", "cos~theta", "cot~theta") # 関数ラベル
  ) |> 
  dplyr::mutate(
    x = dplyr::if_else(condition = is.infinite(x), true = NA_real_, false = x), 
    y = dplyr::if_else(condition = is.infinite(y), true = NA_real_, false = y)
  ) # 発散した場合は欠損値に置換
  
  # 変換曲線の先端の座標を格納
  adapt_point_df <- tibble::tibble(
    x = c(ifelse(test = cos_flg, yes = 1/tan(theta), no = -1/tan(theta)), 0), 
    y = c(1, 1/sin(theta))
  ) |> 
  dplyr::mutate(
    x = dplyr::if_else(condition = is.infinite(x), true = NA_real_, false = x), 
    y = dplyr::if_else(condition = is.infinite(y), true = NA_real_, false = y)
  ) # 発散した場合は欠損値に置換
  
  # csc直線の角度を設定
  if(sin(theta) >= 0) {
    tmp_theta <- asin(sin(theta))
  } else {
    tmp_theta <- pi + asin(sin(theta))
  }
  
  # 軸変換曲線の描画用
  adapt_line_df <- tibble::tibble(
    rad = seq(
      from = tmp_theta, 
      to = ifelse(test = sin(theta) >= 0, yes = 0.5*pi, no = 1.5*pi), 
      length.out = 100
    ), 
    x = abs(1/sin(theta)) * cos(rad), 
    y = abs(1/sin(theta)) * sin(rad)
  )
  
  # csc曲線との対応線の座標を格納
  l <- 0.5
  segment_circle_df <- tibble::tibble(
    x = 0, 
    y = 1/sin(theta), 
    x_to = -x_size-l, 
    y_to = 1/sin(theta)
  ) |> 
  dplyr::mutate(
    y    = dplyr::if_else(condition = is.infinite(y), true = NA_real_, false = y), 
    y_to = dplyr::if_else(condition = is.infinite(y_to), true = NA_real_, false = y_to)
  ) # 発散した場合は欠損値に置換
  
  # 変数ラベル用の文字列を作成
  variable_label <- paste0(
    "list(", 
    "theta==", round(theta/pi, digits = 2), "*pi", 
    #", csc~theta==", round(1/sin(theta), digits = 2), 
    ", sin~theta==", round(sin(theta), digits = 2), 
    ", cos~theta==", round(cos(theta), digits = 2), 
    ", cot~theta==", round(1/tan(theta), digits = 2), 
    ")"
  )
  
  # 単位円上の三角関数直線を作図
  circle_graph <- ggplot() + 
    geom_path(data = circle_df, 
              mapping = aes(x = x, y = y), 
              size = 1) + # 円周
    geom_segment(data = radian_lable_df, 
                 mapping = aes(x = 0, y = 0, xend = x, yend = y), 
                 color = "white") + # 角度目盛グリッド
    geom_text(data = radian_lable_df, 
              mapping = aes(x = x, y = y, angle = t_deg+90), label = "|", 
              size = 2) + # 角度目盛指示線
    geom_text(data = radian_lable_df, 
              mapping = aes(x = label_x, y = label_y, label = rad_label, hjust = h, vjust = v), parse = TRUE) + # 角度目盛ラベル
    geom_hline(yintercept = 1, linetype = "dashed") + # csc直線用の補助線
    geom_point(data = point_df, 
               mapping = aes(x = cos_t, y = sin_t), 
               size = 4) + # 円周上の点
    geom_point(data = adapt_point_df, 
               mapping = aes(x = x, y = y), na.rm = TRUE, 
               size = 4) + # csc関数の点
    geom_segment(data = radius_df, 
                 mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                               size = width), na.rm = TRUE) + # 半径直線
    geom_path(data = angle_mark_df, 
              mapping = aes(x = x, y = y), 
              size = 0.5) + # 角マーク
    geom_text(data = angle_label_df, 
              mapping = aes(x = x, y = y), label = "theta", parse = TRUE, 
              size = 5) + # 角ラベル
    geom_segment(data = function_line_df, 
                 mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                               color = fnc, size = width, linetype = type), na.rm = TRUE) + # 関数直線
    geom_text(data = function_label_df, 
              mapping = aes(x = x, y = y, label = fnc_label, color = fnc, 
                            hjust = h, vjust = v, angle = angle), 
              parse = TRUE, na.rm = TRUE, show.legend = FALSE) + # 関数ラベル
    geom_path(data = adapt_line_df, 
              mapping = aes(x = x, y = y), na.rm = TRUE, 
              size = 1, linetype = "dotted") + # 変換曲線
    geom_segment(data = segment_circle_df, 
                 mapping = aes(x = x, y = y, xend = x_to, yend = y_to), na.rm = TRUE, 
                 size = 1, linetype = "dotted") + # csc曲線との対応線
    scale_size_manual(breaks = c("normal", "bold", "thin"), 
                      values = c(1, 1.6, 0.8), guide = "none") + # (線が重なる対策)
    scale_linetype_manual(breaks = c("main", "sub"), 
                          values = c("solid", "twodash"), guide = "none") + # (補助線用)
    coord_fixed(ratio = 1, clip = "off", 
                xlim = c(-x_size, x_size), ylim = c(-y_size, y_size)) + # 描画領域
    labs(title = "circular functions", 
         subtitle = parse(text = variable_label), 
         color = "function", 
         x = "x", y = "y")
  
  ## csc関数曲線の作図処理
  
  # 作図用の変数の値を作成
  theta_size <- 2 * pi
  theta_min  <- theta - theta_size
  theta_vec  <- seq(from = max(min(theta_i), theta_min), to = theta, length.out = 1000)
  
  # 目盛ラベル用の文字列を作成
  denom <- 6
  numer_vec <- seq(
    from = floor(theta_min / pi * denom), 
    to = ceiling(theta / pi * denom), 
    by = 1
  )
  label_vec <- paste0(c("", "-")[(numer_vec < 0)+1], "frac(", abs(numer_vec), ", ", denom, ")~pi")
  
  # csc関数を計算
  csc_df <- tibble::tibble(
    t = theta_vec, 
    csc_t = 1/sin(t)
  ) |> 
    dplyr::mutate(
      csc_t = dplyr::if_else(
        condition = (csc_t >= -y_size & csc_t <= y_size), 
        true = csc_t, 
        false = NA_real_
      ) # 閾値外の値を欠損値に置換
    )
  
  # csc直線との対応線の座標を格納
  l <- 0.7
  d <- 1.1
  segment_csc_df <- tibble::tibble(
    x = c(theta, theta), 
    y = c(1/sin(theta), 1/sin(theta)), 
    x_to = c(theta, theta+l), 
    y_to = c(-y_size*d, 1/sin(theta))
  ) |> 
  dplyr::mutate(
    y    = dplyr::if_else(condition = is.infinite(y), true = NA_real_, false = y), 
    y_to = dplyr::if_else(condition = is.infinite(y_to), true = NA_real_, false = y_to)
  ) # 発散した場合は欠損値に置換
  
  # 関数ラベル用の文字列を作成
  csc_label <- paste0(
    "list(", 
    "theta==", round(theta/pi, digits = 2), "*pi", 
    ", csc~theta==", round(1/sin(theta), digits = 2), 
    ")"
  )
  
  # csc関数曲線を作図
  csc_graph <- ggplot() + 
    geom_line(data = csc_df, 
              mapping = aes(x = t, y = csc_t), na.rm = TRUE, 
              size = 1) + # csc曲線
    geom_point(data = point_df, 
               mapping = aes(x = t, y = csc_t), na.rm = TRUE, 
               size = 4) + # 曲線上の点
    geom_segment(data = segment_csc_df, 
                 mapping = aes(x = x, y = y, xend = x_to, yend = y_to), na.rm = TRUE, 
                 size = 1, linetype = "dotted") + # csc直線との対応線
    scale_x_continuous(breaks = numer_vec/denom*pi, 
                       labels = parse(text = label_vec)) + # 角度目盛ラベル
    coord_fixed(ratio = 1, clip = "off", 
                xlim = c(theta_min, theta), ylim = c(-y_size, y_size)) + # 描画領域
    labs(title = "cosecant function", 
         subtitle = parse(text = csc_label), 
         x = expression(theta), 
         y = expression(csc~theta))
  
  # 並べて描画
  graph <- patchwork::wrap_plots(csc_graph, circle_graph)
  
  # ファイルを書き出し
  file_path <- paste0(dir_path, "/", stringr::str_pad(i, width = nchar(frame_num), pad = "0"), ".png")
  ggplot2::ggsave(filename = file_path, plot = graph, width = 1500, height = 1000, units = "px", dpi = 100)
  
  # 途中経過を表示
  message("\r", i, " / ", frame_num, appendLF = FALSE)
}

 「1周期」のときと同様に処理します。こちらは、軸目盛の関係から左右の図を入れ替えます。そのため、対応線の方向などが変わっています。

 「1周期」のときのコードで、csc関数のアニメーションを作成します。

単位円におけるなす角とcsc関数の関係

 単位円上の点が1周する  2 \pi の間隔で、曲線が同じ形になるのが分かります。

パターン2

 2つ目の方法では、csc関数とsin関数を並べて可視化します。

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

 theta_iから順番に値を取り出してグラフを作成し、画像ファイルとして書き出す処理を繰り返します。

# 一時保存フォルダを指定
dir_path <- "tmp_folder"

# 関数ラベルのレベルを指定
fnc_level_vec <- c("csc", "sin", "cos", "cot")

# グラフサイズ用の値を設定
x_size <- 2.5
y_size <- 1.5

# 軸変換図のグリッド線の描画用
d <- 0.5
adapt_grid_df <- tidyr::expand_grid(
  ds = seq(from = d, to = 2*x_size, by = d), # グリッド線の位置を指定
  rad = seq(from = 0, to = 0.5*pi, length.out = 100)
) |> # グリッド線の数に応じてラジアンを複製
  dplyr::mutate(
    x = -x_size + ds * cos(rad), 
    y = -x_size + ds * sin(rad)
  )

# 変数ごとに作図
for(i in 1:frame_num) {
  
  # i番目の値を取得
  theta <- theta_i[i]
  
  # 曲線上の点の座標を計算
  point_df <- tibble::tibble(
    t = theta, 
    sin_t = sin(theta), 
    cos_t = cos(theta), 
    csc_t = 1/sin(theta)
  ) |> 
  dplyr::mutate(
    csc_t = dplyr::if_else(condition = is.infinite(csc_t), true = NA_real_, false = csc_t)
  ) # 発散した場合は欠損値に置換
  
  ## 単位円上の関数直線の作図処理
  
  # 角マークの座標を計算
  d <- 0.15
  angle_mark_df <- tibble::tibble(
    t = seq(from = 0, to = theta, length.out = 100), 
    x = d * cos(t), 
    y = d * sin(t)
  )
  
  # 角ラベルの座標を計算
  d <- 0.21
  angle_label_df <- tibble::tibble(
    t = 0.5 * theta, 
    x = d * cos(t), 
    y = d * sin(t)
  )
  
  # 変換フラグを設定
  cos_flg <- cos(theta) >= 0
  
  # 半径の線分の座標を格納
  radius_df <- tibble::tibble(
    x_from = c(
      0, 0, 
      1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
    ), 
    y_from = c(
      0, 0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    x_to = c(
      1, cos(theta), 
      1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
    ), 
    y_to = c(
      0, sin(theta), 
      1, ifelse(test = cos_flg, yes = NA, no = 1)
    ), 
    width = c("normal", "normal", "thin", "thin") # 太さ用
  ) |> 
  dplyr::mutate(
    x_to = dplyr::if_else(condition = is.infinite(x_to), true = NA_real_, false = x_to), 
    y_to = dplyr::if_else(condition = is.infinite(y_to), true = NA_real_, false = y_to)
  ) # 発散した場合は欠損値に置換
  
  # 関数直線の線分の座標を格納
  function_line_df <- tibble::tibble(
    fnc = c(
      "csc", "csc", "csc", 
      "sin", 
      "cos", 
      "cot", "cot"
    ) |> 
      factor(levels = fnc_level_vec), # 色用
    x_from = c(
      0, ifelse(test = cos_flg, yes = NA, no = 0), 0, 
      cos(theta), 
      0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    y_from = c(
      0, ifelse(test = cos_flg, yes = NA, no = 0), 0, 
      0, 
      0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    x_to = c(
      ifelse(test = cos_flg, yes = 1/tan(theta), no = -1/tan(theta)), ifelse(test = cos_flg, yes = NA, no = 1/tan(theta)), 1/sin(theta), 
      cos(theta), 
      cos(theta), 
      1/tan(theta), ifelse(test = cos_flg, yes = NA, no = -1/tan(theta))
    ), 
    y_to = c(
      1, ifelse(test = cos_flg, yes = NA, no = 1), 0, 
      sin(theta), 
      0, 
      0, ifelse(test = cos_flg, yes = NA, no = 0)
    ), 
    type = c(
      "main", "sub", "sub", 
      "main", 
      "main", 
      "main", "sub"
    ), # 線タイプ用
    width = c(
      "normal", "normal", "bold", 
      "normal", 
      "normal", 
      "thin", "thin"
    ) # 太さ用
  ) |> 
  dplyr::mutate(
    x_to = dplyr::if_else(condition = is.infinite(x_to), true = NA_real_, false = x_to), 
    y_to = dplyr::if_else(condition = is.infinite(y_to), true = NA_real_, false = y_to)
  ) # 発散した場合は欠損値に置換
  
  # 関数ラベルの座標を格納
  function_label_df <- tibble::tibble(
    fnc = c("csc", "sin", "cos", "cot") |> 
      factor(levels = fnc_level_vec), # 色用
    x = c(
      0.5 / ifelse(test = cos_flg, yes = tan(theta), no = -tan(theta)), 
      cos(theta), 
      0.5 * cos(theta), 
      0.5 / tan(theta)
    ), 
    y = c(
      0.5, 
      0.5 * sin(theta), 
      0, 
      0
    ), 
    angle = c(0, 90, 0, 0), 
    h = c(1.1, 0.5, 0.5, 0.5), 
    v = c(0.5, -0.5, -0.5, 1), 
    fnc_label = c("csc~theta", "sin~theta", "cos~theta", "cot~theta") # 関数ラベル
  ) |> 
  dplyr::mutate(
    x = dplyr::if_else(condition = is.infinite(x), true = NA_real_, false = x), 
    y = dplyr::if_else(condition = is.infinite(y), true = NA_real_, false = y)
  ) # 発散した場合は欠損値に置換
  
  # 変換曲線の先端の座標を格納
  adapt_point_df <- tibble::tibble(
    x = c(ifelse(test = cos_flg, yes = 1/tan(theta), no = -1/tan(theta)), 1/sin(theta)), 
    y = c(1, 0)
  ) |> 
  dplyr::mutate(
    x = dplyr::if_else(condition = is.infinite(x), true = NA_real_, false = x), 
    y = dplyr::if_else(condition = is.infinite(y), true = NA_real_, false = y)
  ) # 発散した場合は欠損値に置換
  
  # csc直線の角度を設定
  if(sin(theta) >= 0) {
    tmp_theta <- asin(sin(theta))
  } else {
    tmp_theta <- pi + asin(sin(theta))
  }
  
  # 軸変換曲線の描画用
  adapt_line_df <- tibble::tibble(
    rad = seq(
      from = tmp_theta, 
      to = ifelse(test = sin(theta) >= 0, yes = 0, no = pi), 
      length.out = 100
    ), 
    x = abs(1/sin(theta)) * cos(rad), 
    y = abs(1/sin(theta)) * sin(rad)
  )
  
  # csc・sin曲線との対応線の座標を格納
  l <- 1.2
  segment_circle_df <- tibble::tibble(
    x = c(1/sin(theta), cos(theta)), 
    y = c(0, sin(theta)), 
    x_to = c(1/sin(theta), -x_size-l), 
    y_to = c(y_size+l, sin(theta))
  )
  
  # 変数ラベル用の文字列を作成
  variable_label <- paste0(
    "list(", 
    "theta==", round(theta/pi, digits = 2), "*pi", 
    ", csc~theta==", round(1/sin(theta), digits = 2), 
    ", sin~theta==", round(sin(theta), digits = 2), 
    ", cos~theta==", round(cos(theta), digits = 2), 
    ", cot~theta==", round(1/tan(theta), digits = 2), 
    ")"
  )
  
  # 単位円上の三角関数直線を作図
  circle_graph <- ggplot() + 
    geom_path(data = circle_df, 
              mapping = aes(x = x, y = y), 
              size = 1) + # 円周
    geom_segment(data = radian_lable_df, 
                 mapping = aes(x = 0, y = 0, xend = x, yend = y), 
                 color = "white") + # 角度目盛グリッド
    geom_text(data = radian_lable_df, 
              mapping = aes(x = x, y = y, angle = t_deg+90), label = "|", 
              size = 2) + # 角度目盛指示線
    geom_text(data = radian_lable_df, 
              mapping = aes(x = label_x, y = label_y, label = rad_label, hjust = h, vjust = v), parse = TRUE) + # 角度目盛ラベル
    geom_hline(yintercept = 1, linetype = "dashed") + # csc直線用の補助線
    geom_point(data = point_df, 
               mapping = aes(x = cos_t, y = sin_t), 
               size = 4) + # 円周上の点
    geom_point(data = adapt_point_df, 
               mapping = aes(x = x, y = y), na.rm = TRUE, 
               size = 4) + # csc関数の点
    geom_segment(data = radius_df, 
                 mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                               size = width), na.rm = TRUE) + # 半径直線
    geom_path(data = angle_mark_df, 
              mapping = aes(x = x, y = y), 
              size = 0.5) + # 角マーク
    geom_text(data = angle_label_df, 
              mapping = aes(x = x, y = y), label = "theta", parse = TRUE, 
              size = 5) + # 角ラベル
    geom_segment(data = function_line_df, 
                 mapping = aes(x = x_from, y = y_from, xend = x_to, yend = y_to, 
                               color = fnc, size = width, linetype = type), na.rm = TRUE) + # 関数直線
    geom_text(data = function_label_df, 
              mapping = aes(x = x, y = y, label = fnc_label, color = fnc, 
                            hjust = h, vjust = v, angle = angle), 
              parse = TRUE, na.rm = TRUE, show.legend = FALSE) + # 関数ラベル
    geom_path(data = adapt_line_df, 
              mapping = aes(x = x, y = y), na.rm = TRUE, 
              size = 1, linetype = "dotted") + # 変換曲線
    geom_segment(data = segment_circle_df, 
                 mapping = aes(x = x, y = y, xend = x_to, yend = y_to), na.rm = TRUE, 
                 size = 1, linetype = "dotted") + # csc曲線との対応線
    scale_size_manual(breaks = c("normal", "bold", "thin"), 
                      values = c(1, 1.6, 0.8), guide = "none") + # (線が重なる対策)
    scale_linetype_manual(breaks = c("main", "sub"), 
                          values = c("solid", "twodash"), guide = "none") + # (補助線用)
    coord_fixed(ratio = 1, clip = "off", 
                xlim = c(-x_size, x_size), ylim = c(-y_size, y_size)) + # 描画領域
    labs(title = "circular functions", 
         subtitle = parse(text = variable_label), 
         color = "function", 
         x = "x", y = "y")
  
  ## 変数の作成処理
  
  # 作図用の変数の値を作成
  theta_size <- 2 * pi
  theta_min  <- theta - theta_size
  theta_vec  <- seq(from = max(min(theta_i), theta_min), to = theta, length.out = 1000)
  
  # 目盛ラベル用の文字列を作成
  denom <- 6
  numer_vec <- seq(
    from = floor(theta_min / pi * denom), 
    to = ceiling(theta / pi * denom), 
    by = 1
  )
  label_vec <- paste0(c("", "-")[(numer_vec < 0)+1], "frac(", abs(numer_vec), ", ", denom, ")~pi")
  
  # sin・csc関数を計算
  curve_df <- tibble::tibble(
    t = theta_vec, 
    sin_t = sin(t), 
    csc_t = 1/sin(t)
  ) |> 
    dplyr::mutate(
      csc_t = dplyr::if_else(
        condition = (csc_t >= -x_size & csc_t <= x_size), 
        true = csc_t, 
        false = NA_real_
      ) # 閾値外の値を欠損値に置換
    )
  
  ## 軸の変換図の作図処理
  
  # csc関数の軸変換曲線の座標を計算
  adapt_line_df <- tibble::tibble(
    rad = seq(from = 0, to = 0.5*pi, length.out = 100), 
    x = -x_size + (x_size+1/sin(theta)) * cos(rad), 
    y = -x_size + (x_size+1/sin(theta)) * sin(rad)
  ) |> 
    dplyr::mutate(
      x = dplyr::if_else(condition = x >= -x_size, true = x, false = NA_real_), 
      y = dplyr::if_else(condition = y >= -x_size, true = y, false = NA_real_)
    ) # 領域外の場合は欠損値に置換
  
  # csc曲線・直線との対応線の座標を格納
  lx <- 0.8
  ly <- 1
  segment_adapt_df <- tibble::tibble(
    x = c(1/sin(theta), -x_size), 
    y = c(-x_size, 1/sin(theta)), 
    x_to = c(1/sin(theta), -x_size-lx), 
    y_to = c(-x_size-ly, 1/sin(theta))
  ) |> 
    dplyr::mutate(
      x = dplyr::if_else(condition = x >= -x_size, true = x, false = NA_real_), 
      y = dplyr::if_else(condition = y >= -x_size, true = y, false = NA_real_)
    ) # 領域外の場合は欠損値に置換
  
  # 軸の変換曲線を作図
  adapt_graph <- ggplot() + 
    geom_line(data = adapt_grid_df, 
              mapping = aes(x = x, y = y, group = ds), 
              color = "white") + # グリッド線
    geom_line(data = adapt_line_df, 
              mapping = aes(x = x, y = y), na.rm = TRUE, 
              size = 1, linetype = "dotted") + # 軸変換曲線
    geom_point(data = segment_adapt_df, 
               mapping = aes(x = x, y = y), na.rm = TRUE, 
               size = 4) + # csc関数の点
    geom_segment(data = segment_adapt_df, 
                 mapping = aes(x = x, y = y, xend = x_to, yend = y_to), na.rm = TRUE, 
                 size = 1, linetype = "dotted") + # csc直線・曲線との対応線
    #theme(panel.grid = element_blank()) + # 元のグリッド線を非表示
    coord_fixed(ratio = 1, clip = "off", 
                xlim = c(-x_size, x_size), ylim = c(-x_size, x_size)) + # 描画領域
    labs(x = "x", y = "x")
  
  ## csc関数曲線の作図処理
  
  # csc直線との対応線の座標を格納
  l <- 0.7
  d <- 1.1
  segment_csc_df <- tibble::tibble(
    x = c(theta, theta), 
    y = c(1/sin(theta), -x_size*d), 
    x_to = c(theta+l, theta), 
    y_to = c(1/sin(theta), -x_size*d-l)
  )
  
  # 関数ラベル用の文字列を作成
  csc_label <- paste0(
    "list(", 
    "theta==", round(theta/pi, digits = 2), "*pi", 
    ", csc~theta==", round(1/sin(theta), digits = 2), 
    ")"
  )
  
  # csc関数曲線を作図
  csc_graph <- ggplot() + 
    geom_line(data = curve_df, 
              mapping = aes(x = t, y = csc_t), na.rm = TRUE, 
              size = 1) + # csc曲線
    geom_point(data = point_df, 
               mapping = aes(x = t, y = csc_t), na.rm = TRUE, 
               size = 4) + # 曲線上の点
    geom_segment(data = segment_csc_df, 
                 mapping = aes(x = x, y = y, xend = x_to, yend = y_to), na.rm = TRUE, 
                 size = 1, linetype = "dotted") + # csc直線との対応線
    geom_vline(xintercept = theta, size = 1, linetype = "dotted") + # x軸との対応線
    scale_x_continuous(breaks = numer_vec/denom*pi, 
                       labels = parse(text = label_vec)) + # 角度目盛ラベル
    coord_fixed(ratio = 1, clip = "off", 
                xlim = c(theta_min, theta), ylim = c(-x_size, x_size)) + # 描画領域
    labs(title = "cosecant function", 
         subtitle = parse(text = csc_label), 
         x = expression(theta), 
         y = expression(csc~theta))
  
  ## sin曲線の作図処理
  
  # sin直線との対応線の座標を格納
  l <- 1.2
  d <- 1.1
  segment_sin_df <- tibble::tibble(
    x = c(theta, theta), 
    y = c(sin(theta), y_size*d), 
    x_to = c(theta+l, theta), 
    y_to = c(sin(theta), y_size*d+l)
  )
  
  # 関数ラベル用の文字列を作成
  sin_label <- paste0(
    "list(", 
    "theta==", round(theta/pi, digits = 2), "*pi", 
    ", sin~theta==", round(sin(theta), digits = 2), 
    ")"
  )
  
  # sin関数曲線を作図
  sin_graph <- ggplot() + 
    geom_line(data = curve_df, 
              mapping = aes(x = t, y = sin_t), 
              size = 1) + # sin曲線
    geom_point(data = point_df, 
               mapping = aes(x = t, y = sin_t), 
               size = 4) + # 曲線上の点
    geom_segment(data = segment_sin_df, 
                 mapping = aes(x = x, y = y, xend = x_to, yend = y_to), 
                 size = 1, linetype = "dotted") + # 変換曲線との対応線
    geom_vline(xintercept = theta, size = 1, linetype = "dotted") + # x軸との対応線
    scale_x_continuous(breaks = numer_vec/denom*pi, 
                       labels = parse(text = label_vec)) + # 角度目盛ラベル
    coord_fixed(ratio = 1, clip = "off", 
                xlim = c(theta_min, theta), ylim = c(-y_size, y_size)) + # 描画領域
    labs(title = "sine function", 
         subtitle = parse(text = sin_label), 
         x = expression(theta), 
         y = expression(sin~theta))
  
  # 並べて描画
  graph <- patchwork::wrap_plots(
    csc_graph, adapt_graph, 
    sin_graph, circle_graph, 
    nrow = 2, ncol = 2, 
    widths  = c(pi/x_size, 1), 
    heights = c(x_size/y_size, 1)
  )
  
  # ファイルを書き出し
  file_path <- paste0(dir_path, "/", stringr::str_pad(i, width = nchar(frame_num), pad = "0"), ".png")
  ggplot2::ggsave(filename = file_path, plot = graph, width = 1200, height = 1000, units = "px", dpi = 100)
  
  # 途中経過を表示
  message("\r", i, " / ", frame_num, appendLF = FALSE)
}

 「1周期」のときと同様に処理します。こちらは、軸目盛の関係から上下左右の図を入れ替えます。そのため、対応線の方向などが変わっています。

 「1周期」のときのコードで、csc関数とsin関数のアニメーションを作成します。

単位円におけるなす角とcsc関数の関係


 この記事では、csc関数を可視化しました。次の記事では、cot関数を可視化します。

参考書籍

  • 『三角関数(改定第3版)』(Newton別冊)ニュートンプレス,2022年.

おわりに

 一番わけ分かめ図になってしまった気がしますが、これでも頭を捻って考えたんです。私自身としては一応納得できたのでアップしました。理解の助けになれば幸いです。
 作業順としてはこの記事が6つ目です。あとは全部載せを作れば完了です。

 2023年7月2日は、Juice=Juiceの元リーダーの金澤朋子さんの28歳のお誕生日です。

 かなともならどこでもやっていけるだろうことは想像に難くないけど、楽しく歌っていられる環境だといいな。

【次の内容】

www.anarchive-beta.com