はじめに
R言語で三角関数の定義や公式を可視化しようシリーズです。
この記事では、csc関数のグラフを作成します。
【前の内容】
【他の記事一覧】
【この記事の内容】
csc関数の可視化
三角関数(trigonometric functions)・円関数(circular functions)の1つであるcsc関数(余割関数・コセカント関数・cosecant function)をグラフで確認します。
ggplot2パッケージなどを使って作図します。
・作図コード(クリックで展開)
利用するパッケージを読み込みます。
# 利用パッケージ library(tidyverse) library(gganimate) library(patchwork) library(magick)
この記事では、基本的にパッケージ名::関数名()
の記法を使うので、パッケージを読み込む必要はありません。ただし、作図コードがごちゃごちゃしないようにパッケージ名を省略しているためggplot2
を読み込む必要があります。
また、ネイティブパイプ演算子|>
を使っています。magrittr
パッケージのパイプ演算子%>%
に置き換えても処理できますが、その場合はmagrittr
も読み込む必要があります。
定義式の確認
まずは、csc関数の定義式を確認します。
csc関数は、sin関数の逆数で定義されます。
はサイン関数です。sin関数については「【R】sin関数の可視化 - からっぽのしょこ」を参照してください。
ただし、 を整数として
のとき、
なので、0除算になるため定義できません。
は円周率で、変数
は弧度法の角度(ラジアン)です。
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_vec
とします。円周率 は
pi
で扱えます。
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
の値と
の値をデータフレームに格納します。cot関数は
sin()
を使って計算できます。sin関数の値は比較に使います。
(
は整数)付近で
または
に近付くので、閾値
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"
角度 に関する軸目盛ラベルを
を整数として
の形で表示することにします。
を
denom
として整数を指定します。 は、半周期
の範囲における目盛の数に対応します。
theta_vec
に対して、 を
について整理した
を計算して、最小値(の小数部分を
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_vec
の範囲内の の値を(上手いことして)作成します。
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))
x軸を 、y軸を
として、
geom_line()
でcsc関数の曲線を描画します。また、 の曲線を点線で描画します。
x軸が の点(
の前後
間隔)に、
geom_vline()
で漸近線を破線で描画します。
となる
が漸近線なのが分かります。
単位円の作図
続いて、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
円周の座標計算用のラジアンとして の範囲の値を作成して、x軸の値
、y軸の値
を計算します。
円周上に角度(ラジアン)目盛を描画するためのデータフレームを作成します。
# 半円の目盛の数(分母の値)を指定 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
円周上の点の座標計算に用いる変数(ラジアン) を
theta
として値を指定します。ただし、theta
が0
のとき計算結果に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
の値と
の値をデータフレームに格納します。
角マークを描画するためのデータフレームを作成します。
# 角マークの座標を計算 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つの線分のなす角 を示す角マークを描画するために、
から
までのラジアンを作成して、円弧の座標を計算します。サイズの調整用の値(半径)を
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
角マークの中点に角ラベルを配置するために、 のラジアンを作成して、円弧上の点の座標を計算します。表示位置の調整用の値(原点からのノルム)を
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
原点と点 を結ぶ線分(x軸線の正の部分)と、原点と円周上の点
を結ぶ線分を描画するために、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
この例では、関数を示す線分の中点に関数名を表示するため、中点の座標とラベル用の文字列などを格納します。
ただし、 の範囲でcsc直線が直感的でない座標になるので、
のときマイナスの符号を付けて表示することにします。
ラベルの表示角度を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関数の値は、「原点と点
を通る直線」と「
の直線(破線)」の交点
と原点を結ぶ線分の長さです。ただし、
の範囲では符号が反転します。
パターン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」の座標に加えて、 の範囲でも直感的な座標になるように、符号を反転させた線分の座標を格納します。
元の関数(線分)と符号を反転させた関数(線分)を、線の種類で描き分けることにします。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関数の符号は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
原点と点 を結ぶ線分(x軸線の正の部分)と、原点と円周上の点
を結ぶ線分を描画するために、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")
こちらの図は、原点と点 を結ぶ線分を底辺、y軸線の一部を斜辺としたときのパターン1の図と言えます。文字通り首を捻って見てください。
csc関数の値は、「原点と点 を通る直線」に対する「点
を通る垂線」と「
の直線(破線)」の交点
の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
を指定して、円周上の点の座標計算に用いる変数(ラジアン) の値を等間隔に
frame_num
個作成します。範囲を にして
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
の値と
の値をフレーム切替用のラベルとあわせて格納します。
角マークを描画するためのデータフレームを作成します。
# フレームごとの角マークの座標を計算 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
フレームごとの角マークの中点に角ラベルを配置するために、 のラジアンを作成して、円弧上の点の座標を計算します。
ここまでは、共通の処理です。ここからは、「グラフの作成」のときと同様に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
「グラフの作成」のときと同様に、フレーム数分の原点と点 の座標と、フレームごとの点
の座標、また補助線用の線分の座標を格納します。
三角関数を直線として描画するためのデータフレームを作成します。
# 関数ラベルのレベルを指定 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秒当たりのフレーム数を指定できます。
のとき
なので、原点と円周上の点を結ぶ線分が水平になり直線
と平行なため交点ができず、
を描画(定義)できないのが分かります。
パターン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
「グラフの作成」のときと同様に、フレーム数分の原点と点 の座標と、フレームごとの点
の座標、また補助線用の線分の座標を格納します。
三角関数を直線として描画するためのデータフレームを作成します。
# 関数直線の線分の座標を格納 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)
パターン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
フレーム数分の点 の座標と、フレームごとの点
の座標を格納します。
三角関数を直線として描画するためのデータフレームを作成します。
# 関数直線の線分の座標を格納 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関数曲線の関係の可視化
最後は、単位円上における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
曲線上の点の座標計算に用いる変数(ラジアン) を
theta
として値を指定します。ただし、theta
が0
のとき計算結果に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直線の座標について、直線 上の点
と直線
上の点
を格納します。
垂直線になるように直線を回転する軌道を描画するためのデータフレームを作成します。
# 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
軸を変換する軌道として、半径が の弧を描画します。全体値
は
abs()
で計算できます。
任意の範囲で設定したラジアン を
の範囲のラジアンに変換します。コサイン関数
の逆関数(逆コサイン関数)
を使って、
で計算します。逆コサイン関数は
acos()
で計算できます。
のとき(
のとき)第1象限からy軸の正の部分への変化を示すため
のラジアン、
のとき(
のとき)第2象限からy軸の負の部分への変化を示すため
のラジアンを用いて、弧のx軸の値
とy軸の値
を計算します。
単位円における点と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_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関数の作図」のときと同様に、作図します。
2つのグラフを並べて描画します。
# 並べて描画 patchwork::wrap_plots(circle_graph, csc_graph)
patchwork
パッケージのwrap_plots()
を使ってグラフを並べます。
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直線の座標について、直線 上の点
と直線
上の点
を格納します。
水平線になるように直線を回転する軌道を描画するためのデータフレームを作成します。
# 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
のとき(
のとき)第1象限からx軸の正の部分への変化を示すため
のラジアン、
のとき(
のとき)第2象限からx軸の負の部分への変化を示すため
のラジアンを用いて、弧のx軸の値
とy軸の値
を計算します。
単位円における点と軸の変換図上の点を結ぶ補助線(の半分)を描画するためのデータフレームを作成します。
# グラフサイズ用の値を設定 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関数の可視化」のときと同様に、作図します。
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
を で表します。軸を変換する軌道として、中心の座標が
で半径が
の弧を描画します。また、弧の中心が図の右上隅になるようにします。
を用いて、弧のx軸の値
とy軸の値
を計算します。
円の座標計算については「円周の作図」を参照してください。
軸の変換図のグリッド線を描画するためのデータフレームを作成します。
# 軸変換図のグリッド線の描画用 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()
で作成することで、半径ごとに曲線用のラジアンを複製します。
弧の座標を 、
で計算します。
軸の変換図上の点と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
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()
で指定します。
分かりやすい方の図を参考にしてください。
アニメーションの作成
続いて、変数の値を変化させたアニメーションで確認します。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
を指定して、円周上と曲線上の点の座標計算に用いるの変数(ラジアン)として の範囲で
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関数の線分の方向(
の符号)が変わり、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関数のアニメーションを作成します。
のとき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_i
の範囲が の倍数だと、アニメーションの最後と最初のフレームの繋がりが良くなります。
「グラフの作成」のときと同様に、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関数のアニメーションを作成します。
単位円上の点が1周する の間隔で、曲線が同じ形になるのが分かります。
パターン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関数を可視化しました。次の記事では、cot関数を可視化します。
参考書籍
- 『三角関数(改定第3版)』(Newton別冊)ニュートンプレス,2022年.
おわりに
一番わけ分かめ図になってしまった気がしますが、これでも頭を捻って考えたんです。私自身としては一応納得できたのでアップしました。理解の助けになれば幸いです。
作業順としてはこの記事が6つ目です。あとは全部載せを作れば完了です。
2023年7月2日は、Juice=Juiceの元リーダーの金澤朋子さんの28歳のお誕生日です。
かなともならどこでもやっていけるだろうことは想像に難くないけど、楽しく歌っていられる環境だといいな。
【次の内容】