work on better figures
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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)$.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user