14 Visual Demos
Somewhat experimental, and better on a larger screen.
14.1 Cauchy’s Mean Value Theorem
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
import matplotlib.pyplot as plt
import numpy as np
from shiny.express import ui, input, render
sin = np.sin
with ui.tags.head():
ui.tags.link(
rel="stylesheet",
href="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.css"
),
ui.tags.script(src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.js"),
ui.tags.script(src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/contrib/auto-render.min.js"),
ui.tags.script("""
document.addEventListener('DOMContentLoaded', function() {
renderMathInElement(document.body, {
delimiters: [
{left: "$$", right: "$$", display: true},
{left: "\\[", right: "\\]", display: true},
{left: "$", right: "$", display: false},
{left: "\\(", right: "\\)", display: false}
]
});
});
""")
ui.tags.style(
"""
body { background: #C8E0FF !important; }
.irs-bar { background: #0054A9 !important; }
.irs-handle { background: #0054A9 !important; }
.irs-single { background: #0054A9 !important; color: #FFFFFF !important; }
.irs-min { background:#99CBFF !important; color: #000000 !important; }
.irs-max { background:#99CBFF !important; color: #000000 !important; }
.control-label { display: block; text-align: center; }
.shiny-input-container { margin:auto; }
"""
)
a = -0.5
b = 10
npts = 400
ui.input_slider(id="t",label="$t$ slider",min=a,max=b,value=2,step=0.25)
@render.plot(alt="Graph of the tangent to the parametric curve at $t$.")
def ball():
t = input.t()
def f(x):
return (x+2)/(x**2+1)
def g(x):
return (x**2+20*x-2)/(x**2+30)
def df(x):
return -(-1 + 4*x + x**2)/(1 + x**2)**2
def dg(x):
return (600 + 64*x - 20*x**2)/(30 + x**2)**2
U = [a + (b-a)*i/npts for i in range(0,npts+1)]
X = [g(u) for u in U]
Y = [f(u) for u in U]
plt.figure(facecolor='#C8E0FF')
plt.plot(X,Y,color="#0054A9",label="parametric curve $(g(t),f(t))$")
plt.plot([g(a),g(b)],[f(a),f(b)],color="#00A954",label="secant line")
plt.plot(g(a),f(a),color="#0054A9",markersize=5,marker="o")
plt.plot(g(b),f(b),color="#0054A9",markersize=5,marker="o")
ax = plt.gca()
ax.set_aspect('equal')
ax.set_facecolor('#C8E0FF')
ax.axline((g(t),f(t)),slope=df(t)/dg(t),color="#FF9933",label="tangent at $(g(t),f(t))$")
plt.plot(g(t),f(t),color="#FF9933",markersize=5,marker="o")
ax.legend(facecolor='#C8E0FF',frameon=False)14.2 \(L_p\) Norms
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
import matplotlib.pyplot as plt
import numpy as np
from shiny.express import ui, input, render
with ui.tags.head():
ui.tags.link(
rel="stylesheet",
href="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.css"
),
ui.tags.script(src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.js"),
ui.tags.script(src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/contrib/auto-render.min.js"),
ui.tags.script("""
document.addEventListener('DOMContentLoaded', function() {
renderMathInElement(document.body, {
delimiters: [
{left: "$$", right: "$$", display: true},
{left: "\\[", right: "\\]", display: true},
{left: "$", right: "$", display: false},
{left: "\\(", right: "\\)", display: false}
]
});
});
""")
ui.tags.style(
"""
body { background: #C8E0FF !important; }
.irs-bar { background: #0054A9 !important; }
.irs-handle { background: #0054A9 !important; }
.irs-single { background: #0054A9 !important; color: #FFFFFF !important; }
.irs-min { background:#99CBFF !important; color: #000000 !important; }
.irs-max { background:#99CBFF !important; color: #000000 !important; }
.control-label { display: block; text-align: center; }
"""
)
ui.input_slider(id="p",label="Ball and sphere for the $L_p$ norm.",min=1,max=8,value=2,step=0.5).add_style("margin:auto;") # center the slider
@render.plot(alt="Unit ball and sphere for the $L_p$ norm.")
def ball():
p = input.p()
npts = 200
X = [-1 + 2*x/npts for x in range(0,npts+1)]
Ytop = [(1-abs(x)**p)**(1/p) for x in X]
Ybot = [-(1-abs(x)**p)**(1/p) for x in X]
plt.figure(facecolor='#C8E0FF')
plt.plot(X,Ytop,color="#0054A9")
plt.plot(X,Ybot,color="#0054A9")
plt.fill_between(X,Ytop,color="#99CBFF")
plt.fill_between(X,Ybot,color="#99CBFF")
plt.xlim(-1.4,1.4)
plt.ylim(-1.4,1.4)
ax = plt.gca()
ax.set_aspect('equal')
ax.set_facecolor('#C8E0FF')14.3 Newton’s Method
Applied to \(f(x) = x^3 - 4x - 2\) starting from \(x_0 = 5\). It will converge quite quickly to a root.
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
import matplotlib.pyplot as plt
import numpy as np
from shiny import reactive, render
from shiny.express import input, ui
ui.tags.style(
"""
body { background: #C8E0FF !important; }
.shiny-input-container { margin:auto; }
.action-button { background-color: #99CBFF; color: black; border: none;}
.action-button:hover { background-color: #0054A9; color: white; border-color: none;}
"""
)
with ui.layout_columns(col_widths=(-2,3,-2,3,-2)):
ui.input_action_button("step", "Step")
ui.input_action_button("reset", "Reset")
rxcur = reactive.value(5)
@reactive.effect
@reactive.event(input.reset, ignore_none=False)
def _():
rxcur.set(5)
@render.plot(alt="Newton's method step from $x_n$ to $x_{n+1}$")
@reactive.event(input.step,input.reset, ignore_none=False)
def nmplot():
def f(x):
return x**3 - 4*x - 2
def df(x):
return 3*x**2 - 4
xcur = rxcur.get()
xnew = xcur - f(xcur)/df(xcur)
# plotting
fig, ax = plt.subplots()
xs = list(np.linspace(xnew-0.5,xcur+0.5,100))
# the function
ax.plot(xs,[f(x) for x in xs],color="#0054A9",label="$f(x)=x^3 - 4x - 2$")
# current point and tangent
ax.plot(xcur,f(xcur),color="#FF9933",markersize=5,marker="o")
ax.plot(xs, [f(xcur) + df(xcur)*(x-xcur) for x in xs],color="#FF9933",label="tangent at $(x_n,f(x_n))$")
# informational text
ax.scatter([],[],marker="",color="black", label=f"$x_n = {xcur:.4f}$")
ax.scatter([],[],marker="",color="black", label=f"$x_{{n+1}} = {xnew:.4f}$")
# formatting
fig.set_facecolor('#C8E0FF')
ax.set_facecolor('#C8E0FF')
ax.spines.right.set_color('none')
ax.spines.bottom.set_position('zero')
ax.spines.top.set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.set_xticks([xcur,xnew],["$x_n$","$x_{n+1}$"])
ax.legend(facecolor='#C8E0FF',frameon=False)
rxcur.set(xnew)
return figOn the other hand, we could apply it to \(\arctan(x)\). This will not converge for all initial values – in fact, it will diverge extremely quickly (can you see why?). In this example, it starts from \(x_0 = 1.5\) and reaches what the computer considers \(\infty\) in just a couple steps.
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
import matplotlib.pyplot as plt
import numpy as np
from shiny import reactive, render
from shiny.express import input, ui
ui.tags.style(
"""
body { background: #C8E0FF !important; }
.shiny-input-container { margin:auto; }
.action-button { background-color: #99CBFF; color: black; border: none;}
.action-button:hover { background-color: #0054A9; color: white; border-color: none;}
"""
)
with ui.layout_columns(col_widths=(-2,3,-2,3,-2)):
ui.input_action_button("step", "Step")
ui.input_action_button("reset", "Reset")
rxcur = reactive.value(1.5)
@reactive.effect
@reactive.event(input.reset, ignore_none=False)
def _():
rxcur.set(1.5)
@render.plot(alt="Newton's method step from $x_n$ to $x_{n+1}$")
@reactive.event(input.step,input.reset, ignore_none=False)
def nmplot():
def f(x):
return np.arctan(x)
def df(x):
return 1/(1+x**2)
xcur = rxcur.get()
xnew = xcur - f(xcur)/df(xcur)
# plotting
fig, ax = plt.subplots()
bd = 24
xs = list(np.linspace(-bd-1,bd+1,200))
# the function
ax.plot(xs,[f(x) for x in xs],color="#0054A9",label="$f(x)=\\arctan(x)$")
# current point and tangent
ax.plot(xcur,f(xcur),color="#FF9933",markersize=5,marker="o")
ax.plot(xs, [f(xcur) + df(xcur)*(x-xcur) for x in xs],color="#FF9933",label="tangent at $(x_n,f(x_n))$")
# informational text
ax.scatter([],[],marker="",color="black", label=f"$x_n = {xcur:.4f}$")
ax.scatter([],[],marker="",color="black", label=f"$x_{{n+1}} = {xnew:.4f}$")
# formatting
fig.set_facecolor('#C8E0FF')
ax.set_facecolor('#C8E0FF')
ax.set_ylim(-2, 2)
ax.set_xlim(-bd, bd)
ax.spines.right.set_color('none')
ax.spines.top.set_color('none')
ax.spines.bottom.set_position('zero')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
tx = []
tl = []
if abs(xcur) < 23:
tx += [xcur]
tl += ["$x_n$"]
if abs(xnew) < 23:
tx += [xnew]
tl += ["$x_{n+1}$"]
ax.set_xticks(tx,tl)
ax.legend(facecolor='#C8E0FF',frameon=False)
rxcur.set(xnew)
return figHowever, we know that our convergence theorem should apply somewhere near an actual root. From \(x_0 = 1.25\), it rapidly converges to the root at \(x=0\).
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
import matplotlib.pyplot as plt
import numpy as np
from shiny import reactive, render
from shiny.express import input, ui
ui.tags.style(
"""
body { background: #C8E0FF !important; }
.shiny-input-container { margin:auto; }
.action-button { background-color: #99CBFF; color: black; border: none;}
.action-button:hover { background-color: #0054A9; color: white; border-color: none;}
"""
)
with ui.layout_columns(col_widths=(-2,3,-2,3,-2)):
ui.input_action_button("step", "Step")
ui.input_action_button("reset", "Reset")
rxcur = reactive.value(1.25)
@reactive.effect
@reactive.event(input.reset, ignore_none=False)
def _():
rxcur.set(1.25)
@render.plot(alt="Newton's method step from $x_n$ to $x_{n+1}$")
@reactive.event(input.step,input.reset, ignore_none=False)
def nmplot():
def f(x):
return np.arctan(x)
def df(x):
return 1/(1+x**2)
xcur = rxcur.get()
xnew = xcur - f(xcur)/df(xcur)
# plotting
fig, ax = plt.subplots()
bd = 1.5
xs = list(np.linspace(-bd-1,bd+1,200))
# the function
ax.plot(xs,[f(x) for x in xs],color="#0054A9",label="$f(x)=\\arctan(x)$")
# current point and tangent
ax.plot(xcur,f(xcur),color="#FF9933",markersize=5,marker="o")
ax.plot(xs, [f(xcur) + df(xcur)*(x-xcur) for x in xs],color="#FF9933",label="tangent at $(x_n,f(x_n))$")
# informational text
ax.scatter([],[],marker="",color="black", label=f"$x_n = {xcur:.4f}$")
ax.scatter([],[],marker="",color="black", label=f"$x_{{n+1}} = {xnew:.4f}$")
# formatting
fig.set_facecolor('#C8E0FF')
ax.set_facecolor('#C8E0FF')
ax.set_ylim(-1.5, 1.5)
ax.set_xlim(-bd, bd)
ax.spines.right.set_color('none')
ax.spines.top.set_color('none')
ax.spines.bottom.set_position('zero')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
tx = []
tl = []
if abs(xcur) < 23:
tx += [xcur]
tl += ["$x_n$"]
if abs(xnew) < 23:
tx += [xnew]
tl += ["$x_{n+1}$"]
ax.set_xticks(tx,tl)
ax.legend(facecolor='#C8E0FF',frameon=False)
rxcur.set(xnew)
return fig