Skip to content

Commit

Permalink
fix angles
Browse files Browse the repository at this point in the history
  • Loading branch information
wjschne committed Feb 3, 2025
1 parent c8c65b3 commit 9e6a09e
Show file tree
Hide file tree
Showing 51 changed files with 107 additions and 6,509 deletions.
1 change: 1 addition & 0 deletions .github/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.html
49 changes: 49 additions & 0 deletions .github/workflows/pkgdown.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
push:
branches: [main, master]
pull_request:
release:
types: [published]
workflow_dispatch:

name: pkgdown.yaml

permissions: read-all

jobs:
pkgdown:
runs-on: ubuntu-latest
# Only restrict concurrency for non-PR jobs
concurrency:
group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }}
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
permissions:
contents: write
steps:
- uses: actions/checkout@v4

- uses: r-lib/actions/setup-pandoc@v2

- uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true

- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::pkgdown, local::.
needs: website

- name: Build site
run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
shell: Rscript {0}

- name: Deploy to GitHub pages 🚀
if: github.event_name != 'pull_request'
uses: JamesIves/[email protected]
with:
clean: false
branch: gh-pages
folder: docs
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ vignettes/*.R
*_cache/
/*_files/
docs/
docs
2 changes: 1 addition & 1 deletion R/a_early.R
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ S7::method(`[<-`, has_style) <- function(x, y, value) {
}
}
new_x <- rlang::inject(.fn(!!!d))
if (prop_exists(new_x, "vertex_radius")) {
if (S7::prop_exists(new_x, "vertex_radius")) {
new_x@vertex_radius <- x@vertex_radius
}
new_x
Expand Down
17 changes: 17 additions & 0 deletions vignettes/_freeze/articles/angle/execute-results/html.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"hash": "70d265da61f07f01bc725867fcc78ced",
"result": {
"engine": "knitr",
"markdown": "---\ntitle: \"Angles\"\nformat: \n html:\n toc: true\n html-math-method: katex\nvignette: >\n %\\VignetteIndexEntry{angles}\n %\\VignetteEngine{quarto::html}\n %\\VignetteEncoding{UTF-8}\n---\n\n\n\n\n\n# Setup\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(ggdiagram)\nlibrary(ggplot2)\nlibrary(dplyr)\nlibrary(ggtext)\nlibrary(ggarrow)\nmy_font <- \"Roboto Condensed\"\nmy_arrow_head <- arrowheadr::arrow_head_deltoid(d = 2.3, n = 100)\n```\n:::\n\n\n\n# Angles\n\nAngles have different kinds of units associated with them: turns (1 turn = one full rotation a circle), degrees (1 turn = 360 degrees), and radians (1 turn = $2\\pi$ = $\\tau$).\n\nI like &pi; just fine, but I agree with Michael Hartl's [Tau Manifesto](https://tauday.com/tau-manifesto) that we would have been better off if we had recognized that the number of radians to complete a full turn of a circle (&tau; = 2&pi; &asymp; 6.283185) is more fundamental than the number of radians to complete a half turn (&pi;). \n\nTurns | Radians | Degrees |\n:----:|:-------:|:-------:|\n$\\frac{1}{12}$ | $\\frac{\\tau}{12}=\\frac{\\pi}{6}$ | $30^\\circ$ |\n$\\frac{1}{8}$ | $\\frac{\\tau}{8}=\\frac{\\pi}{4}$ | $45^\\circ$ |\n$\\frac{1}{6}$ | $\\frac{\\tau}{6}=\\frac{\\pi}{3}$ | $60^\\circ$ |\n$\\frac{1}{4}$ | $\\frac{\\tau}{4}=\\frac{\\pi}{2}$ | $90^\\circ$ |\n$\\frac{1}{3}$ | $\\frac{\\tau}{3}=\\frac{2\\pi}{3}$ | $120^\\circ$ |\n$\\frac{1}{2}$ | $\\frac{\\tau}{2}=\\pi$ | $180^\\circ$ |\n$1$ | $\\tau=2\\pi$ | $360^\\circ$ |\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\ntheta <- degree(seq(0,330, 30))\nangle_types <- c(\"Turns\", \"Radians\", \"Degrees\")\ntheta_list <- lapply(list(turn, radian, degree), \\(.a) .a(theta))\n\np <- ob_polar(theta, r = 1)\n\n\nr <- seq(1, .5, length.out = length(angle_types))\nmy_shades <- (tinter::tinter(\"royalblue\", \n steps = 7, \n direction = \"tints\")[seq(length(angle_types))])\n\nggplot() +\n coord_equal() +\n theme_void() +\n ob_circle(\n center = ob_point(),\n radius = r,\n fill = my_shades,\n color = NA,\n linewidth = .25\n ) +\n ob_segment(ob_point(), p, linewidth = .25) +\n purrr::pmap(\n .l = list(r, theta_list, my_shades), \n .f = \\(rs, ts, ss) {\n ob_circle(radius = rs - 1/8)@point_at(ts)@label(ts, fill = ss, size = 16)@geom(family = my_font)\n }) +\n ob_point(0, y = r - 1/18)@label(angle_types, \n fill = my_shades, \n fontface = \"bold\", \n family = my_font,\n size = 16)\n\n```\n\n::: {.cell-output-display}\n![Angle Metrics](angle_files/figure-html/fig-angles-1.png){#fig-angles width=768}\n:::\n:::\n\n\n\nOne can create equivalent angles with any of the three metrics.\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ndegree(90)\n#> 90°\nturn(1 / 4)\n#> .25\nradian(pi / 2)\n#> 0.5π\n```\n:::\n\n\n\nAlthough these methods have convenient printing, under the hood they are `ob_angle` objects can retrieve angle in any of the the three metrics.\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nradian(pi)\n#> π\nradian(pi)@degree\n#> [1] 180\nradian(pi)@turn\n#> [1] 0.5\n\ndegree(180)\n#> 180°\ndegree(180)@turn\n#> [1] 0.5\ndegree(180)@radian\n#> [1] 3.141593\n\nturn(.5)\n#> .50\nturn(.5)@radian\n#> [1] 3.141593\nturn(.5)@degree\n#> [1] 180\n```\n:::\n\n\n\n\n\n# Character Printing\n\nFor labeling, sometimes is convenient to convert angles to text:\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nas.character(degree(90))\n#> [1] \"90°\"\nas.character(turn(.25))\n#> [1] \".25\"\nas.character(radian(.5 * pi))\n#> [1] \"0.5π\"\n```\n:::\n\n\n\n## Angle Metric Conversions\n\nAny of the metrics can be converted to any other:\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\na <- degree(degree = 270)\na\n#> 270°\nradian(a)\n#> 1.5π\nturn(a)\n#> .75\n```\n:::\n\n\n\n\n# Arithmetic Operations\n\nAngles can be added, subtracted, multiplied, and divided. The underlying value stored can be any real number (in turn units), but degrees, radians, and turns are always displayed as between &minus;1 and +1 turns, &pm;360 degrees, or &pm;2&pi; radians.\n\n30&deg; + 60&deg; = 90&deg;\n\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nmake_angles <- function(a = c(80, 300), \n r = c(.1, .2, .3), \n label_adjust = c(0,0,0), \n multiplier = c(1.4,1.4,1.4)) {\nstart_angles <- degree(c(0,a[1], 0))\nend_angles <- degree(c(a[1], sum(a), degree(sum(a))@degree))\n\narc_labels <- as.character(end_angles - start_angles)\n\nmycolors <- c(\"firebrick4\", \"royalblue3\", \"orchid4\")\n\n\narc_labels[3] <- paste0(arc_labels[1],\n \" + \", \n arc_labels[2],\n \" = \", \n arc_labels[3])\n\narcs <- ob_arc(radius = r, \n start = start_angles, \n end = end_angles,\n label = ob_label(arc_labels, \n color = mycolors, \n family = my_font),\n linewidth = .25,\n length_head = 10,\n arrow_head = arrowheadr::arrow_head_deltoid(),\n color = mycolors)\n\n\n\nggplot() +\n theme_void() +\n coord_equal() +\n arcs +\n ob_segment(\n p1 = ob_point(), \n p2 = ob_polar(theta = degree(c(0,a[1],sum(a))), r = 1), \n length_head = 5,\n linewidth = .75,\n arrow_head = arrowheadr::arrow_head_deltoid(),\n color = c(\"firebrick\", \"firebrick\", \"royalblue\")) \n}\n\n```\n:::\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nmake_angles(a = c(30, 60), \n r = c(.12,.24, .36), \n multiplier = c(1.5,1.5,1.5)) \n```\n\n::: {.cell-output-display}\n![30&deg; + 60&deg; = 90&deg;](angle_files/figure-html/fig-3060-1.png){#fig-3060 width=672}\n:::\n:::\n\n::: {.cell}\n\n```{.r .cell-code}\ndegree(30) + degree(60)\n#> 90°\n```\n:::\n\n\n\nAdding a number to the degree class assumes the number is in the degree metric.\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ndegree(30) + 10\n#> 40°\n```\n:::\n\n\n\nLikewise, adding a number to a radian (or an angle by default) makes a radian:\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nradian(pi) + 0.5 * pi\n#> 1.5π\n```\n:::\n\n\n\nTurns work the same way:\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nturn(.1) + .2\n#> .30\n```\n:::\n\n\n\nWhen degrees are outside the range of &pm;360, they recalculate:\n\n$$\n\\begin{aligned}\n80^{\\circ} + 300^\\circ &= 380^\\circ\\\\\n&= 380^\\circ-360^\\circ\\\\\n&=20^\\circ\\end{aligned}\n$$\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nmake_angles(c(80, 300)) \n```\n\n::: {.cell-output-display}\n![80&deg; + 300&deg; = 380&deg; = 20&deg;](angle_files/figure-html/fig-80300-1.png){#fig-80300 width=672}\n:::\n:::\n\n::: {.cell}\n\n```{.r .cell-code}\ndegree(80) + degree(300)\n#> 20°\n```\n:::\n\n\n\n\n\n\n$$\n\\begin{aligned}\n20^\\circ - 40^\\circ &= -20^\\circ\\\\&=340^\\circ\n\\end{aligned}\n$$\n\n\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\nmake_angles(c(40, -60)) \n\n```\n\n::: {.cell-output-display}\n![40&deg; &minus; 60&deg; = &minus;20&deg;](angle_files/figure-html/fig-neg-1.png){#fig-neg width=672}\n:::\n:::\n\n::: {.cell}\n\n```{.r .cell-code}\ndegree(40) - degree(60)\n#> −20°\n```\n:::\n\n\n\n$$2\\cdot20^\\circ=40^\\circ$$\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n2 * degree(20)\n#> 40°\n```\n:::\n\n\n\n$$\n\\begin{aligned}\n2\\cdot180 &= 360^\\circ\\\\&=0^\\circ\n\\end{aligned}\n$$\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n2 * degree(180)\n#> 0°\n```\n:::\n\n\n\n# Trigonometry\n\nThe outputs of `degree`, `radian`, and `turn` can take the three standard trigonometric functions\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ntheta <- degree(60)\ncos(theta)\n#> [1] 0.5\nsin(theta)\n#> [1] 0.8660254\ntan(theta)\n#> [1] 1.732051\n```\n:::\n\n::: {.cell}\n\n```{.r .cell-code code-fold=\"true\"}\no <- ob_point(0, 0)\np <- ob_polar(theta, 1)\n\n# col <- purrr::map2_chr(scico::scico(6, palette = \"hawaii\"),\n# c(0.01,0.01,0.01,0.01,.15, .4), \n# tinter::darken)\n\nmy_colors <- c(\"#8C0172\", \"#944046\", \"#9B7424\", \n \"#8EB63B\", \"#53BD91\", \"#6C939A\")\nggdiagram() +\n ob_circle(fill = NA, color = \"gray\") +\n # axes\n ob_line(intercept = 0,\n color = \"gray\",\n linewidth = .25) +\n ob_line(xintercept = 0,\n color = \"gray\",\n linewidth = .25) +\n # degree arc\n ob_arc(\n end = theta,\n radius = .25,\n label = theta,\n linewidth = .2\n ) +\n # angle arrow\n connect(o, p, label = \"*r* = 1\", resect_head = 1) +\n # sin(theta)\n ob_segment(\n ob_polar(theta = 0, r = cos(theta)),\n p,\n label = paste0(\"sin(\", \n theta, \n \") = \", \n round(sin(theta), 2)),\n color = my_colors[1],\n linewidth = .5\n ) +\n # cos(theta)\n ob_segment(\n ob_point(0, sin(theta)),\n ob_point(cos(theta), sin(theta)),\n label = ob_label(\n paste0(\n \"cos(\",\n theta,\n \") = \",\n round(cos(theta), 2)), vjust = 1),\n color = my_colors[2],\n linewidth = .5\n ) +\n # tan(theta)\n ob_segment(\n p,\n p + ob_polar(theta - 90, r = tan(theta)),\n label = paste0(\n \"tan(\",\n theta,\n \") = \",\n round(tan(theta), 2)),\n color = my_colors[3],\n linewidth = .5\n ) +\n # sec(theta)\n ob_segment(\n o,\n ob_point(1 / cos(theta)),\n label = ob_label(\n label = paste0(\n \"sec(\",\n theta,\n \") = \",\n round(1 / cos(theta), 2)),\n vjust = 1\n ),\n color = my_colors[5]\n ) +\n # cot(theta)\n ob_segment(\n p + ob_polar(theta + 90, r = 1 / tan(theta)),\n p,\n label = paste0(\n \"cot(\",\n theta,\n \") = \",\n round(1 / tan(theta), 2)),\n color = my_colors[4],\n linewidth = .5\n ) +\n # csc(theta)\n ob_segment(\n o,\n ob_point(0, 1 / sin(theta)),\n label = paste0(\n \"csc(\",\n theta,\n \") = \",\n round(1 / sin(theta), 2)),\n color = my_colors[6]\n ) \n \n```\n\n::: {.cell-output-display}\n![Trigonometric functions](angle_files/figure-html/fig-trig-1.png){#fig-trig width=864}\n:::\n:::\n\n\n\n\nBenefits of using trigonometric functions with angles instead of numeric radians include:\n\n* Angle metric conversions are handled automatically.\n* Under the hood, the `cospi`, `sinpi`, and `tanpi` functions are used to get the rounding right on key locations (e.g., 90 degrees, 180 degrees)\n\nFor example, `tan(pi)` is slightly off from its true value of 0.\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ntan(pi)\n#> [1] -1.224647e-16\n```\n:::\n\n\n\nBy contrast, `tan(radian(pi))` rounds to 0 exactly.\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ntan(radian(pi))\n#> [1] 0\n```\n:::\n\n\n\n# Retrieving the underlying data from a `ob_angle` object\n\nAngles created with the `degree`, `radian`, or `turn` function are `ob_angle` objects. The `ob_angle` function exists but is not meant to be used directly. Its underlying data is a vector of numeric data representing the number of turns. The underlying turn data from any `ob_angle` object can be extracted with the `c` function (or with the `S7::S7_data` function).\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\ntheta <- degree(c(0,180,360, 720))\n# Degrees range: 0<= degree < 360\ntheta@degree\n#> [1] 0 180 0 0\n# Underlying data in turns\nc(theta)\n#> [1] 0.0 0.5 1.0 2.0\n# Alternative method of extracting data\nS7::S7_data(theta)\n#> [1] 0.0 0.5 1.0 2.0\n```\n:::\n",
"supporting": [
"angle_files"
],
"filters": [
"rmarkdown/pagebreak.lua"
],
"includes": {},
"engineDependencies": {},
"preserve": {},
"postProcess": true
}
}
Loading

0 comments on commit 9e6a09e

Please sign in to comment.