This commit is contained in:
jverzani
2022-05-24 13:51:49 -04:00
parent 5c0fd1b6fe
commit 244f492f9e
240 changed files with 65211 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
[deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
Contour = "d38c429a-6771-53c6-b99e-75d170b6e991"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MDBM = "dd61e66b-39ce-57b0-8813-509f78be4b4d"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee"
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
SymPy = "24249f21-da20-56a4-8eb1-6a02cf4ae2e6"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,29 @@
From [bennedich](https://discourse.julialang.org/t/love-in-245-characters-code-golf/20771)
```
0:2e-3:2π .|>d->(P=
fill(5<<11,64 ,25);z=8cis(
d)sin(.46d);P[ 64,:].=10;for
r=0:98,c=0 :5^3 x,y=@.mod(2-
$reim((.016c-r/49im-1-im)z),
4)-2;4-x^2>√2(y+.5-√√x^2)^
2&&(P[c÷2+1,r÷4+1]|=Int(
")*,h08H¨"[4&4c+1+r&
3])-40)end;print(
"\e[H\e[1;31m",
join(Char.(
P)))
);
```
[New York Times](https://www.nytimes.com/2019/02/14/science/math-algorithm-valentine.html)
Süss — German for “sweet” — is an interactive widget that allows you to tweak the algebra and customize the heart to your soulss delight. It was created for Valentines Day by Imaginary, a nonprofit organization in Berlin that designs open-source mathematics programs and exhibitions.
You can stretch and squeeze the heart by moving the two left-most sliders, which change the “a” and “b” parameters; the right-most slider zooms in and out. Better yet, canoodle directly with Süsss equation and engage in the dialectical interplay between algebra and geometry. (Change that final z³ to a z² to see the heart in its underwear.)
```
(x^2+((1+b)*y)^2+z^2-1)^3-x^2*z^3-a*y^2*z^3
```

View File

@@ -0,0 +1,72 @@
"","elevation","elev_units","longitude","latitude"
"1",126.85,"meters",-74.2986363,40.7541939
"2",125.19,"meters",-74.298561,40.754122
"3",123.52,"meters",-74.298505,40.754049
"4",121.92,"meters",-74.298435,40.753972
"5",119.86,"meters",-74.298402,40.753872
"6",119.86,"meters",-74.298416,40.753818
"7",119.86,"meters",-74.298393,40.753805
"8",118.32,"meters",-74.298233,40.753717
"9",118.48,"meters",-74.298113,40.753706
"10",118.48,"meters",-74.298079,40.753714
"11",110.65,"meters",-74.297548,40.753434
"12",108.68,"meters",-74.297364,40.753392
"13",108.68,"meters",-74.2973338,40.7533463
"14",107.67,"meters",-74.2972265,40.7533169
"15",107.54,"meters",-74.297087,40.753356
"16",107.54,"meters",-74.2970438,40.7533584
"17",106.74,"meters",-74.296979,40.753397
"18",107.69,"meters",-74.29689,40.753533
"19",108.01,"meters",-74.296812,40.753661
"20",108.34,"meters",-74.296718,40.753785
"21",108.93,"meters",-74.296627,40.753874
"22",109.26,"meters",-74.296514,40.753973
"23",109.44,"meters",-74.296377,40.754026
"24",107.8,"meters",-74.296184,40.754049
"25",108.14,"meters",-74.29596,40.754119
"26",108.31,"meters",-74.295761,40.754191
"27",107.08,"meters",-74.295542,40.754277
"28",106.54,"meters",-74.295345,40.754276
"29",105.18,"meters",-74.295177,40.754295
"30",104.93,"meters",-74.2951,40.754358
"31",103.79,"meters",-74.294976,40.754381
"32",103.79,"meters",-74.294943,40.754379
"33",103.62,"meters",-74.294873,40.754362
"34",103.46,"meters",-74.294805,40.754359
"35",102.68,"meters",-74.294687,40.754349
"36",102.78,"meters",-74.294537,40.754269
"37",100.91,"meters",-74.294341,40.754248
"38",101.24,"meters",-74.294228,40.754249
"39",101.15,"meters",-74.294146,40.75427
"40",100.73,"meters",-74.294043,40.754277
"41",100.77,"meters",-74.293997,40.75418
"42",97.54,"meters",-74.293672,40.75418
"43",97.58,"meters",-74.293539,40.754324
"44",97.41,"meters",-74.293442,40.754447
"45",97.02,"meters",-74.29342,40.754555
"46",96.78,"meters",-74.293397,40.754677
"47",96.72,"meters",-74.293319,40.754787
"48",96.98,"meters",-74.2933093,40.7549621
"49",97.04,"meters",-74.2931914,40.7550903
"50",95.89,"meters",-74.2931359,40.7552002
"51",95.48,"meters",-74.293124,40.75528
"52",95.43,"meters",-74.293142,40.755375
"53",95.58,"meters",-74.293163,40.7554692
"54",95.58,"meters",-74.2931806,40.7555174
"55",95.31,"meters",-74.2930826,40.7555402
"56",95.45,"meters",-74.2930283,40.7555572
"57",94.19,"meters",-74.2929292,40.7555853
"58",93.57,"meters",-74.2928114,40.7556067
"59",92.9,"meters",-74.2927408,40.7556127
"60",92.9,"meters",-74.2926921,40.7556257
"61",91.46,"meters",-74.2926528,40.7556602
"62",91.46,"meters",-74.2926104,40.7556888
"63",88.42,"meters",-74.2925696,40.7557042
"64",88.42,"meters",-74.2925272,40.7556876
"65",85.62,"meters",-74.2924927,40.7556674
"66",85.32,"meters",-74.2924503,40.755646
"67",85.32,"meters",-74.2924377,40.7556222
"68",85.32,"meters",-74.2924377,40.7555877
"69",84.49,"meters",-74.2924346,40.7555365
"70",84.49,"meters",-74.2924236,40.755502
"71",84.36,"meters",-74.2923562,40.7554961
1 elevation elev_units longitude latitude
2 1 126.85 meters -74.2986363 40.7541939
3 2 125.19 meters -74.298561 40.754122
4 3 123.52 meters -74.298505 40.754049
5 4 121.92 meters -74.298435 40.753972
6 5 119.86 meters -74.298402 40.753872
7 6 119.86 meters -74.298416 40.753818
8 7 119.86 meters -74.298393 40.753805
9 8 118.32 meters -74.298233 40.753717
10 9 118.48 meters -74.298113 40.753706
11 10 118.48 meters -74.298079 40.753714
12 11 110.65 meters -74.297548 40.753434
13 12 108.68 meters -74.297364 40.753392
14 13 108.68 meters -74.2973338 40.7533463
15 14 107.67 meters -74.2972265 40.7533169
16 15 107.54 meters -74.297087 40.753356
17 16 107.54 meters -74.2970438 40.7533584
18 17 106.74 meters -74.296979 40.753397
19 18 107.69 meters -74.29689 40.753533
20 19 108.01 meters -74.296812 40.753661
21 20 108.34 meters -74.296718 40.753785
22 21 108.93 meters -74.296627 40.753874
23 22 109.26 meters -74.296514 40.753973
24 23 109.44 meters -74.296377 40.754026
25 24 107.8 meters -74.296184 40.754049
26 25 108.14 meters -74.29596 40.754119
27 26 108.31 meters -74.295761 40.754191
28 27 107.08 meters -74.295542 40.754277
29 28 106.54 meters -74.295345 40.754276
30 29 105.18 meters -74.295177 40.754295
31 30 104.93 meters -74.2951 40.754358
32 31 103.79 meters -74.294976 40.754381
33 32 103.79 meters -74.294943 40.754379
34 33 103.62 meters -74.294873 40.754362
35 34 103.46 meters -74.294805 40.754359
36 35 102.68 meters -74.294687 40.754349
37 36 102.78 meters -74.294537 40.754269
38 37 100.91 meters -74.294341 40.754248
39 38 101.24 meters -74.294228 40.754249
40 39 101.15 meters -74.294146 40.75427
41 40 100.73 meters -74.294043 40.754277
42 41 100.77 meters -74.293997 40.75418
43 42 97.54 meters -74.293672 40.75418
44 43 97.58 meters -74.293539 40.754324
45 44 97.41 meters -74.293442 40.754447
46 45 97.02 meters -74.29342 40.754555
47 46 96.78 meters -74.293397 40.754677
48 47 96.72 meters -74.293319 40.754787
49 48 96.98 meters -74.2933093 40.7549621
50 49 97.04 meters -74.2931914 40.7550903
51 50 95.89 meters -74.2931359 40.7552002
52 51 95.48 meters -74.293124 40.75528
53 52 95.43 meters -74.293142 40.755375
54 53 95.58 meters -74.293163 40.7554692
55 54 95.58 meters -74.2931806 40.7555174
56 55 95.31 meters -74.2930826 40.7555402
57 56 95.45 meters -74.2930283 40.7555572
58 57 94.19 meters -74.2929292 40.7555853
59 58 93.57 meters -74.2928114 40.7556067
60 59 92.9 meters -74.2927408 40.7556127
61 60 92.9 meters -74.2926921 40.7556257
62 61 91.46 meters -74.2926528 40.7556602
63 62 91.46 meters -74.2926104 40.7556888
64 63 88.42 meters -74.2925696 40.7557042
65 64 88.42 meters -74.2925272 40.7556876
66 65 85.62 meters -74.2924927 40.7556674
67 66 85.32 meters -74.2924503 40.755646
68 67 85.32 meters -74.2924377 40.7556222
69 68 85.32 meters -74.2924377 40.7555877
70 69 84.49 meters -74.2924346 40.7555365
71 70 84.49 meters -74.2924236 40.755502
72 71 84.36 meters -74.2923562 40.7554961

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,294 @@
## container of points into vectors n vectors of length N
## N points, each of size n
## Lesson learned -- this is a very bad idea!
## better to handle the T a different way
evec(T,n) = Tuple(T[] for _ in 1:n)
evec(T, N, n) = Tuple(Vector{T}(undef, N) for _ in 1:n)
## julia> @btime xs_ys1(vs) setup=(vs=[randn(1000) for i in 1:3]);
## 83.308 μs (1013 allocations: 172.67 KiB)
## julia> @btime xs_ys2(vs) setup=(vs=[randn(1000) for i in 1:3]);
## 222.371 μs (2016 allocations: 180.72 KiB)
## julia> @btime xs_ys3(vs) setup=(vs=[randn(1000) for i in 1:3]);
## 1.003 ms (1019 allocations: 165.20 KiB)
## julia> @btime xs_ys4(vs) setup=(vs=[randn(1000) for i in 1:3]);
## 1.115 ms (5474 allocations: 210.95 KiB)
## julia> @btime xs_ys5(vs) setup=(vs=[randn(1000) for i in 1:3]);
## 1.120 ms (5474 allocations: 210.95 KiB)
## julia> @btime xs_ys6(vs) setup=(vs=[randn(1000) for i in 1:3]);
## 76.604 μs (1008 allocations: 164.63 KiB)
## julia> @btime xs_ys7(vs) setup=(vs=[randn(1000) for i in 1:3]);
## 74.306 μs (1008 allocations: 164.63 KiB)
## julia> @btime xs_ys8(vs) setup=(vs=[randn(1000) for i in 1:3]);
## 36.098 μs (2006 allocations: 94.25 KiB)
## julia> @btime xs_ys9(vs) setup=(vs=[randn(1000) for i in 1:3]);
## 85.732 μs (3006 allocations: 203.63 KiB)
## ....
## THE WINNER, but we would use one with keywords
## julia> @btime xs_ys13a(vs) setup=(vs=[randn(1000) for i in 1:3]);
## 62.768 μs (1003 allocations: 117.28 KiB)
## julia> @btime xs_ys13akw(vs) setup=(vs=[randn(1000) for i in 1:3]);
## 65.905 μs (1003 allocations: 117.28 KiB)
## make a matrix n x N, then go down 1:n
function xs_ys1(vs)
A=hcat(vs...)
Tuple([A[i,:] for i in eachindex(first(vs))])
end
## broadcast push!
function xs_ys2(vs)
u = first(vs); N = length(vs)
T = eltype(u); n = length(u)
v0 = evec(T,n)
for v in vs
push!.(v0, v)
end
v0
end
## broadcast push!
function xs_ys2a(vs)
u = first(vs); N = length(vs)
n = length(u)
v0 = Tuple(eltype(u)[] for _ in eachindex(u))
for v in vs
push!.(v0, v)
end
v0
end
## broadcast setindex!
function xs_ys3(vs)
u = first(vs); N = length(vs)
T = eltype(u); n = length(u)
v0 = evec(T,N,n)
for (i,v) in enumerate(vs)
setindex!.(v0, v, i)
end
v0
end
## 10 times faster ~77mus avoiding passing T
function xs_ys3a(vs)
u = first(vs); N = length(vs)
n = length(u)
v0 = Tuple(Vector{eltype(u)}(undef, N) for _ in eachindex(u))
for (i,v) in enumerate(vs)
setindex!.(v0, v, i)
end
v0
end
function xs_ys3b(vs)
u = first(vs); N = length(vs)
n = length(u)
v0 = ntuple(_ -> Vector{eltype(u)}(undef, N), n)
for (i,v) in enumerate(vs)
setindex!.(v0, v, i)
end
v0
end
## loop N n
function xs_ys4(vs)
u = first(vs); N = length(vs)
T = eltype(u); n = length(u)
v0 = evec(T,N,n)
for i in 1:N
for j in 1:n
v0[j][i] = vs[i][j]
end
end
v0
end
## loop N n
function xs_ys4a(vs)
u = first(vs); N = length(vs)
T = eltype(u); n = length(u)
v0 = evec(T,N,n)
for (i,v) in enumerate(vs)
for j in 1:n
v0[j][i] = v[j]
end
end
v0
end
## fast 67mus
function xs_ys4b(vs)
u = first(vs); N = length(vs)
n = length(u)
v0 = Tuple(Vector{eltype(u)}(undef, N) for _ in eachindex(u))
for (i,v) in enumerate(vs)
for j in 1:n
v0[j][i] = v[j]
end
end
v0
end
## loop n N
function xs_ys5(vs)
u = first(vs); N = length(vs)
T = eltype(u); n = length(u)
v0 = evec(T,N,n)
for j in 1:n
for i in 1:N
v0[j][i] = vs[i][j]
end
end
v0
end
function xs_ys6(vs)
u = first(vs); N = length(vs)
T = eltype(u); n = length(u)
A = Matrix{T}(undef, (N,n))
for (i,v) in enumerate(vs)
A[i,:] = v
end
Tuple(A[:,i] for i in 1:n)
end
function xs_ys7(vs)
u = first(vs); N = length(vs)
T = eltype(u); n = length(u)
A = Matrix{T}(undef, (n, N))
for (i,v) in enumerate(vs)
A[:,i] = v
end
Tuple(A[i, :] for i in 1:n)
end
# faster but doesn't wotk with plot recipes
# and may be slower once realized
function xs_ys8(vs)
N = length(vs)
u = first(vs); T = eltype(u); n = length(u)
Tuple((vs[j][i] for j in 1:N) for i in 1:n)
end
function xs_ys9(vs)
N = length(vs)
u = first(vs); T = eltype(u); n = length(u)
Tuple(collect(vs[j][i] for j in 1:N) for i in 1:n)
end
function xs_ys10(vs)
N = length(vs)
u = first(vs); T = eltype(u); n = length(u)
v0 = evec(T,N, n)
for j in 1:n
v0[j][:] .= (v[j] for v in vs)
end
v0
end
# mauro3 https://github.com/JuliaDiffEq/ODE.jl/issues/80
_pluck(y,i) = eltype(first(y))[el[i] for el in y]
xs_ys11(vs) = Tuple(_pluck(vs, i) for i in eachindex(first(vs)))
# slower
xs_ys11a(vs) = ntuple(i->_pluck(vs, i), length(first(vs)))
# one liner
xs_ys11b(vs) = Tuple(eltype(first(vs))[el[i] for el in vs] for i in eachindex(first(vs)))
function xs_ys11c(vs)
u = first(vs)
Tuple(eltype(u)[el[i] for el in vs] for i in eachindex(u))
end
xs_ys11d(vs) = (u=first(vs); Tuple(eltype(u)[el[i] for el in vs] for i in eachindex(u)))
xs_ys11e(vs) = (u=first(vs); ntuple(i->eltype(u)[v[i] for v in vs], length(u)))
xs_ys11f(vs) = (u=first(vs);n::Int=length(u);T::DataType=eltype(u);ntuple(i->eltype(u)[v[i] for v in vs], n))
xs_ys11g(vs::Vector{Vector{T}}) where {T} = (u=first(vs);n::Int=length(u);ntuple(i->T[v[i] for v in vs], n))
@inline _pluck(T, y, i) = T[el[i] for el in y]
function xs_ys11b(vs)
T = eltype(first(vs))
Tuple(_pluck(T, vs, i) for i in eachindex(first(vs)))
end
function xs_ys12(vs)
N = length(vs)
u = first(vs); T = eltype(u); n = length(u)
Tuple(T[el[i] for el in vs] for i in eachindex(first(vs)))
end
function xs_ys12a(vs)
N = length(vs)
u = first(vs); T = eltype(u); n = length(u)
ntuple( i -> T[el[i] for el in vs], n)
end
function xs_ys11h(vs)
u = first(vs)
T = eltype(u)
Tuple(T[el[i] for el in vs] for i in eachindex(u))
end
function xs_ys11i(vs)
u = first(vs)
Tuple(eltype(u)[el[i] for el in vs] for i in eachindex(u))
end
function _xs_ys12(vs, u::Vector{T}) where {T}
Tuple(T[el[i] for el in vs] for i in eachindex(u))
end
xs_ys13(vs, u::Vector{T}=first(vs)) where {T} = Tuple(T[el[i] for el in vs] for i in eachindex(u))
xs_ys13a(vs, u::Vector{T}=first(vs), n::Val{N}=Val(length(u))) where {T,N} = ntuple(i -> T[el[i] for el in vs], n)
## cleaned up
function xs_ys13a(vs, u::Vector{T}=first(vs), n::Val{N}=Val(length(u))) where {T,N}
plucki = i -> T[el[i] for el in vs]
ntuple(plucki, n)
end
function xs_ys13akw(vs; u::Vector{T}=first(vs), n::Val{N}=Val(length(u))) where {T,N}
plucki = i -> T[el[i] for el in vs]
ntuple(plucki, n)
end
function xs_ys13b(vs, u::Vector{T}=first(vs), n::Val{N}=Val(length(u))) where {T,N}
Tuple(T[el[i] for el in vs] for i in eachindex(u))
end
xs_ys14(vs) = Tuple(eltype(vs[1])[vs[i][j] for i in 1:length(vs)] for j in 1:length(vs[1]))
xs_ys14a(vs) = Tuple([vs[i][j] for i in 1:length(vs)] for j in 1:length(first(vs)))

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 KiB

View File

@@ -0,0 +1,370 @@
# 2D and 3D plots in Julia with Plots
This section uses these add-on packages:
```julia
using CalculusWithJulia
using Plots
import Contour: contours, levels, level, lines, coordinates
using LinearAlgebra
using ForwardDiff
```
```julia; echo=false; results="hidden"
using CalculusWithJulia.WeaveSupport
const frontmatter = (
title = "2D and 3D plots in Julia with Plots",
description = "Calculus with Julia: 2D and 3D plots in Julia with Plots",
tags = ["CalculusWithJulia", "differentiable_vector_calculus", "2d and 3d plots in julia with plots"],
);
nothing
```
----
This covers plotting the typical 2D and 3D plots in Julia with the `Plots` package.
We will make use of some helper functions that will simplify plotting provided by the `CalculusWithJulia` package. As well, we will need to manipulate contours directly, so pull in the `Contours` package, using `import` to avoid name collisions and explicitly listing the methods we will use.
## Parametrically described curves in space
Let $r(t)$ be a vector-valued function with values in $R^d$, $d$ being $2$ or $3$. A familiar example is the equation for a line that travels in the direction of $\vec{v}$ and goes through the point $P$: $r(t) = P + t \cdot \vec{v}$.
A *parametric plot* over $[a,b]$ is the collection of all points $r(t)$ for $a \leq t \leq b$.
In `Plots`, parameterized curves can be plotted through two interfaces, here illustrated for $d=2$: `plot(f1, f2, a, b)` or `plot(xs, ys)`. The former is convenient for some cases, but typically we will have a function `r(t)` which is vector-valued, as opposed to a vector of functions. As such, we only discuss the latter.
An example helps illustrate. Suppose $r(t) = \langle \sin(t), 2\cos(t) \rangle$ and the goal is to plot the full ellipse by plotting over $0 \leq t \leq 2\pi$. As with plotting of curves, the goal would be to take many points between `a` and `b` and from there generate the $x$ values and $y$ values.
Let's see this with 5 points, the first and last being identical due to the curve:
```julia
r₂(t) = [sin(t), 2cos(t)]
ts = range(0, stop=2pi, length=5)
```
Then we can create the $5$ points easily through broadcasting:
```julia
vs = r₂.(ts)
```
This returns a vector of points (stored as vectors). The plotting function wants two collections: the set of $x$ values for the points and the set of $y$ values. The data needs to be generated differently or reshaped. The function `unzip` above takes data in this style and returns the desired format, returning a tuple with the $x$ values and $y$ values pulled out:
```julia
unzip(vs)
```
To plot this, we "splat" the tuple so that `plot` gets the arguments separately:
```julia
plot(unzip(vs)...)
```
This basic plot is lacking, of course, as there are not enough points. Using more initially is a remedy.
```julia; hold=true
ts = range(0, 2pi, length=100)
plot(unzip(r₂.(ts))...)
```
As a convenience, `CalculusWithJulia` provides `plot_parametric` to produce this plot. The interval is specified with the `a..b` notation, the points to plot are adaptively chosen:
```julia
plot_parametric(0..2pi, r₂) # interval first
```
### Plotting a space curve in 3 dimensions
A parametrically described curve in 3D is similarly created. For example, a helix is described mathematically by $r(t) = \langle \sin(t), \cos(t), t \rangle$. Here we graph two turns:
```julia;
r₃(t) = [sin(t), cos(t), t]
plot_parametric(0..4pi, r₃)
```
### Adding a vector
The tangent vector indicates the instantaneous direction one would travel were they walking along the space curve. We can add a tangent vector to the graph. The `quiver!` function would be used to add a 2D vector, but `Plots` does not currently have a `3D` analog. In addition, `quiver!` has a somewhat cumbersome calling pattern when adding just one vector. The `CalculusWithJulia` package defines an `arrow!` function that uses `quiver` for 2D arrows and a simple line for 3D arrows. As a vector incorporates magnitude and direction, but not a position, `arrow!` needs both a point for the position and a vector.
Here is how we can visualize the tangent vector at a few points on the helix:
```julia; hold=true
plot_parametric(0..4pi, r₃, legend=false)
ts = range(0, 4pi, length=5)
for t in ts
arrow!(r₃(t), r₃'(t))
end
```
```julia; echo=false
note("""Adding many arrows this way would be inefficient.""")
```
### Setting a viewing angle for 3D plots
For 3D plots, the viewing angle can make the difference in visualizing the key features. In `Plots`, some backends allow the viewing angle to be set with the mouse by clicking and dragging. Not all do. For such, the `camera` argument is used, as in `camera(azimuthal, elevation)` where the angles are given in degrees. If the $x$-$y$-$z$ coorinates are given, then `elevation` or *inclination*, is the angle between the $z$ axis and the $x-y$ plane (so `90` is a top view) and `azimuthal` is the angle in the $x-y$ plane from the $x$ axes.
## Visualizing functions from $R^2 \rightarrow R$
If a function $f: R^2 \rightarrow R$ then a graph of $(x,y,f(x,y))$ can be represented in 3D. It will form a surface. Such graphs can be most simply made by specifying a set of $x$ values, a set of $y$ values and a function $f$, as with:
```julia
xs = range(-2, stop=2, length=100)
ys = range(-pi, stop=pi, length=100)
f(x,y) = x*sin(y)
surface(xs, ys, f)
```
Rather than pass in a function, values can be passed in. Here they are generated with a list comprehension. The `y` values are innermost to match the graphic when passing in a function object:
```julia; hold=true
zs = [f(x,y) for y in ys, x in xs]
surface(xs, ys, zs)
```
Remembering if the `ys` or `xs` go first in the above can be
hard. Alternatively, broadcasting can be used. The command `f.(xs,ys)`
would return a vector, as the `xs` and `ys` match in shape--they are both column vectors. But the
*transpose* of `xs` looks like a *row* vector and `ys` looks like a
column vector, so broadcasting will create a matrix of values, as
desired here:
```julia
surface(xs, ys, f.(xs', ys))
```
This graph shows the tessalation algorithm. Here only the grid in the $x$-$y$ plane is just one cell:
```julia; hold=true
xs = ys = range(-1, 1, length=2)
f(x,y) = x*y
surface(xs, ys, f)
```
A more accurate graph, can be seen here:
```julia; hold=true
xs = ys = range(-1, 1, length=100)
f(x,y) = x*y
surface(xs, ys, f)
```
### Contour plots
Returning to the
The contour plot of $f:R^2 \rightarrow R$ draws level curves, $f(x,y)=c$, for different values of $c$ in the $x-y$ plane.
They are produced in a similar manner as the surface plots:
```julia; hold=true
xs = ys = range(-2,2, length=100)
f(x,y) = x*y
contour(xs, ys, f)
```
The cross in the middle corresponds to $c=0$, as when $x=0$ or $y=0$ then $f(x,y)=0$.
Similarly, computed values for $f(x,y)$ can be passed in. Here we change the function:
```julia; hold=true
f(x,y) = 2 - (x^2 + y^2)
xs = ys = range(-2,2, length=100)
zs = [f(x,y) for y in ys, x in xs]
contour(xs, ys, zs)
```
The chosen levels can be specified by the user through the `levels` argument, as in:
```julia; hold=true
f(x,y) = 2 - (x^2 + y^2)
xs = ys = range(-2,2, length=100)
zs = [f(x,y) for y in ys, x in xs]
contour(xs, ys, zs, levels = [-1.0, 0.0, 1.0])
```
If only a single level is desired, as scalar value can be specified. Though not with all backends for `Plots`. For example, this next graphic shows the $0$-level of the [devil](http://www-groups.dcs.st-and.ac.uk/~history/Curves/Devils.html)'s curve.
```julia; hold=true
a, b = -1, 2
f(x,y) = y^4 - x^4 + a*y^2 + b*x^2
xs = ys = range(-5, stop=5, length=100)
contour(xs, ys, f, levels=[0.0])
```
Contour plots are well known from the presence of contour lines on many maps. Contour lines indicate constant elevations. A peak is characterized by a series of nested closed paths. The following graph shows this for the peak at $(x,y)=(0,0)$.
```julia; hold=true
xs = ys = range(-pi/2, stop=pi/2, length=100)
f(x,y) = sinc(sqrt(x^2 + y^2)) # sinc(x) is sin(x)/x
contour(xs, ys, f)
```
Contour plots can be filled with colors through the `contourf` function:
```julia; hold=true
xs = ys = range(-pi/2, stop=pi/2, length=100)
f(x,y) = sinc(sqrt(x^2 + y^2))
contourf(xs, ys, f)
```
### Combining surface plots and contour plots
In `PyPlot` it is possible to add a contour lines to the surface, or projected onto an axis.
To replicate something similar, though not as satisfying, in `Plots` we use the `Contour` package.
```julia; hold=true
f(x,y) = 2 + x^2 + y^2
xs = ys = range(-2, stop=2, length=100)
zs = [f(x,y) for y in ys, x in xs]
p = surface(xs, ys, zs, legend=false, fillalpha=0.5)
## we add to the graphic p, then plot
for cl in levels(contours(xs, ys, zs))
lvl = level(cl) # the z-value of this contour level
for line in lines(cl)
_xs, _ys = coordinates(line) # coordinates of this line segment
_zs = 0 * _xs
plot!(p, _xs, _ys, lvl .+ _zs, alpha=0.5) # add on surface
plot!(p, _xs, _ys, _zs, alpha=0.5) # add on x-y plane
end
end
p
```
There is no hidden line calculuation, in place we give the contour lines a transparency through the argument `alpha=0.5`.
### Gradient and surface plots
The surface plot of $f: R^2 \rightarrow R$ plots $(x, y, f(x,y))$ as a surface. The *gradient* of $f$ is $\langle \partial f/\partial x, \partial f/\partial y\rangle$. It is a two-dimensional object indicating the direction at a point $(x,y)$ where the surface has the greatest ascent. Illurating the gradient and the surface on the same plot requires embedding the 2D gradient into the 3D surface. This can be done by adding a constant $z$ value to the gradient, such as $0$.
```julia; hold=true
f(x,y) = 2 - (x^2 + y^2)
xs = ys = range(-2, stop=2, length=100)
zs = [f(x,y) for y in ys, x in xs]
surface(xs, ys, zs, camera=(40, 25), legend=false)
p = [-1, 1] # in the region graphed, [-2,2] × [-2, 2]
f(x) = f(x...)
v = ForwardDiff.gradient(f, p)
# add 0 to p and v (two styles)
push!(p, -15)
scatter!(unzip([p])..., markersize=3)
v = vcat(v, 0)
arrow!(p, v)
```
### The tangent plane
Let $z = f(x,y)$ describe a surface, and $F(x,y,z) = f(x,y) - z$. The the gradient of $F$ at a point $p$ on the surface, $\nabla F(p)$, will be normal to the surface and for a function, $f(p) + \nabla f \cdot (x-p)$ describes the tangent plane. We can visualize each, as follows:
```julia; hold=true
f(x,y) = 2 - x^2 - y^2
f(v) = f(v...)
F(x,y,z) = z - f(x,y)
F(v) = F(v...)
p = [1/10, -1/10]
global p1 = vcat(p, f(p...)) # note F(p1) == 0
global n⃗ = ForwardDiff.gradient(F, p1)
global tl(x) = f(p) + ForwardDiff.gradient(f, p) ⋅ (x - p)
tl(x,y) = tl([x,y])
xs = ys = range(-2, stop=2, length=100)
surface(xs, ys, f)
surface!(xs, ys, tl)
arrow!(p1, 5n⃗)
```
From some viewing angles, the normal does not look perpendicular to the tangent plane. This is a quick verification for a randomly chosen point in the $x-y$ plane:
```julia
a, b = randn(2)
dot(n⃗, (p1 - [a,b, tl(a,b)]))
```
### Parameterized surface plots
As illustrated, we can plot surfaces of the form $(x,y,f(x,y)$. However, not all surfaces are so readily described. For example, if $F(x,y,z)$ is a function from $R^3 \rightarrow R$, then $F(x,y,z)=c$ is a surface of interest. For example, the sphere of radius one is a solution to $F(x,y,z)=1$ where $F(x,y,z) = x^2 + y^2 + z^2$.
Plotting such generally described surfaces is not so easy, but *parameterized* surfaces can be represented. For example, the sphere as a surface is not represented as a surface of a function, but can be represented in spherical coordinates as parameterized by two angles, essentially an "azimuth" and and "elevation", as used with the `camera` argument.
Here we define functions that represent $(x,y,z)$ coordinates in terms of the corresponding spherical coordinates $(r, \theta, \phi)$.
```julia
# spherical: (radius r, inclination θ, azimuth φ)
X(r,theta,phi) = r * sin(theta) * sin(phi)
Y(r,theta,phi) = r * sin(theta) * cos(phi)
Z(r,theta,phi) = r * cos(theta)
```
We can parameterize the sphere by plotting values for $x$, $y$, and $z$ produced by a sequence of values for $\theta$ and $\phi$, holding $r=1$:
```julia; hold=true
thetas = range(0, stop=pi, length=50)
phis = range(0, stop=pi/2, length=50)
xs = [X(1, theta, phi) for theta in thetas, phi in phis]
ys = [Y(1, theta, phi) for theta in thetas, phi in phis]
zs = [Z(1, theta, phi) for theta in thetas, phi in phis]
surface(xs, ys, zs)
```
```julia; echo=false
note("The above may not work with all backends for `Plots`, even if those that support 3D graphics.")
```
For convenience, the `plot_parametric` function from `CalculusWithJulia` can produce these plots using interval notation and a function:
```julia; hold=true
F(theta, phi) = [X(1, theta, phi), Y(1, theta, phi), Z(1, theta, phi)]
plot_parametric(0..pi, 0..pi/2, F)
```
### Plotting F(x,y, z) = c
There is no built in functionality in `Plots` to create surface described by $F(x,y,z) = c$. An example of how to provide some such functionality for `PyPlot` appears [here](https://stackoverflow.com/questions/4680525/plotting-implicit-equations-in-3d ). The non-exported `plot_implicit_surface` function can be used to approximate this.
To use it, we see what happens when a sphere if rendered:
```julia; hold=true
f(x,y,z) = x^2 + y^2 + z^2 - 25
CalculusWithJulia.plot_implicit_surface(f)
```
This figure comes from a February 14, 2019 article in the [New York Times](https://www.nytimes.com/2019/02/14/science/math-algorithm-valentine.html). It shows an equation for a "heart," as the graphic will illustrate:
```julia; hold=true
a,b = 1,3
f(x,y,z) = (x^2+((1+b)*y)^2+z^2-1)^3-x^2*z^3-a*y^2*z^3
CalculusWithJulia.plot_implicit_surface(f, xlim=-2..2, ylim=-1..1, zlim=-1..2)
```

View File

@@ -0,0 +1,720 @@
# Polar Coordinates and Curves
This section uses these add-on packages:
```julia;
using CalculusWithJulia
using Plots
using SymPy
using Roots
using QuadGK
```
```julia; echo=false; results="hidden"
using CalculusWithJulia.WeaveSupport
const frontmatter = (
title = "Polar Coordinates and Curves",
description = "Calculus with Julia: Polar Coordinates and Curves",
tags = ["CalculusWithJulia", "differentiable_vector_calculus", "polar coordinates and curves"],
);
using LaTeXStrings
nothing
```
----
The description of the $x$-$y$ plane via Cartesian coordinates is not
the only possible way, though one that is most familiar. Here we discuss
a different means. Instead of talking about over and up from an
origin, we focus on a direction and a distance from the origin.
## Definition of polar coordinates
Polar coordinates parameterize the plane though an angle $\theta$ made from the positive ray of the $x$ axis and a radius $r$.
```julia; hold=true; echo=false
theta = pi/6
rr = 1
p = plot(xticks=nothing, yticks=nothing, border=:none, aspect_ratio=:equal, xlim=(-.1,1), ylim=(-.1,3/4))
plot!([0,rr*cos(theta)], [0, rr*sin(theta)], legend=false, color=:blue, linewidth=2)
scatter!([rr*cos(theta)],[rr*sin(theta)], markersize=3, color=:blue)
arrow!([0,0], [0,3/4], color=:black)
arrow!([0,0], [1,0], color=:black)
ts = range(0, theta, length=50)
rr = 1/6
plot!(rr*cos.(ts), rr*sin.(ts), color=:black)
plot!([cos(theta),cos(theta)],[0, sin(theta)], linestyle=:dash, color=:gray)
plot!([0,cos(theta)],[sin(theta), sin(theta)], linestyle=:dash, color=:gray)
annotate!([
(1/5*cos(theta/2), 1/5*sin(theta/2), L"\theta"),
(1/2*cos(theta*1.2), 1/2*sin(theta*1.2), L"r"),
(cos(theta), sin(theta)+.05, L"(x,y)"),
(cos(theta),-.05, L"x"),
(-.05, sin(theta),L"y")
])
```
To recover the Cartesian coordinates from the pair $(r,\theta)$, we have these formulas from [right](http://en.wikipedia.org/wiki/Polar_coordinate_system#Converting_between_polar_and_Cartesian_coordinates) triangle geometry:
```math
x = r \cos(\theta),~ y = r \sin(\theta).
```
Each point $(x,y)$ corresponds to several possible values of
$(r,\theta)$, as any integer multiple of $2\pi$ added to $\theta$ will
describe the same point. Except for the origin, there is only one pair
when we restrict to $r > 0$ and $0 \leq \theta < 2\pi$.
For values in the first and fourth quadrants (the range of
$\tan^{-1}(x)$), we have:
```math
r = \sqrt{x^2 + y^2},~ \theta=\tan^{-1}(y/x).
```
For the other two quadrants, the signs of $y$ and $x$ must be
considered. This is done with the function `atan` when two arguments are used.
For example, $(-3, 4)$ would have polar coordinates:
```julia;
x,y = -3, 4
rad, theta = sqrt(x^2 + y^2), atan(y, x)
```
And reversing
```julia;
rad*cos(theta), rad*sin(theta)
```
This figure illustrates:
```julia; hold=true; echo=false
p = plot([-5,5], [0,0], color=:blue, legend=false)
plot!([0,0], [-5,5], color=:blue)
plot!([-3,0], [4,0])
scatter!([-3], [4])
title!("(-3,4) Cartesian or (5, 2.21...) polar")
p
```
The case where $r < 0$ is handled by going ``180`` degrees in the opposite direction, in other
words the point $(r, \theta)$ can be described as well by $(-r,\theta+\pi)$.
## Parameterizing curves using polar coordinates
If $r=r(\theta)$, then the parameterized curve $(r(\theta), \theta)$
is just the set of points generated as $\theta$ ranges over some set
of values. There are many examples of parameterized curves that
simplify what might be a complicated presentation in Cartesian coordinates.
For example, a circle has the form $x^2 + y^2 = R^2$. Whereas
parameterized by polar coordinates it is just $r(\theta) = R$, or a
constant function.
The circle centered at $(r_0, \gamma)$ (in polar coordinates) with
radius $R$ has a more involved description in polar coordinates:
```math
r(\theta) = r_0 \cos(\theta - \gamma) + \sqrt{R^2 - r_0^2\sin^2(\theta - \gamma)}.
```
The case where $r_0 > R$ will not be defined for all values of $\theta$, only when $|\sin(\theta-\gamma)| \leq R/r_0$.
#### Examples
The `Plots.jl` package provides a means to visualize polar plots through `plot(thetas, rs, proj=:polar)`. For example, to plot a circe with $r_0=1/2$ and $\gamma=\pi/6$ we would have:
```julia; hold=true
R, r0, gamma = 1, 1/2, pi/6
r(theta) = r0 * cos(theta-gamma) + sqrt(R^2 - r0^2*sin(theta-gamma)^2)
ts = range(0, 2pi, length=100)
rs = r.(ts)
plot(ts, rs, proj=:polar, legend=false)
```
To avoid having to create values for $\theta$ and values for $r$, the `CalculusWithJulia` package provides a helper function, `plot_polar`. To distinguish it from other functions provided by `Plots`, the calling pattern is different. It specifies an interval to plot over by `a..b` and puts that first, followed by `r`. Other keyword arguments are passed onto a `plot` call.
We will use this in the following, as the graphs are a bit more familiar and the calling pattern similar to how we have plotted functions.
As `Plots` will make a parametric plot when called as `plot(function, function, a,b)`, the above
function creates two such functions using the relationship $x=r\cos(\theta)$ and $y=r\sin(\theta)$.
Using `plot_polar`, we can plot circles with the following. We have to be a bit careful for the general circle, as when the center is farther away from the origin that the radius ($R$), then not all angles will be acceptable and there are two functions needed to describe the radius, as this comes from a quadratic equation and both the "plus" and "minus" terms are used.
```julia; hold=true
R=4; r(t) = R;
function plot_general_circle!(r0, gamma, R)
# law of cosines has if gamma=0, |theta| <= asin(R/r0)
# R^2 = a^2 + r^2 - 2a*r*cos(theta); solve for a
r(t) = r0 * cos(t - gamma) + sqrt(R^2 - r0^2*sin(t-gamma)^2)
l(t) = r0 * cos(t - gamma) - sqrt(R^2 - r0^2*sin(t-gamma)^2)
if R < r0
theta = asin(R/r0)-1e-6 # avoid round off issues
plot_polar!((gamma-theta)..(gamma+theta), r)
plot_polar!((gamma-theta)..(gamma+theta), l)
else
plot_polar!(0..2pi, r)
end
end
plot_polar(0..2pi, r, aspect_ratio=:equal, legend=false)
plot_general_circle!(2, 0, 2)
plot_general_circle!(3, 0, 1)
```
There are many interesting examples of curves described by polar coordinates. An interesting [compilation](http://www-history.mcs.st-and.ac.uk/Curves/Curves.html) of famous curves is found at the MacTutor History of Mathematics archive, many of which have formulas in polar coordinates.
##### Example
The [rhodenea](http://www-history.mcs.st-and.ac.uk/Curves/Rhodonea.html) curve has
```math
r(\theta) = a \sin(k\theta)
```
```julia; hold=true
a, k = 4, 5
r(theta) = a * sin(k * theta)
plot_polar(0..pi, r)
```
This graph has radius $0$ whenever $\sin(k\theta) = 0$ or $k\theta
=n\pi$. Solving means that it is $0$ at integer multiples of
$\pi/k$. In the above, with $k=5$, there will $5$ zeroes in
$[0,\pi]$. The entire curve is traced out over this interval, the
values from $\pi$ to $2\pi$ yield negative value of $r$, so are
related to values within $0$ to $\pi$ via the relation $(r,\pi
+\theta) = (-r, \theta)$.
##### Example
The [folium](http://www-history.mcs.st-and.ac.uk/Curves/Folium.html)
is a somewhat similar looking curve, but has this description:
```math
r(\theta) = -b \cos(\theta) + 4a \cos(\theta) \sin(2\theta)
```
```julia;
𝒂, 𝒃 = 4, 2
𝒓(theta) = -𝒃 * cos(theta) + 4𝒂 * cos(theta) * sin(2theta)
plot_polar(0..2pi, 𝒓)
```
The folium has radial part $0$ when $\cos(\theta) = 0$ or
$\sin(2\theta) = b/4a$. This could be used to find out what values
correspond to which loop. For our choice of $a$ and $b$ this gives $\pi/2$, $3\pi/2$ or, as
$b/4a = 1/8$, when $\sin(2\theta) = 1/8$ which happens at
$a_0=\sin^{-1}(1/8)/2=0.0626...$ and $\pi/2 - a_0$, $\pi+a_0$ and $3\pi/2 - a_0$. The first folium can be plotted with:
```julia;
𝒂0 = (1/2) * asin(1/8)
plot_polar(𝒂0..(pi/2-𝒂0), 𝒓)
```
The second - which is too small to appear in the initial plot without zooming in - with
```julia;
plot_polar((pi/2 - 𝒂0)..(pi/2), 𝒓)
```
The third with
```julia;
plot_polar((pi/2)..(pi + 𝒂0), 𝒓)
```
The plot repeats from there, so the initial plot could have been made over $[0, \pi + a_0]$.
##### Example
The [Limacon of Pascal](http://www-history.mcs.st-and.ac.uk/Curves/Limacon.html) has
```math
r(\theta) = b + 2a\cos(\theta)
```
```julia; hold=true
a,b = 4, 2
r(theta) = b + 2a*cos(theta)
plot_polar(0..2pi, r)
```
##### Example
Some curves require a longer parameterization, such as this where we
plot over $[0, 8\pi]$ so that the cosine term can range over an entire
half period:
```julia; hold=true
r(theta) = sqrt(abs(cos(theta/8)))
plot_polar(0..8pi, r)
```
## Area of polar graphs
Consider the [cardioid](http://www-history.mcs.st-and.ac.uk/Curves/Cardioid.html) described by $r(\theta) = 2(1 + \cos(\theta))$:
```julia; hold=true
r(theta) = 2(1 + cos(theta))
plot_polar(0..2pi, r)
```
How much area is contained in the graph?
In some cases it might be possible to translate back into Cartesian
coordinates and compute from there. In practice, this is not usually the best
solution.
The area can be approximated by wedges (not rectangles). For example, here we see that the area over a given angle is well approximated by the wedge for each of the sectors:
```julia; hold=true; echo=false
r(theta) = 1/(1 + (1/3)cos(theta))
p = plot_polar(0..pi/2, r, legend=false, linewidth=3, aspect_ratio=:equal)
t0, t1, t2, t3 = collect(range(pi/12, pi/2 - pi/12, length=4))
for s in (t0,t1,t2,t3)
plot!(p, [0, r(s)*cos(s)], [0, r(s)*sin(s)], linewidth=3)
end
for (s0,s1) in ((t0,t1), (t1, t2), (t2,t3))
s = (s0 + s1)/2
plot!(p, [0, ])
plot!(p, [0,r(s)*cos(s)], [0, r(s)*sin(s)])
ts = range(s0, s1, length=25)
xs, ys = r(s)*cos.(ts), r(s)*sin.(ts)
plot!(p, xs, ys)
plot!(p, [0,xs[1]],[0,ys[1]])
end
p
```
As well, see this part of a
[Wikipedia](http://en.wikipedia.org/wiki/Polar_coordinate_system#Integral_calculus_.28area.29)
page for a figure.
Imagine we have $a < b$ and a partition $a=t_0 < t_1 < \cdots < t_n =
b$. Let $\phi_i = (1/2)(t_{i-1} + t_{i})$ be the midpoint.
Then the wedge of radius $r(\phi_i)$ with angle between $t_{i-1}$ and $t_i$ will have area $\pi r(\phi_i)^2 (t_i-t_{i-1}) / (2\pi) = (1/2) r(\phi_i)(t_i-t_{i-1})$, the ratio $(t_i-t_{i-1}) / (2\pi)$ being the angle to the total angle of a circle.
Summing the area of these wedges
over the partition gives a Riemann sum approximation for the integral $(1/2)\int_a^b
r(\theta)^2 d\theta$. This limit of this sum defines the area in polar coordinates.
> *Area of polar regions*. Let $R$ denote the region bounded by the curve $r(\theta)$ and bounded by the rays
> $\theta=a$ and $\theta=b$ with $b-a \leq 2\pi$, then the area of $R$ is given by:
>
> ``A = \frac{1}{2}\int_a^b r(\theta)^2 d\theta.``
So the area of the cardioid, which is parameterized over $[0, 2\pi]$ is found by
```julia; hold=true
r(theta) = 2(1 + cos(theta))
@syms theta
(1//2) * integrate(r(theta)^2, (theta, 0, 2PI))
```
##### Example
The folium has general formula $r(\theta) = -b \cos(\theta)
+4a\cos(\theta)\sin(\theta)^2$. When $a=1$ and $b=1$ a leaf of the
folium is traced out between $\pi/6$ and $\pi/2$. What is the area of
that leaf?
An antiderivative exists for arbitrary $a$ and $b$:
```julia;
@syms 𝐚 𝐛 𝐭heta
𝐫(theta) = -𝐛*cos(theta) + 4𝐚*cos(theta)*sin(theta)^2
integrate(𝐫(𝐭heta)^2, 𝐭heta) / 2
```
For our specific values, the answer can be computed with:
```julia;
ex = integrate(𝐫(𝐭heta)^2, (𝐭heta, PI/6, PI/2)) / 2
ex(𝐚 => 1, 𝐛=>1)
```
###### Example
Pascal's
[limacon](http://www-history.mcs.st-and.ac.uk/Curves/Limacon.html) is
like the cardioid, but contains an extra loop. When $a=1$ and $b=1$ we
have this graph.
```julia; hold=true; echo=false
a,b = 1,1
r(theta) = b + 2a*cos(theta)
p = plot(t->r(t)*cos(t), t->r(t)*sin(t), 0, pi/2 + pi/6, legend=false, color=:blue)
plot!(p, t->r(t)*cos(t), t->r(t)*sin(t), 3pi/2 - pi/6, pi/2 + pi/6, color=:orange)
plot!(p, t->r(t)*cos(t), t->r(t)*sin(t), 3pi/2 - pi/6, 2pi, color=:blue)
p
```
What is the area contained in the outer loop, that is not in the inner loop?
To answer, we need to find out what range of values in $[0, 2\pi]$ the
inner and outer loops are traced. This will be when $r(\theta) = 0$,
which for the choice of $a$ and $b$ solves $1 + 2\cos(\theta) = 0$, or
$\cos(\theta) = -1/2$. This is $\pi/2 + \pi/6$ and $3\pi/2 -
\pi/6$. The inner loop is traversed between those values and has area:
```julia;
@syms 𝖺 𝖻 𝗍heta
𝗋(theta) = 𝖻 + 2𝖺*cos(𝗍heta)
𝖾x = integrate(𝗋(𝗍heta)^2 / 2, (𝗍heta, PI/2 + PI/6, 3PI/2 - PI/6))
𝗂nner = 𝖾x(𝖺=>1, 𝖻=>1)
```
The outer area (including the inner loop) is the integral from $0$ to $\pi/2 + \pi/6$ plus that from $3\pi/2 - \pi/6$ to $2\pi$. These areas are equal, so we double the first:
```julia;
𝖾x1 = 2 * integrate(𝗋(𝗍heta)^2 / 2, (𝗍heta, 0, PI/2 + PI/6))
𝗈uter = 𝖾x1(𝖺=>1, 𝖻=>1)
```
The answer is the difference:
```julia;
𝗈uter - 𝗂nner
```
## Arc length
The length of the arc traced by a polar graph can also be expressed
using an integral. Again, we partition the interval $[a,b]$ and
consider the wedge from $(r(t_{i-1}), t_{i-1})$ to $(r(t_i),
t_i)$. The curve this wedge approximates will have its arc length
approximated by the line segment connecting the points. Expressing the
points in Cartesian coordinates and simplifying gives the distance
squared as:
```math
\begin{align}
d_i^2 &= (r(t_i) \cos(t_i) - r(t_{i-1})\cos(t_{i-1}))^2 + (r(t_i) \sin(t_i) - r(t_{i-1})\sin(t_{i-1}))^2\\
&= r(t_i)^2 - 2r(t_i)r(t_{i-1}) \cos(t_i - t_{i-1}) + r(t_{i-1})^2 \\
&\approx r(t_i)^2 - 2r(t_i)r(t_{i-1}) (1 - \frac{(t_i - t_{i-1})^2}{2})+ r(t_{i-1})^2 \quad(\text{as} \cos(x) \approx 1 - x^2/2)\\
&= (r(t_i) - r(t_{i-1}))^2 + r(t_i)r(t_{i-1}) (t_i - t_{i-1})^2.
\end{align}
```
As was done with arc length we multiply $d_i$ by $(t_i - t_{i-1})/(t_i - t_{i-1})$
and move the bottom factor under the square root:
```math
\begin{align}
d_i
&= d_i \frac{t_i - t_{i-1}}{t_i - t_{i-1}} \\
&\approx \sqrt{\frac{(r(t_i) - r(t_{i-1}))^2}{(t_i - t_{i-1})^2} +
\frac{r(t_i)r(t_{i-1}) (t_i - t_{i-1})^2}{(t_i - t_{i-1})^2}} \cdot (t_i - t_{i-1})\\
&= \sqrt{(r'(\xi_i))^2 + r(t_i)r(t_{i-1})} \cdot (t_i - t_{i-1}).\quad(\text{the mean value theorem})
\end{align}
```
Adding the approximations to the $d_i$ looks like a Riemann sum approximation to the
integral $\int_a^b \sqrt{(r'(\theta)^2) + r(\theta)^2} d\theta$ (with
the extension to the Riemann sum formula needed to derive the arc
length for a parameterized curve). That is:
> *Arc length of a polar curve*. The arc length of the curve described in polar coordinates by $r(\theta)$ for $a \leq \theta \leq b$ is given by:
>
> ``\int_a^b \sqrt{r'(\theta)^2 + r(\theta)^2} d\theta.``
We test this out on a circle with $r(\theta) = R$, a constant. The
integrand simplifies to just $\sqrt{R^2}$ and the integral is from $0$
to $2\pi$, so the arc length is $2\pi R$, precisely the formula for
the circumference.
##### Example
A cardioid is described by $r(\theta) = 2(1 + \cos(\theta))$. What is the arc length from $0$ to $2\pi$?
The integrand is integrable with antiderivative $4\sqrt{2\cos(\theta) + 2} \cdot \tan(\theta/2)$,
but `SymPy` isn't able to find the integral. Instead we give a numeric answer:
```julia; hold=true
r(theta) = 2*(1 + cos(theta))
quadgk(t -> sqrt(r'(t)^2 + r(t)^2), 0, 2pi)[1]
```
##### Example
The [equiangular](http://www-history.mcs.st-and.ac.uk/Curves/Equiangular.html) spiral has polar representation
```math
r(\theta) = a e^{\theta \cot(b)}
```
With $a=1$ and $b=\pi/4$, find the arc length traced out from $\theta=0$ to $\theta=1$.
```julia; hold=true
a, b = 1, PI/4
@syms θ
r(theta) = a * exp(theta * cot(b))
ds = sqrt(diff(r(θ), θ)^2 + r(θ)^2)
integrate(ds, (θ, 0, 1))
```
##### Example
An Archimedean [spiral](http://en.wikipedia.org/wiki/Archimedean_spiral) is defined in polar form by
```math
r(\theta) = a + b \theta
```
That is, the radius increases linearly. The crossings of the positive $x$ axis occur at $a + b n 2\pi$, so are evenly spaced out by $2\pi b$. These could be a model for such things as coils of materials of uniform thickness.
For example, a roll of toilet paper promises ``1000`` sheets with the
[smaller](http://www.phlmetropolis.com/2011/03/the-incredible-shrinking-toilet-paper.php)
$4.1 \times 3.7$ inch size. This $3700$ inch long connected sheet of
paper is wrapped around a paper tube in an Archimedean spiral with
$r(\theta) = d_{\text{inner}}/2 + b\theta$. The entire roll must fit in a standard
dimension, so the outer diameter will be $d_{\text{outer}} = 5~1/4$ inches. Can we figure out
$b$?
Let $n$ be the number of windings and assume the starting and ending point is on the positive $x$ axis,
$r(2\pi n) = d_{\text{outer}}/2 = d_{\text{inner}}/2 + b (2\pi n)$. Solving for $n$ in terms of $b$ we get:
$n = ( d_{\text{outer}} - d_{\text{inner}})/2 / (2\pi b)$. With this, the following must hold as the total arc length is $3700$ inches.
```math
\int_0^{n\cdot 2\pi} \sqrt{r(\theta)^2 + r'(\theta)^2} d\theta = 3700
```
Numerically then we have:
```julia; hold=true
dinner = 1 + 5/8
douter = 5 + 1/4
r(b,t) = dinner/2 + b*t
rp(b,t) = b
integrand(b,t) = sqrt((r(b,t))^2 + rp(b,t)^2) # sqrt(r^2 + r'^2)
n(b) = (douter - dinner)/2/(2*pi*b)
b = find_zero(b -> quadgk(t->integrand(b,t), 0, n(b)*2*pi)[1] - 3700, (1/100000, 1/100))
b, b*25.4
```
The value `b` gives a value in inches, the latter in millimeters.
## Questions
###### Question
Let $r=3$ and $\theta=\pi/8$. In Cartesian coordinates what is $x$?
```julia; hold=true; echo=false
x,y = 3 * [cos(pi/8), sin(pi/8)]
numericq(x)
```
What is $y$?
```julia; hold=true; echo=false
numericq(y)
```
###### Question
A point in Cartesian coordinates is given by $(-12, -5)$. In has a polar coordinate representation with an angle $\theta$ in $[0,2\pi]$ and $r > 0$. What is $r$?
```julia; hold=true; echo=false
x,y = -12, -5
r1, theta1 = sqrt(x^2 + y^2), atan(y,x)
numericq(r1)
```
What is $\theta$?
```julia; hold=true; echo=false
x,y = -12, -5
r1, theta1 = sqrt(x^2 + y^2), atan(y,x)
numericq(theta1)
```
###### Question
Does $r(\theta) = a \sec(\theta - \gamma)$ describe a line for $0$ when $a=3$ and $\gamma=\pi/4$?
```julia; hold=true; echo=false
yesnoq("yes")
```
If yes, what is the $y$ intercept
```julia; hold=true; echo=false
r(theta) = 3 * sec(theta -pi/4)
val = r(pi/2)
numericq(val)
```
What is slope of the line?
```julia; hold=true; echo=false
r(theta) = 3 * sec(theta -pi/4)
val = (r(pi/2)*sin(pi/2) - r(pi/4)*sin(pi/4)) / (r(pi/2)*cos(pi/2) - r(pi/4)*cos(pi/4))
numericq(val)
```
Does this seem likely: the slope is $-1/\tan(\gamma)$?
```julia; hold=true; echo=false
yesnoq("yes")
```
###### Question
The polar curve $r(\theta) = 2\cos(\theta)$ has tangent lines at most points. This differential representation of the chain rule
```math
\frac{dy}{dx} = \frac{dy}{d\theta} / \frac{dx}{d\theta},
```
allows the slope to be computed when $y$ and $x$ are the Cartesian
form of the polar curve. For this curve, we have
```math
\frac{dy}{d\theta} = \frac{d}{d\theta}(2\cos(\theta) \cdot \cos(\theta)),~ \text{ and }
\frac{dx}{d\theta} = \frac{d}{d\theta}(2\sin(\theta) \cdot \cos(\theta)).
```
Numerically, what is the slope of the tangent line when $\theta = \pi/4$?
```julia; hold=true; echo=false
r(theta) = 2cos(theta)
g(theta) = r(theta)*cos(theta)
f(theta) = r(theta)*sin(theta)
c = pi/4
val = D(g)(c) / D(f)(c)
numericq(val)
```
###### Question
For different values $k > 0$ and $e > 0$ the polar equation
```math
r(\theta) = \frac{ke}{1 + e\cos(\theta)}
```
has a familiar form. The value of $k$ is just a scale factor, but different values of $e$ yield different shapes.
When $0 < e < 1$ what is the shape of the curve? (Answer by making a plot and guessing.)
```julia; hold=true; echo=false
choices = [
"an ellipse",
"a parabola",
"a hyperbola",
"a circle",
"a line"
]
ans = 1
radioq(choices, ans, keep_order=true)
```
When $e = 1$ what is the shape of the curve?
```julia; hold=true; echo=false
choices = [
"an ellipse",
"a parabola",
"a hyperbola",
"a circle",
"a line"
]
ans = 2
radioq(choices, ans, keep_order=true)
```
When $1 < e$ what is the shape of the curve?
```julia; hold=true; echo=false
choices = [
"an ellipse",
"a parabola",
"a hyperbola",
"a circle",
"a line"
]
ans = 3
radioq(choices, ans, keep_order=true)
```
###### Question
Find the area of a lobe of the
[lemniscate](http://www-history.mcs.st-and.ac.uk/Curves/Lemniscate.html)
curve traced out by $r(\theta) = \sqrt{\cos(2\theta)}$ between
$-\pi/4$ and $\pi/4$. What is the answer?
```julia; hold=true; echo=false
choices = [
"``1/2``",
"``\\pi/2``",
"``1``"
]
ans=1
radioq(choices, ans)
```
###### Question
Find the area of a lobe of the [eight](http://www-history.mcs.st-and.ac.uk/Curves/Eight.html) curve traced out by $r(\theta) = \cos(2\theta)\sec(\theta)^4$ from $-\pi/4$ to $\pi/4$. Do this numerically.
```julia; hold=true; echo=false
r(theta) = sqrt(cos(2theta) * sec(theta)^4)
val, _ = quadgk(t -> r(t)^2/2, -pi/4, pi/4)
numericq(val)
```
###### Question
Find the arc length of a lobe of the
[lemniscate](http://www-history.mcs.st-and.ac.uk/Curves/Lemniscate.html)
curve traced out by $r(\theta) = \sqrt{\cos(2\theta)}$ between
$-\pi/4$ and $\pi/4$. What is the answer (numerically)?
```julia; hold=true; echo=false
r(theta) = sqrt(cos(2theta))
val, _ = quadgk(t -> sqrt(D(r)(t)^2 + r(t)^2), -pi/4, pi/4)
numericq(val)
```
###### Question
Find the arc length of a lobe of the [eight](http://www-history.mcs.st-and.ac.uk/Curves/Eight.html) curve traced out by $r(\theta) = \cos(2\theta)\sec(\theta)^4$ from $-\pi/4$ to $\pi/4$. Do this numerically.
```julia; hold=true; echo=false
r(theta) = sqrt(cos(2theta) * sec(theta)^4)
val, _ = quadgk(t -> sqrt(D(r)(t)^2 + r(t)^2), -pi/4, pi/4)
numericq(val)
```

View File

@@ -0,0 +1,36 @@
using WeavePynb
using Mustache
mmd(fname) = mmd_to_html(fname, BRAND_HREF="../toc.html", BRAND_NAME="Calculus with Julia")
## uncomment to generate just .md files
#mmd(fname) = mmd_to_md(fname, BRAND_HREF="../toc.html", BRAND_NAME="Calculus with Julia")
fnames = ["polar_coordinates",
"vectors",
"vector_valued_functions",
"scalar_functions",
"scalar_functions_applications",
"vector_fields"
]
function process_file(nm, twice=false)
include("$nm.jl")
mmd_to_md("$nm.mmd")
markdownToHTML("$nm.md")
twice && markdownToHTML("$nm.md")
end
process_files(twice=false) = [process_file(nm, twice) for nm in fnames]
"""
## TODO differential_vector_calcululs
### Add questions for scalar_function_applications
* Newton's method??
* optimization. Find least squares for perpendicular distance using the same 3 points...??
"""

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff