diff --git a/quarto/_common_code.qmd b/quarto/_common_code.qmd
index fcc1575..db01bfd 100644
--- a/quarto/_common_code.qmd
+++ b/quarto/_common_code.qmd
@@ -2,6 +2,28 @@
#| output: false
#| echo: false
+# Some style choices for `Plots.jl`
+
+empty_style = (xaxis=([], false),
+ yaxis=([], false),
+ framestyle=:origin,
+ legend=false)
+axis_style = (arrow=true, side=:head, line=(:gray, 1))
+text_style = (10,)
+fn_style = (;line=(:black, 3))
+fn2_style = (;line=(:red, 4))
+mark_style = (;line=(:gray, 1, :dot))
+
+domain_style = (;fill=(:orange, 0.35))
+range_style = (; fill=(:blue, 0.35))
+
+nothing
+```
+
+```{julia}
+#| output: false
+#| echo: false
+
## Formatting options are included here; not in CalculusWithJulia.WeaveSupport
using QuizQuestions
nothing
diff --git a/quarto/_quarto.yml b/quarto/_quarto.yml
index 178bc7e..ddd335a 100644
--- a/quarto/_quarto.yml
+++ b/quarto/_quarto.yml
@@ -158,7 +158,7 @@ format:
execute:
error: false
- freeze: false
-# freeze: auto
+# freeze: false
+ freeze: auto
# cache: false
# enabled: true
\ No newline at end of file
diff --git a/quarto/adjust_plotly.jl b/quarto/adjust_plotly.jl
index 34a0d01..ec06770 100644
--- a/quarto/adjust_plotly.jl
+++ b/quarto/adjust_plotly.jl
@@ -7,16 +7,19 @@
#alternatives/plotly_plotting.html
function _add_plotly(f)
- lineno = 117
+ #lineno = 117
-str = """
-
-"""
r = readlines(f)
+ inserted = false
open(f, "w") do io
for (i,l) ∈ enumerate(r)
- i == lineno && println(io, str)
+ if contains(l, "require.min.js")
+ !inserted && println(io, """
+
+""")
+ inserted = true
+ end
println(io, l)
end
end
@@ -29,6 +32,7 @@ function (@main)(args...)
for fᵢ ∈ files
f = joinpath(root, fᵢ)
if endswith(f, ".html")
+ dirname(f) == "_book" && continue
_add_plotly(f)
end
end
diff --git a/quarto/index.qmd b/quarto/index.qmd
index 46d6eca..0529f15 100644
--- a/quarto/index.qmd
+++ b/quarto/index.qmd
@@ -59,7 +59,7 @@ in a spirit similar to a section of a book. Just like a book, there
are try-it-yourself questions at the end of each page. All have a
limited number of self-graded answers. These notes borrow ideas from
many sources, for example @Strang, @Knill, @Schey, @Thomas,
-@RogawskiAdams, several Wikipedia pages, and other sources.
+@RogawskiAdams, @Angenent, several Wikipedia pages, and other sources.
These notes are accompanied by a `Julia` package `CalculusWithJulia`
that provides some simple functions to streamline some common tasks
diff --git a/quarto/integrals/area_between_curves.qmd b/quarto/integrals/area_between_curves.qmd
index cce4ab5..b279dea 100644
--- a/quarto/integrals/area_between_curves.qmd
+++ b/quarto/integrals/area_between_curves.qmd
@@ -64,7 +64,88 @@ $$
#### Examples
+Find the area between
+$$
+\begin{align*}
+f(x) &= \frac{x^3 \cdot (2-x)}{2} \text{ and } \\
+g(x) &= e^{x/3} + (1-\frac{x}{1.7})^6 - 0.6
+\end{align*}
+$$
+
+over the interval $[0.2, 1.7]$. The area is illustrated in the figure below.
+
+```{julia}
+f(x) = x^3*(2-x)/2
+g(x) = exp(x/3) + (1 - (x/1.7))^6 - 0.6
+a, b = 0.2, 1.7
+h(x) = g(x) - f(x)
+answer, _ = quadgk(h, a, b)
+answer
+```
+
+
+::: {#fig-area-between-f-g}
+
+```{julia}
+#| echo: false
+p = let
+ gr()
+ # area between graphs
+ # https://github.com/SigurdAngenent/WisconsinCalculus/blob/master/figures/221/09areabetweengraphs.pdf
+
+ f(x) = 1/6+x^3*(2-x)/2
+ g(x) = 1/6+exp(x/3)+(1-x/1.7)^6-0.6
+ a,b =0.2, 1.7
+ A, B = 0, 2
+ A′, B′ = A + .1, B - .1
+ n = 20
+
+ plot(; empty_style..., aspect_ratio=:equal, xlims=(A,B))
+ plot!(f, A′, B′; fn_style...)
+ plot!(g, A′, B′; fn_style...)
+
+ xp = range(a, b, n)
+ marked = n ÷ 2
+ for i in 1:n-1
+ x0, x1 = xp[i], xp[i+1]
+ mpt = (x0 + x1)/2
+ R = Shape([x0,x1,x1,x0], [f(mpt),f(mpt),g(mpt),g(mpt)])
+ color = i == marked ? :gray : :white
+ plot!(R; fill=(color, 0.5), line=(:black, 1))
+ end
+
+ # axis
+ plot!([(A,0),(B,0)]; axis_style...)
+
+ # hightlight
+ x0, x1 = xp[marked], xp[marked+1]
+ _style = (;line=(:gray, 1, :dash))
+ plot!([(a,0), (a, f(a))]; _style...)
+ plot!([(b,0), (b,f(b))]; _style...)
+ plot!([(x0,0), (x0, f(x0))]; _style...)
+ plot!([(x1,0), (x1, f(x1))]; _style...)
+
+ annotate!([
+ (B′, f(B′), text(L"f(x)", 10, :left,:top)),
+ (B′, g(B′), text(L"g(x)", 10, :left, :bottom)),
+ (a, 0, text(L"a=x_0", 10, :top, :left)),
+ (b, 0, text(L"b=x_n", 10, :top, :left)),
+ (x0, 0, text(L"x_i", 10, :top)),
+ (x1, 0, text(L"x_{i+1}", 10, :top,:left))
+ ])
+
+ current()
+end
+
+plotly()
+p
+```
+
+Illustration of a Riemann sum approximation to estimate the area between $f(x)$ and $g(x)$ over an interval $[a,b]$. (Figure follows one by @Angenent.)
+:::
+
+##### Example
Find the area bounded by the line $y=2x$ and the curve $y=2 - x^2$.
@@ -970,4 +1051,3 @@ choices = ["The two enclosed areas should be equal",
"The two enclosed areas are clearly different, as they do not overap"]
radioq(choices, 1)
```
-
diff --git a/quarto/integrals/volumes_slice.qmd b/quarto/integrals/volumes_slice.qmd
index 2a891ff..4b4d0d7 100644
--- a/quarto/integrals/volumes_slice.qmd
+++ b/quarto/integrals/volumes_slice.qmd
@@ -20,6 +20,7 @@ using SymPy
#| echo: false
#| results: "hidden"
import LinearAlgebra: norm
+using SplitApplyCombine
nothing
```
@@ -122,6 +123,145 @@ The formula is for a rotation around the $x$-axis, but can easily be generalized
:::
+::: {#fig-solid-of-revolution}
+
+```{julia}
+#| echo: false
+plt = let
+ gr()
+ # Follow lead of # https://github.com/SigurdAngenent/WisconsinCalculus/blob/master/figures/221/09surf_of_rotation2.py
+ # plot surface of revolution around x axis between [0, 3]
+ # best if r(t) descreases
+
+ rad(x) = 2/(1 + exp(x))#2/(2.0+x)
+ viewp = [2,-2,1]
+
+ ##
+ unitize(x) = x / norm(x)
+
+ """Orthogonal projection along the vector viewp"""
+ function make_Pmat(viewp)
+ a = unitize( [-viewp[2], viewp[1], 0] )
+ b = unitize( [-viewp[3]*viewp[1],
+ -viewp[3]*viewp[2],
+ viewp[1]^2 + viewp[2]^2] )
+ collect(zip(a,b))
+ end
+
+ #linear projection of R^3 onto R^2
+ function proj(X, viewp)
+ Pmat = make_Pmat(viewp)
+ x=sum([Pmat[i][1]*X[i] for i in 1:3])
+ y=sum([Pmat[i][2]*X[i] for i in 1:3])
+ (x, y) # a point
+ end
+ proj(X) = proj(X, viewp)
+
+ # discrete determinant of Jacobian; area multiplier?
+ function jac(X, u, v)
+ ϵ = 0.000001
+ A = map((p,q) -> (p-q)/ϵ, X(u+ϵ/2, v), X(u-ϵ/2, v))
+ B = map((p,q) -> (p-q)/ϵ, X(u, v+ϵ/2), X(u, v-ϵ/2))
+ return A[1]*B[2]-A[2]*B[1]
+ end
+
+
+ # surface of revolution
+ surf(t, z) = [t, rad(t)*cos(z), rad(t)*sin(z)]
+
+ # project the surface at (t, a=theta)
+ psurf(t,z) = proj(surf(t,z))
+
+
+ bisect(f, a, b) = find_zero(f, (a,b), Bisection())
+ _fold(t, zmin, zmax) = bisect(z -> jac(psurf, t, z), zmin, zmax)
+
+ # create shape holding project disc
+ drawdiscF(t) = Shape(invert([psurf(t, 2*i*pi/100) for i in 1:101])...)
+
+ # project a line between two points
+ pline!(p,q; kwargs...) = plot!([proj(p),proj(q)];
+ line_style..., kwargs...)
+ α = 1.0
+ line_style = (; line=(:black, 1))
+
+ plot(; empty_style..., aspect_ratio=:equal)
+
+
+
+ # by layering, we get x-axis as desired
+ pline!([-1,0,0], [0,0,0])
+ plot!(drawdiscF(0); fill =(:lightgray, α))
+ pline!([0,0,0], [1,0,0])
+ plot!(drawdiscF(1); fill =(:black, α)) # black to lightgray gives thickness
+ plot!(drawdiscF(1.1); fill=(:lightgray, α))
+ pline!([1.1,0,0], [2,0,0])
+ plot!(drawdiscF(2); fill=(:lightgray, α))
+ pline!([2,0,0], [3,0,0])
+ plot!(drawdiscF(3); fill=(:lightgray, α))
+ pline!([3,0,0], [4,0,0]; arrow=true, side=:head)
+ pline!([0,0,0], [0,0,1.25]; arrow=true, side=:head)
+
+
+ tt = range(0, pi, 30)
+ curve = [psurf(t, pi/2) for t in tt]
+ plot!(curve; line=(:black, 2))
+
+ f1 = [[t, _fold(t, 0, pi)] for t in tt]
+ curve = [psurf(f[1], f[2]) for f in f1]
+ plot!(curve; line=(:black,))
+
+ f2 = [[t, _fold(t, pi, 2*pi)] for t in tt]
+ curve = [psurf(f[1], f[2]) for f in f2]
+ plot!(curve; line=(:black,))
+
+
+
+ tt= [0.025*i for i in 1:121]
+ f1 = [[t, _fold(t, pi, 2*pi)] for t in tt]
+ for f in f1
+ plot!([psurf(f[1], f[2]-k*0.01*(4-f[1])) for k in 1:21];
+ line=(:black,1))
+ end
+ tt= [0.05*i for i in 1:61]
+ f1 = [[t, _fold(t, pi, 2*pi)] for t in tt]
+ for f in f1
+ plot!([psurf( f[1], f[2]-k*0.01*(6-f[1]) )
+ for k in 1:21]; line=(:black, 1))
+ end
+#=
+ ts = 0:.1:2.95
+ θs = range(pi + pi/4, 3pi/2, 25)
+ for ti in ts
+ plot!([psurf(ti,θ) for θ in θs]; line=(:black, 1))
+ end
+ θs = range(pi + pi/6, 3pi/2, 25)
+ for ti in ts
+ plot!([psurf(ti +0.05,θ) for θ in θs]; line=(:black, 1))
+ end
+=#
+ current()
+
+ #ts = range(0, 3, 100)
+ #θs = range(0, 2pi, 100)
+ #contour(ts, θs, (t,z) -> jac(psurf,t,z), levels=[0])
+
+end
+plt
+```
+
+```{julia}
+#| echo: false
+plotly()
+nothing
+```
+
+
+Illustration of a figure being rotated around the $x$-axis. The discs have approximate volume given by the area of the base times the height or $\pi r(x)^2 \Delta x$. (Figure ported from @Angenent.)
+
+:::
+
+
For a numeric example, we consider the original Red [Solo](http://en.wikipedia.org/wiki/Red_Solo_Cup) Cup. The dimensions of the cup were basically: a top diameter of $d_1 = 3~ \frac{3}{4}$ inches, a bottom diameter of $d_0 = 2~ \frac{1}{2}$ inches and a height of $h = 4~ \frac{3}{4}$ inches.
@@ -352,6 +492,136 @@ $$
V = \int_a^b \pi \cdot (R(x)^2 - r(x)^2) dx.
$$
+::: {#fig-washer-illustration}
+```{julia}
+#| echo: false
+plt = let
+ gr()
+ # Follow lead of # https://github.com/SigurdAngenent/WisconsinCalculus/blob/master/figures/221/09surf_of_rotation2.py
+ # plot surface of revolution around x axis between [0, 3]
+ # best if r(t) descreases
+
+ rad(x) = 2/(1 + exp(x))#2/(2.0+x)
+ viewp = [2,-2,1]
+
+ ##
+ unitize(x) = x / norm(x)
+
+ """Orthogonal projection along the vector viewp"""
+ function make_Pmat(viewp)
+ a = unitize( [-viewp[2], viewp[1], 0] )
+ b = unitize( [-viewp[3]*viewp[1],
+ -viewp[3]*viewp[2],
+ viewp[1]^2 + viewp[2]^2] )
+ collect(zip(a,b))
+ end
+
+ #linear projection of R^3 onto R^2
+ function proj(X, viewp)
+ Pmat = make_Pmat(viewp)
+ x=sum([Pmat[i][1]*X[i] for i in 1:3])
+ y=sum([Pmat[i][2]*X[i] for i in 1:3])
+ (x, y) # a point
+ end
+ proj(X) = proj(X, viewp)
+
+ # discrete determinant of Jacobian; area multiplier?
+ function jac(X, u, v)
+ ϵ = 0.000001
+ A = map((p,q) -> (p-q)/ϵ, X(u+ϵ/2, v), X(u-ϵ/2, v))
+ B = map((p,q) -> (p-q)/ϵ, X(u, v+ϵ/2), X(u, v-ϵ/2))
+ return A[1]*B[2]-A[2]*B[1]
+ end
+
+
+ # surface of revolution
+ surf(t, z) = [t, rad(t)*cos(z), rad(t)*sin(z)]
+ surf2(t, z) = (t, rad(t)*cos(z)/2, rad(t)*sin(z)/2)
+
+ # project the surface at (t, a=theta)
+ psurf(t,z) = proj(surf(t,z))
+ psurf2(t, z) = proj(surf2(t,z))
+
+ bisect(f, a, b) = find_zero(f, (a,b), Bisection())
+ _fold(t, zmin, zmax) = bisect(z -> jac(psurf, t, z), zmin, zmax)
+
+ # create shape holding project disc
+ drawdiscF(t) = Shape(invert([psurf(t, 2*i*pi/100) for i in 1:101])...)
+ drawdiscI(t) = Shape([psurf2(t, 2*i*pi/100) for i in 1:101])
+
+ # project a line between two points
+ pline!(p,q; kwargs...) = plot!([proj(p),proj(q)];
+ line_style..., kwargs...)
+ α = 1.0
+ line_style = (; line=(:black, 1))
+
+ plot(; empty_style..., aspect_ratio=:equal)
+
+
+
+ # by layering, we get x-axis as desired
+ pline!([-1,0,0], [0,0,0])
+ plot!(drawdiscF(0); fill =(:lightgray, α))
+ plot!(drawdiscI(0); fill=(:white, .5))
+ pline!([0,0,0], [1,0,0])
+ plot!(drawdiscF(1); fill =(:black, α)) # black to lightgray gives thickness
+ plot!(drawdiscI(1); fill=(:white, .5))
+ plot!(drawdiscF(1.1); fill=(:lightgray, α))
+ plot!(drawdiscI(1.1); fill=(:white, .5))
+ pline!([1.1,0,0], [2,0,0])
+ plot!(drawdiscF(2); fill=(:lightgray, α))
+ plot!(drawdiscI(2); fill=(:white, .5))
+ pline!([2,0,0], [3,0,0])
+ plot!(drawdiscF(3); fill=(:lightgray, α))
+ plot!(drawdiscI(3); fill=(:white, .5))
+ pline!([3,0,0], [4,0,0]; arrow=true, side=:head)
+ pline!([0,0,0], [0,0,1.25]; arrow=true, side=:head)
+
+
+ tt = range(0, pi, 30)
+ curve = [psurf(t, pi/2) for t in tt]
+ plot!(curve; line=(:black, 2))
+
+ f1 = [[t, _fold(t, 0, pi)] for t in tt]
+ curve = [psurf(f[1], f[2]) for f in f1]
+ plot!(curve; line=(:black,))
+
+ f2 = [[t, _fold(t, pi, 2*pi)] for t in tt]
+ curve = [psurf(f[1], f[2]) for f in f2]
+ plot!(curve; line=(:black,))
+
+
+
+ tt= [0.025*i for i in 1:121]
+ f1 = [[t, _fold(t, pi, 2*pi)] for t in tt]
+ for f in f1
+ plot!([psurf(f[1], f[2]-k*0.01*(4-f[1])) for k in 1:21];
+ line=(:black,1))
+ end
+ tt= [0.05*i for i in 1:61]
+ f1 = [[t, _fold(t, pi, 2*pi)] for t in tt]
+ for f in f1
+ plot!([psurf( f[1], f[2]-k*0.01*(6-f[1]) )
+ for k in 1:21]; line=(:black, 1))
+ end
+
+ current()
+
+
+end
+plt
+```
+
+```{julia}
+#| echo: false
+plotly()
+nothing
+```
+
+Modification of earlier figure to show washer method. The interior volumn would be given by $\int_a^b \pi r(x)^2 dx$, the entire volume by $\int_a^b \pi R(x)^2 dx$. The difference then is the volume computed by the washer method.
+
+:::
+
##### Example
@@ -412,19 +682,21 @@ Let $h$ be the distance from the apex to the base. Consider cones with the prope
```{julia}
-#| hold: true
#| echo: false
-h = 5
-R, r, rho = 1, 1/4, 1/4
-f(t) = (R-r) * cos(t) + rho * cos((R-r)/r * t)
-g(t) = (R-r) * sin(t) - rho * sin((R-r)/r * t)
-ts = range(0, 2pi, length=100)
+plt = let
+ h = 5
+ R, r, rho = 1, 1/4, 1/4
+ f(t) = (R-r) * cos(t) + rho * cos((R-r)/r * t)
+ g(t) = (R-r) * sin(t) - rho * sin((R-r)/r * t)
+ ts = range(0, 2pi, length=100)
-p = plot(f.(ts), g.(ts), zero.(ts), legend=false)
-for t ∈ range(0, 2pi, length=25)
- plot!(p, [0,f(t)], [0,g(t)], [h, 0], linecolor=:red)
+ plot(f.(ts), g.(ts), zero.(ts), legend=false)
+ for t ∈ range(0, 2pi, length=25)
+ plot!([0,f(t)], [0,g(t)], [h, 0], linecolor=:red)
+ end
+ current()
end
-p
+plot
```
A right circular cone is one where this shape is a circle. This definition can be more general, as a square-based right pyramid is also such a cone. After possibly reorienting the cone in space so the base is at $u=0$ and the apex at $u=h$ the volume of the cone can be found from:
@@ -450,6 +722,72 @@ $$
This gives a general formula for the volume of such cones.
+::: {#fig-cross-sections}
+
+```{julia}
+#| echo: false
+plt = let
+ gr()
+ # sections
+ # https://github.com/SigurdAngenent/WisconsinCalculus/blob/master/figures/221/09Xsections.py
+
+ x(h,z) = 0.3*h^2+(0.6-0.2*h)*cos(z)
+ y(h,z) = h+(0.3-0.2*h)*sin(z)+0.05*sin(4*z)
+ r(h,z) = (x(h,z), y(h,z))
+ r1(h,z) = (2,0) .+ r(h,z)
+
+ Nh=30
+ heights = range(-1/2, 1/2, Nh)
+ h0=heights[Nh ÷ 2]
+ h1=heights[Nh ÷ 2 + 1]
+ hs = [heights[1], h0, h1, heights[end]]
+ ts = range(0, 2pi, 300)
+
+ plot(; empty_style..., aspect_ratio=:equal)
+
+ # stack the curves
+ for h in heights
+ curve = r.(h, ts)
+ plot!(Shape(curve); fill=(:white, 1.0), line=(:black, 1))
+ end
+
+ # shape pull outs; use black to give thickness
+ for (h, color) in zip(hs, (:white, :black, :white, :white))
+ curve = r1.(h,ts)
+ plot!(Shape(curve); fill=(color,1.0), line=(:black, 1,))
+ end
+
+ # axis with marked points
+ plot!([(-1,-1), (-1, 1)]; axis_style...)
+ pts = [(-1, y(h, pi)) for h in hs]
+ scatter!(pts, marker=(5, :circle))
+
+ # connect with dashes
+ for h in hs
+ plot!([(-1, y(h, pi)), r(h,pi)]; line=(:black, 1, :dash))
+ plot!([r(h,0), r1(h,pi)]; line=(:black, 1, :dash))
+ end
+
+
+
+
+
+ current()
+
+
+end
+plt
+```
+
+This figure shows the volume of a figure being comprised of slices. A discrete approximation would be found by estimating the volume of each slice by the cross sectional area times a small $\Delta h$.
+(This figure was ported from @Angenent.)
+:::
+
+```{julia}
+#| echo: false
+plotly()
+nothing
+```
### Cavalieri's method
@@ -457,6 +795,47 @@ This gives a general formula for the volume of such cones.
[Cavalieri's](http://tinyurl.com/oda9xd9) Principle is "Suppose two regions in three-space (solids) are included between two parallel planes. If every plane parallel to these two planes intersects both regions in cross-sections of equal area, then the two regions have equal volumes." (Wikipedia).
+::: {#fig-Cavalieris-first}
+
+```{julia}
+#| echo: false
+plt = let
+ gr()
+
+ x(h,z) = (0.6-0.2*h) * cos(z)
+ y(h,z) = h + (0.2-0.15*h) * sin(z) + 0.01 * sin(4*z)
+ xa(h,z) = 2 + 0.1 * cos(7*pi*h) + (0.6-0.2*h)*cos(z)
+
+
+ heights = range(-1/2, 1/2, 50)
+ ts = range(0, 2pi, 300)
+ h0 = heights[25]
+ h1 = heights[26]
+
+ plot(; empty_style..., aspect_ratio=:equal)
+
+ for h in heights
+ curve=[(x(h, t), y(h, t)) for t in ts]
+ plot!(Shape(curve); fill=(:white,), line=(:black,1))
+
+ curve=[(xa(h, t), y(h, t)) for t in ts]
+ plot!(Shape(curve); fill=(:white,), line=(:black,1))
+ end
+ current()
+end
+plt
+```
+
+```{julia}
+#| echo: false
+plotly()
+nothing
+```
+
+Illustration of Cavalieri's first principle. The discs from the left are moved around to form the left volume, but as the volumes of each cross-sectional disc remains the same, the two valumes are equally approximated. (This figure ported from @Angenent.)
+
+:::
+
With the formula for the volume of solids based on cross sections, this is a trivial observation, as the functions giving the cross-sectional area are identical. Still, it can be surprising. Consider a sphere with an interior cylinder bored out of it. (The [Napkin](http://tinyurl.com/o237v83) ring problem.) The bore has height $h$ - for larger radius spheres this means very wide bores.
diff --git a/quarto/limits/intermediate_value_theorem.qmd b/quarto/limits/intermediate_value_theorem.qmd
index ab07071..5562eeb 100644
--- a/quarto/limits/intermediate_value_theorem.qmd
+++ b/quarto/limits/intermediate_value_theorem.qmd
@@ -32,12 +32,69 @@ If $f$ is continuous on $[a,b]$ with, say, $f(a) < f(b)$, then for any $y$ with
:::
+::: {#fig-IVT}
```{julia}
#| hold: true
#| echo: false
#| cache: true
### {{{IVT}}}
-gr()
+plt = let
+ gr()
+ # IVT
+ empty_style = (xaxis=([], false),
+ yaxis=([], false),
+ framestyle=:origin,
+ legend=false)
+ axis_style = (arrow=true, side=:head, line=(:gray, 1))
+ text_style = (10,)
+ fn_style = (;line=(:black, 3))
+ fn2_style = (;line=(:red, 4))
+ mark_style = (;line=(:gray, 1, :dot))
+ domain_style = (;fill=(:orange, 0.35), line=nothing)
+ range_style = (; fill=(:blue, 0.35), line=nothing)
+
+ f(x) = x + sinpi(3x) + 5sin(2x) + 3cospi(2x)
+ a, b = -1, 5
+ xs = range(a, b, 251)
+ ys = f.(xs)
+ y0, y1 = extrema(ys)
+
+ plot(; empty_style...)
+ plot!(f, a, b; fn_style...)
+
+ plot!([a-.2, b + .2],[0,0]; axis_style...)
+ plot!([a-.1, a-.1], [y0-2, y1+2]; axis_style...)
+
+ plot!([(a,0),(a,f(a))]; line=(:black, 1, :dash))
+ plot!([(b,0),(b,f(b))]; line=(:black, 1, :dash))
+
+ m = f(a/2 + b/2)
+ plot!([a, b], [m,m]; line=(:black, 1, :dashdot))
+
+ δx = 0.03
+ plot!(Shape([a,b,b,a], 4*δx*[-1,-1,1,1]);
+ domain_style...)
+ plot!(Shape((a-.1) .+ 2δx * [-1,1,1,-1], [f(a),f(a),f(b), f(b)]);
+ range_style...)
+ plot!(Shape((a-.1) .+ δx/2 * [-1,1,1,-1], [y0,y0,y1,y1]);
+ range_style...)
+
+ zs = find_zeros(f, (a,b))
+ c = zs[2]
+ plot!([(c,0), (c,f(c))]; line=(:black, 1, :dashdot))
+
+ annotate!([
+ (a, 0, text(L"a", 12, :bottom)),
+ (b, 0, text(L"b", 12, :top)),
+ (c, 0, text(L"c", 12, :top)),
+ (a-.1, f(a), text(L"f(a)", 12, :right)),
+ (a-.1, f(b), text(L"f(b)", 12, :right)),
+ (b, m, text(L"y", 12, :left)),
+ ])
+end
+plt
+
+#=
function IVT_graph(n)
f(x) = sin(pi*x) + 9x/10
a,b = [0,3]
@@ -76,7 +133,17 @@ with $f(x)=y$.
plotly()
ImageFile(imgfile, caption)
+=#
```
+```{julia}
+#| echo: false
+plotly()
+nothing
+```
+
+Illustration of the intermediate value theorem. The theorem implies that any randomly chosen $y$ value between $f(a)$ and $f(b)$ will have at least one $c$ in $[a,b]$ with $f(c)=y$. This graphic shows one of several possible values for the given choice of $y$.
+
+:::
In the early years of calculus, the intermediate value theorem was intricately connected with the definition of continuity, now it is a consequence.
diff --git a/quarto/limits/limits.qmd b/quarto/limits/limits.qmd
index 59c24b4..614319d 100644
--- a/quarto/limits/limits.qmd
+++ b/quarto/limits/limits.qmd
@@ -218,35 +218,64 @@ This bounds the expression $\sin(x)/x$ between $1$ and $\cos(x)$ and as $x$ gets
The above bound comes from this figure, for small $x > 0$:
+::: {#fig-sin-cos-bound}
```{julia}
#| hold: true
#| echo: false
-gr()
-p = plot(x -> sqrt(1 - x^2), 0, 1, legend=false, aspect_ratio=:equal,
- linewidth=3, color=:black)
-θ = π/6
-y,x = sincos(θ)
-col=RGBA(0.0,0.0,1.0, 0.25)
-plot!(range(0,x, length=2), zero, fillrange=u->y/x*u, color=col)
-plot!(range(x, 1, length=50), zero, fillrange = u -> sqrt(1 - u^2), color=col)
-plot!([x,x],[0,y], linestyle=:dash, linewidth=3, color=:black)
-plot!([x,1],[y,0], linestyle=:dot, linewidth=3, color=:black)
-plot!([1,1], [0,y/x], linewidth=3, color=:black)
-plot!([0,1], [0,y/x], linewidth=3, color=:black)
-plot!([0,1], [0,0], linewidth=3, color=:black)
-Δ = 0.05
-annotate!([(0,0+Δ,"A"), (x-Δ,y+Δ/4, "B"), (1+Δ/2,y/x, "C"),
- (1+Δ/2,0+Δ/2,"D")])
-annotate!([(.2*cos(θ/2), 0.2*sin(θ/2), "θ")])
-imgfile = tempname() * ".png"
-savefig(p, imgfile)
-caption = "Triangle ``ABD`` has less area than the shaded wedge, which has less area than triangle ``ACD``. Their respective areas are ``(1/2)\\sin(\\theta)``, ``(1/2)\\theta``, and ``(1/2)\\tan(\\theta)``. The inequality used to show ``\\sin(x)/x`` is bounded below by ``\\cos(x)`` and above by ``1`` comes from a division by ``(1/2) \\sin(x)`` and taking reciprocals.
-"
-plotly()
-ImageFile(imgfile, caption)
+plt = let
+ gr()
+
+ empty_style = (xaxis=([], false),
+ yaxis=([], false),
+ framestyle=:origin,
+ legend=false)
+ axis_style = (arrow=true, side=:head, line=(:gray, 1))
+ text_style = (10,)
+ fn_style = (;line=(:black, 3))
+ fn2_style = (;line=(:red, 4))
+ mark_style = (;line=(:gray, 1, :dot))
+ domain_style = (;fill=(:orange, 0.35), line=nothing)
+ range_style = (; fill=(:blue, 0.35), line=nothing)
+
+ plot(; empty_style..., aspect_ratio=:equal)
+ plot!(x -> sqrt(1 - x^2), 0, 1; line=(:black, 2))
+
+
+ θ = π/6
+ y,x = sincos(θ)
+ col=RGBA(0.0,0.0,1.0, 0.25)
+
+ plot!(range(0,x, length=2), zero, fillrange=u->y/x*u, color=col)
+ plot!(range(x, 1, length=50), zero, fillrange = u -> sqrt(1 - u^2), color=col)
+
+ plot!([x,x],[0,y], line=(:dash, 2, :black))
+ plot!([x,1],[y,0], line=(:dot, 2, :black))
+ plot!([1,1], [0,y/x], line=(2, :black))
+ plot!([0,1], [0,y/x], line=(2, :black))
+ plot!([0,1], [0,0], line=(2, :black))
+ Δ = 0.05
+ annotate!([(0,0+Δ, text(L"A", 10)),
+ (x-Δ,y+Δ/4, text(L"B",10)),
+ (1+Δ/2,y/x, text(L"C", 10)),
+ (1+Δ/2,0+Δ/2, text(L"D", 10)),
+ (0.2*cos(θ/2), 0.2*sin(θ/2), text(L"\theta", 12))
+ ])
+ current()
+end
+plt
```
+```{julia}
+#| echo: false
+plotly()
+nothing
+```
+
+Triangle $\triangle ABD$ has less area than the shaded wedge, which has less area than triangle $\triangle ACD$. Their respective areas are $(1/2)\sin(\theta)$, $(1/2)\theta$, and $(1/2)\tan(\theta)$. The inequality used to show $\sin(x)/x$ is bounded below by $\cos(x)$ and above by $1$ comes from a division by $(1/2) \sin(x)$ and taking reciprocals.
+
+:::
+
To discuss the case of $(1+x)^{1/x}$ it proved convenient to assume $x = 1/m$ for integer values of $m$. At the time of Cauchy, log tables were available to identify the approximate value of the limit. Cauchy computed the following value from logarithm tables:
diff --git a/quarto/precalc/functions.qmd b/quarto/precalc/functions.qmd
index b51b5a2..2df9f4b 100644
--- a/quarto/precalc/functions.qmd
+++ b/quarto/precalc/functions.qmd
@@ -42,6 +42,101 @@ For these examples, the domain of both $f(x)$ and $g(x)$ is all real values of $
In general the range is harder to identify than the domain, and this is the case for these functions too. For $f(x)$ we may know the $\cos$ function is trapped in $[-1,1]$ and it is intuitively clear than all values in that set are possible. The function $h(x)$ would have range $[0,\infty)$. The $s(x)$ function is either $-1$ or $1$, so only has two possible values in its range. What about $g(x)$? It is a parabola that opens upward, so any $y$ values below the $y$ value of its vertex will not appear in the range. In this case, the symmetry indicates that the vertex will be at $(1/2, -1/4)$, so the range is $[-1/4, \infty)$.
+::: {#fig-domain-range layout-nrow=2}
+```{julia}
+#| echo: false
+plt = let
+ gr()
+ # domain/range shade
+ λ = 1.2
+ a, b = .1, 3
+ f(x) = (x-1/2) + sin((x-1)^2)
+
+ empty_style = (xaxis=([], false),
+ yaxis=([], false),
+ framestyle=:origin,
+ legend=false)
+ axis_style = (arrow=true, side=:head, line=(:gray, 1))
+ text_style = (10,)
+ fn_style = (;line=(:black, 3))
+ fn2_style = (;line=(:red, 4))
+ mark_style = (;line=(:gray, 1, :dot))
+
+ domain_style = (;fill=(:orange, 0.35))
+ range_style = (; fill=(:blue, 0.35))
+
+ xs = range(a,b, 1000)
+ y0,y1 = extrema(f.(xs))
+ Δy = (y1-y0)/60
+ Δx = (b - a)/75
+
+ plot(; aspect_ratio=:equal, empty_style...)
+ plot!([-.25,3.25],[0,0]; axis_style...)
+ plot!([0,0], [min(-2Δy, y0 - Δy), y1 + 4Δy]; axis_style... )
+
+ plot!(f, a, b; fn_style...)
+ plot!(Shape([a,b,b,a], Δy * [-1,-1,1,1] ); domain_style...)
+ plot!(Shape(Δx*[-1,1,1,-1], [y0,y0,y1,y1]); range_style...)
+
+ plot!([a,a], [0, f(a)]; mark_style...)
+ plot!([b,b], [0, f(b)]; mark_style...)
+ plot!([a, b], [f(a), f(a)]; mark_style...)
+ plot!([a, b], [f(b), f(b)]; mark_style...)
+end
+plot
+```
+
+```{julia}
+#| echo: false
+plt = let
+ a, b = 0, 2pi
+ λ = 1.1
+ Δx, Δy = .033, .1
+ δx = 0.05
+ f(x) = sec(x)
+ g(x) = abs(f(x)) < 5 ? f(x) : NaN
+
+ empty_style = (xaxis=([], false),
+ yaxis=([], false),
+ framestyle=:origin,
+ legend=false)
+ axis_style = (arrow=true, side=:head, line=(:gray, 1))
+ text_style = (10,)
+ fn_style = (;line=(:black, 3))
+ fn2_style = (;line=(:red, 4))
+ mark_style = (;line=(:gray, 1, :dot))
+
+ domain_style = (;fill=(:orange, 0.35))
+ range_style = (; fill=(:blue, 0.35))
+
+
+ plot(; empty_style...)
+ plot!(g, a+0.1, b; fn_style...)
+ plot!(λ*[a,b],[0,0]; axis_style...)
+ plot!([0,0], λ*[-5,5+1/2]; axis_style...)
+ vline!([pi/2, 3pi/2]; line=(:gray, :dash))
+
+ plot!(Shape([a,a+pi/2-δx,a+pi/2-δx,a], Δy*[-1,-1,1,1]); domain_style...)
+ plot!(Shape([a+pi/2+δx, a+pi/2+pi-δx,a+pi/2+pi-δx,a+pi/2+δx],
+ Δy*[-1,-1,1,1]); domain_style...)
+ plot!(Shape([3pi/2 + δx, 2pi, 2pi, 3pi/2+δx],
+ Δy*[-1,-1,1,1]); domain_style...)
+ plot!(Shape(Δx*[-1,1,1,-1], [-5, -5,-1,-1]); range_style...)
+ plot!(Shape(Δx*[-1,1,1,-1], [ 5, 5,1,1]); range_style...)
+end
+plot
+```
+
+
+```{julia}
+#| echo: false
+plotly()
+nothing
+```
+
+The top figure shows the domain and range of the function as highlighted intervals. The bottom figure shows that the domain may be a collection of intervals. (In this case the $\sec$ function is not defined at $\pi/2 + k \pi$ for integer $k$) and the range may be a collection of intervals. (In this case, the $\sec$ function never have a value in $(-1,1)$.
+:::
+
:::{.callout-note}
## Note
@@ -90,7 +185,7 @@ Whereas function definitions and usage in `Julia` mirrors standard math notation
:::
-### The domain of a function
+### The domain of a function in Julia
Functions in `Julia` have an implicit domain, just as they do mathematically. In the case of $f(x)$ and $g(x)$, the right-hand side is defined for all real values of $x$, so the domain is all $x$. For $h(x)$ this isn't the case, of course. Trying to call $h(x)$ when $x < 0$ will give an error:
@@ -347,10 +442,27 @@ In our example, we see that in trying to find an answer to $f(x) = 0$ ( $\sqrt{2
```{julia}
#| echo: false
-plot(q, a, b, linewidth=5, legend=false)
-plot!(zero, a, b)
-plot!([a, b], q.([a, b]))
-scatter!([c], [q(c)])
+plt = let
+gr()
+plt = plot(q, a, b, linewidth=5, legend=false)
+plot!(plt, zero, a, b)
+plot!(plt, [a, b], q.([a, b]))
+scatter!(plt, [c], [q(c)]; marker=(:circle,))
+scatter!(plt, [a,b], [q(a), q(b)]; marker=(:square,))
+
+annotate!(plt, [
+(a, 0, text(L"a", 10,:top)),
+(b, 0, text(L"b", 10, :top)),
+(c, 0, text(L"c", 10, :bottom))
+])
+end
+plt
+```
+
+```{julia}
+#| echo: false
+plotly()
+nothing
```
Still, `q(c)` is not really close to $0$:
@@ -398,6 +510,7 @@ c = secant_intersection(f, a, b)
p = plot(f, a, b, linewidth=5, legend=false)
plot!(p, zero, a, b)
+scatter!([a,b], [f(a), f(b)]; marker=(:square,))
plot!(p, [a,b], f.([a,b]));
scatter!(p, [c], [f(c)])
@@ -918,6 +1031,86 @@ answ = 1
radioq(choices, answ)
```
+##### Question
+
+::: {#fig-floor-function}
+
+```{julia}
+#| echo: false
+plt = let
+ gr()
+ empty_style = (xaxis=([], false),
+ yaxis=([], false),
+ framestyle=:origin,
+ legend=false)
+ axis_style = (arrow=true, side=:head, line=(:gray, 1))
+ text_style = (10,)
+ fn_style = (;line=(:black, 3))
+ fn2_style = (;line=(:red, 4))
+ mark_style = (;line=(:gray, 1, :dot))
+ domain_style = (;fill=(:orange, 0.35), line=nothing)
+ range_style = (; fill=(:blue, 0.35), line=nothing)
+
+ ts = range(0, 2pi, 100)
+ xys = sincos.(ts)
+ xys = [.1 .* xy for xy in xys]
+
+ plot(; empty_style..., aspect_ratio=:equal)
+ plot!([-4.25,4.25], [0,0]; axis_style...)
+ plot!([0,0], [-4.25, 4.25]; axis_style...)
+
+ for k in -4:4
+ P,Q = (k,k),(k+1,k)
+ plot!([P,Q], line=(:black,1))
+ S = Shape([k .+ xy for xy in xys])
+ plot!(S; fill=(:black,))
+ S = Shape([(k+1,k) .+ xy for xy in xys])
+ plot!(S; fill=(:white,), line=(:black,1))
+ end
+ current()
+end
+plotly()
+plt
+```
+
+The `floor` function rounds down. For example, any value in $[k,k+1)$ rounds to $k$ for integer $k$.
+:::
+
+The figure shows the `floor` function which is useful in programming. It rounds down to the first integer value.
+
+
+From the graph, what is the domain of the function?
+
+
+```{julia}
+#| hold: true
+#| echo: false
+choices = [
+ "The entire real line",
+ "The entire real line except for integer values",
+ "The integers"
+]
+answer = 1
+radioq(choices, answ)
+```
+
+From the graph, what is the range of the function?
+
+
+```{julia}
+#| hold: true
+#| echo: false
+choices = [
+ "The entire real line",
+ "The entire real line except for integer values",
+ "The integers"
+]
+answer = 3
+radioq(choices, answ)
+```
+
+(This graphic uses the convention that a filled in point is present, but an open point is not, hence each bar represents some $[k, k+1)$.)
+
###### Question
diff --git a/quarto/precalc/inversefunctions.qmd b/quarto/precalc/inversefunctions.qmd
index 324a4da..822b3cf 100644
--- a/quarto/precalc/inversefunctions.qmd
+++ b/quarto/precalc/inversefunctions.qmd
@@ -30,20 +30,57 @@ Why is this useful? When available, it can help us solve equations. If we can wr
Let's explore when we can "solve" for an inverse function.
-Consider the graph of the function $f(x) = 2^x$:
-
+Consider this graph of the function $f(x) = 2^x$
```{julia}
-#| hold: true
-f(x) = 2^x
-plot(f, 0, 4, legend=false)
-plot!([2,2,0], [0,f(2),f(2)])
+#| echo: false
+p = let
+ gr()
+ empty_style = (xaxis=([], false),
+ yaxis=([], false),
+ framestyle=:origin,
+ legend=false)
+ axis_style = (arrow=true, side=:head, line=(:gray, 1))
+ text_style = (10,)
+ fn_style = (;line=(:black, 3))
+ fn2_style = (;line=(:red, 4))
+ mark_style = (;line=(:gray, 1, :dot))
+ domain_style = (;fill=(:orange, 0.35), line=nothing)
+ range_style = (; fill=(:blue, 0.35), line=nothing)
+
+ f(x) = 2^x
+ a, b = 0, 2
+ plot(; empty_style...)
+ xs = range(a, b, 200)
+ ys = f.(xs)
+
+ plot!( xs, ys; fn_style...)
+ plot!([a-1/4, b+.2], [0,0]; axis_style...)
+ plot!([0, 0], [-.1, f(2.1)]; axis_style...)
+
+ x = 1
+ y = (f(b)+f(a))/2
+ plot!([x,x,0],[0,f(x),f(x)]; line=(:black, 1, :dash), arrow=true, side=:head)
+ plot!([0,log2(y), log2(y)], [y,y,0]; line=(:black,1,:dash), arrow=true, side=:head)
+
+ annotate!([
+ (x, 0, text(L"c", 10, :top)),
+ (0,f(x), text(L"f(c)", 10, :right)),
+ (0, y, text(L"y=f(d)", 10, :right)),
+ (log2(y), 0, text(L"d", 10, :top))
+
+ ])
+
+
+end
+plotly()
+p
```
The graph of a function is a representation of points $(x,f(x))$, so to *find* $y = f(c)$ from the graph, we begin on the $x$ axis at $c$, move vertically to the graph (the point $(c, f(c))$), and then move horizontally to the $y$ axis, intersecting it at $y = f(c)$. The figure shows this for $c=2$, from which we can read that $f(c)$ is about $4$. This is how an $x$ is associated to a single $y$.
-If we were to *reverse* the direction, starting at $y = f(c)$ on the $y$ axis and then moving horizontally to the graph, and then vertically to the $x$-axis we end up at a value $c$ with the correct $f(c)$. This allows solving for $x$ knowing $y$ in $y=f(x)$.
+If we were to *reverse* the direction, starting at $y = f(d)$ on the $y$ axis and then moving horizontally to the graph, and then vertically to the $x$-axis we end up at a value $d$ with the correct $f(d)$. This allows solving for $x$ knowing $y$ in $y=f(x)$.
The operation described will form a function **if** the initial movement horizontally is guaranteed to find *no more than one* value on the graph. That is, to have an inverse function, there can not be two $x$ values corresponding to a given $y$ value. This observation is often visualized through the "horizontal line test" - the graph of a function with an inverse function can only intersect a horizontal line at most in one place.
@@ -309,6 +346,131 @@ What do we see? In blue, we can see the familiar square root graph along with a
This is reminiscent of the formula for the slope of a perpendicular line, $-1/m$, but quite different, as this formula implies the two lines have either both positive slopes or both negative slopes, unlike the relationship in slopes between a line and a perpendicular line.
+::: {#fig-inverse-normal layout-ncol=1}
+```{julia}
+#| echo: false
+# inverse function slope
+gr()
+p1 = let
+ f(x) = x^2
+ df(x) = 2x
+
+ empty_style = (xaxis=([], false),
+ yaxis=([], false),
+ framestyle=:origin,
+ legend=false)
+ axis_style = (arrow=true, side=:head, line=(:gray, 1))
+ text_style = (10,)
+ fn_style = (;line=(:black, 3))
+ fn2_style = (;line=(:red, 4))
+ mark_style = (;line=(:gray, 1, :dot))
+
+ plot(; aspect_ratio=:equal, empty_style...)
+ xs = range(0, 1.25, 100)
+ plot!(xs,f.(xs); fn_style...)
+ plot!(f.(xs), xs; fn2_style...)
+ plot!(identity, -1/4, 2; line=(:gray, 1, :dot))
+
+ #plot!([-.1, 1.35],[0,0]; axis_style...)
+ #plot!([0,0], [-0.1, f(1.3)]; axis_style...)
+
+ c = .4
+ m = df(c)
+ tl(x) = f(c) + df(c)*(x-c)
+ plot!(tl; line=(:black, 1, :dash))
+ d = c + .6
+ p1, p2, p3 = (c, tl(c)), (d, tl(c)), (d, tl(d))
+ q1, q2, q3 = (tl(c),c), (tl(c),d), (tl(d), d)
+
+ plot!([p1, p2, p3]; line=(:black, 1, :dot))
+
+
+ tl1(x) = c + (1/m)*(x - f(c))
+ plot!(tl1; line=(:red, 1, :dash))
+ plot!([q1, q2, q3]; line=(:red, 1, :dot))
+
+ annotate!([
+ ((c+d)/2, f(c), text(L"\Delta x", 10, :top, :black)),
+ (d, (tl(c)+tl(d))/2, text(L"\Delta y", 10, :left, :black)),
+ (f(c), (c+d)/2, text(L"\Delta x", 10, :right, :red)),
+ ((tl(c)+tl(d))/2, d, text(L"\Delta y", 10, :bottom, :red)),
+ (d, tl(d),
+ text(L"rise/run = $m = \Delta y / \Delta x$", 10, :top, :left,
+ rotation= rad2deg(atan(m)))),
+ (tl(d), d,
+ text(L"rise/run = $\Delta x / \Delta y = 1/m$", 10, :bottom, :left, rotation=rad2deg(atan(1/m)))),
+ (1.9, 1.9, text(L"y=x", 10, :top, rotation=45))
+
+
+
+ ])
+ current()
+end
+
+# normal line
+
+p2 = let
+ f(x) = 4 - (x-2)^2
+ df(x) = -2*(x-2)
+
+ empty_style = (xaxis=([], false),
+ yaxis=([], false),
+ framestyle=:origin,
+ legend=false)
+ axis_style = (arrow=true, side=:head, line=(:gray, 1))
+ text_style = (10,)
+ fn_style = (;line=(:black, 3))
+ fn2_style = (;line=(:red, 4))
+ mark_style = (;line=(:gray, 1, :dot))
+
+ plot(; aspect_ratio=:equal, empty_style...,
+ xlims=(1, 2.5), ylims=(3, 4.5))
+ xs = range(.99, 2.01, 100)
+ plot!(xs,f.(xs); fn_style...)
+
+ c = 1.5
+ tl(x) = f(c) + df(c)*(x-c)
+ nl(x) = f(c) - (x-c)/df(c)
+
+ xs = range(1, 2, 10)
+ plot!(xs, tl.(xs); fn2_style...)
+
+ xs = range(.9, 2, 10)
+ plot!(xs, nl.(xs); fn2_style...)
+
+ ylims!((f(.85), nl(.95)))
+
+ o = 1/3
+ plot!([c,c+o, c+o], [tl(c), tl(c), tl(c+o)]; mark_style...)
+ m = (tl(c+o) - tl(c))
+ plot!([c,c,c+m], [nl(c),nl(c + m),nl(c+m)]; mark_style...)
+
+ theta = rad2deg(atan(tl(c+o)-tl(c), o))
+ annotate!([
+ (c + o/2, f(c), text(L"1", :top, 10)),
+ (c + o, (f(c)+f(c+o))/2, text(L"m", :right, 10)),
+ (c, (nl(c) + nl(c+m))/2, text(L"-1", :right, 10)),
+ (c+m/2, nl(c+m), text(L"m", :top, 10)),
+ (c + o/2, tl(c+o), text(L"rise/run $=m/1$", 10, :top,
+ rotation=theta)),
+ (c + 1.1*o, nl(c+1.1*o), text(L"rise/run $=(-1)/m$", 10, :bottom,
+ rotation=theta-90))
+ ])
+ current()
+end
+
+plot(p1, p2)
+```
+
+The inverse function has slope at a corresponding point that is the *reciprocal*; the "normal line" for a function at a point has slope that is the *negative reciprocal* of the "tangent line" at a point.
+
+:::
+
+```{julia}
+#| echo: false
+plotly()
+nothing
+```
The key here is that the shape of $f(x)$ near $x=c$ is somewhat related to the shape of $f^{-1}(x)$ at $f(c)$. In this case, if we use the tangent line as a fill in for how steep a function is, we see from the relationship that if $f(x)$ is "steep" at $x=c$, then $f^{-1}(x)$ will be "shallow" at $x=f(c)$.
diff --git a/quarto/precalc/plotting.qmd b/quarto/precalc/plotting.qmd
index c98c2dd..4218c76 100644
--- a/quarto/precalc/plotting.qmd
+++ b/quarto/precalc/plotting.qmd
@@ -108,11 +108,6 @@ Plotting a function is then this simple: `plot(f, xmin, xmax)`.
-:::{.callout-note}
-## Note
-The time to first plot can feel sluggish, but subsequent plots will be speedy. See the technical note at the end of this section for an explanation.
-
-:::
Let's see some other graphs.
@@ -193,7 +188,70 @@ Some types we will encounter, such as the one for symbolic values or the special
:::
----
+:::{.callout-note}
+## Viewing window
+
+The default style for `Plots.jl` is to use a frame style where the viewing window is emphasized. This is a rectangular region, $[x_0, x_1] \times [y_0, y_1]$, which is seen through the tick labeling, the bounding scales on the left and bottom, and emphasized through the grid.
+
+This choices does *not* show the $x-y$ axes. As such, we might layer on the axes when these are of interest.
+
+To emphasize concepts, we may stylize a function graph, rather than display the basic graphic. For example, in this graphic highlighting the amount the function goes up as it moves from $1$ to $x$:
+
+```{julia}
+gr()
+#| echo: false
+let
+ f(x) = x^2
+
+ empty_style = (xaxis=([], false),
+ yaxis=([], false),
+ framestyle=:origin,
+ legend=false)
+ axis_style = (arrow=true, side=:head, line=(:gray, 1))
+ text_style = (10,)
+ fn_style = (;line=(:black, 3))
+ fn2_style = (;line=(:red, 4))
+ mark_style = (;line=(:gray, 1, :dot))
+
+ plot(; empty_style..., aspect_ratio=:equal)
+ a, b = 0, 1.25
+ x = 1.15
+
+ plot!(f, a, b; fn_style...)
+ plot!([-.1, 1.5], [0,0]; axis_style...)
+ plot!([0,0], [-.1, f(1.35)]; axis_style...)
+
+ plot!([1,x,x], [f(1),f(1),f(x)]; line=(:black, 1))
+ plot!([1,1],[0,f(1)]; mark_style...)
+ plot!([x,x],[0,f(1)]; mark_style...)
+ plot!([0,1],[f(1),f(1)]; mark_style...)
+ plot!([0,x],[f(x),f(x)]; mark_style...)
+
+ annotate!([
+ (1, 0, text(L"1", 10, :top)),
+ (x, 0, text(L"x", 10, :top)),
+ (0, f(1), text(L"1", 10, :right)),
+ (0, f(x), text(L"x^2", 10, :right)),
+ (1, f(1), text(L"P", 10, :right, :bottom)),
+ (x, f(x), text(L"Q", 10, :right, :bottom)),
+ ((1 + x)/2, f(1), text(L"\Delta x", 10, :top)),
+ (x, (f(1) + f(x))/2, text(L"\Delta y", 10, :left))
+ ])
+ current()
+end
+```
+
+```{julia}
+#| echo: false
+plotly()
+nothing
+```
+
+:::
+
+
+
+----
Making a graph with `Plots` is easy, but producing a graph that is informative can be a challenge, as the choice of a viewing window can make a big difference in what is seen. For example, trying to make a graph of $f(x) = \tan(x)$, as below, will result in a bit of a mess - the chosen viewing window crosses several places where the function blows up:
@@ -699,6 +757,40 @@ plot(f, g, 0, max((R-r)/r, r/(R-r))*2pi)
In the above, one can fix $R=1$. Then different values for `r` and `rho` will produce different graphs. These graphs will be periodic if $(R-r)/r$ is a rational. (Nothing about these equations requires $\rho < r$.)
+## Points, lines, polygons
+
+Two basic objects to graph are points and lines.
+
+A point in two-dimensional space has two coordinates, often denoted by $(x,y)$. In `Julia`, the same notation produces a `tuple`. Using square brackets, as in `[x,y]`, produces a vector. Vectors are usually used, as we have seen there are algebraic operations defined for them. However, tuples have other advantages and are how `Plots` designates a point.
+
+The plot command `plot(xs, ys)` plots the points $(x_1,y_1), \dots, (x_n, y_n)$ and then connects adjacent points with with lines. The command `scatter(xs, ys)` just plots the points.
+
+However, the points might be more naturally specified as coordinate pairs. If tuples are used to pair them off, then `Plots` will plot a vector of tuples as a sequence of points:
+
+```{julia}
+pts = [(1, 0), (1/4, 1/4), (0, 1), (-1/4, 1/4), (-1, 0),
+ (-1/4, -1/4), (0, -1), (1/4, -1/4)]
+scatter(pts; legend=false)
+```
+
+A line segment simply connects two points. While these can be specified as vectors of $x$ and $y$ values, again it may be more convenient to use coordinate pairs to specify the points. Continuing the above, we can connect adjacent points with line segments:
+
+```{julia}
+plot!(pts; line=(:gray, 0.5, :dash))
+```
+
+This uses the shorthand notation of `Plots` to specify `linecolor=:gray, linealpha=0.5, linestyle=:dash`. To plot just a line segment, just specifying two points suffices.
+
+The four-pointed star is not closed off, as there isn't a value from the last point to the first point. A polygon closes itself off. The `Shape` function can take a vector of points or a pair of `xs` and `ys` to specify a polygon. When these are plotted, the arguments to `fill` describe the interior of the polygon, the arguments to `line` the boundary:
+
+
+```{julia}
+plot(Shape(pts); fill=(:gray, 0.25), line=(:black, 2), legend=false)
+scatter!(pts)
+```
+
+
+
## Questions
diff --git a/quarto/references.bib b/quarto/references.bib
index b096c05..a324c0b 100644
--- a/quarto/references.bib
+++ b/quarto/references.bib
@@ -18,6 +18,15 @@
+@Misc{Angenent,
+ key = {WisconsinCalculus},
+ author = {Sigurd Angenent},
+ title = {Wisconsin Calculus},
+ howpublished = {https://github.com/SigurdAngenent/WisconsinCalculus/tree/master},
+ year = 2012,
+ note = {GNU Free Documentation License, Version 1.2}
+ }
+
@Book{Schey,
author = {H.M. Schey},
title = {Div, Grad, Curl, and all that},