Plots for bigOĀ¶
import math
import polars as pl
import seaborn as sns
from matplotlib.axes import Axes
def f(x: float) -> float:
return 4.5 * (x ** 3) - 100 * (x ** 2) + (50000 * x) + 10000000
def g(x: float) -> float:
return 5 * x ** 3
There has to be a better way than storing all of these points in a data frame, but I can't seem to easily find that, so
r_start = 0
r_stop = 1500
r_step = 1
f_stop = r_stop * round(1 / r_step)
p_range = [x * r_step for x in range(r_start, f_stop)]
x_series = pl.Series("x", [x for x in p_range], dtype=pl.Float32)
df = pl.DataFrame(
{
"x": x_series,
"f(x)": [f(x) for x in x_series],
"g(x)": [g(x) for x in x_series],
}
)
df_long = df.unpivot(index=['x'], on=['f(x)', 'g(x)'], variable_name="function", value_name="y")
sns.set_theme(context='notebook', palette='colorblind')
Where does f(x) get bigger than g(x)?Ā¶
With
\begin{equation*} f(x) = 4.5x^3 - 100x^2 + 50000x + 10000000 \end{equation*}
and
\begin{equation*} g(x) = 5x^3 \end{equation*}
The intersection should be at the real roots of
\begin{equation*} f(x) - g(x) = -0.5x^3 - 100x^2 + 50000x + 10000000 \end{equation*}
My previous notes tell me that that the one real root of that, which I am going to call ā$\hat{x}$ā is at
\begin{align*} \hat{x} &= 100 \sqrt{10} \\ &\approx 316.2 \end{align*}
x_intersect = 100 * math.sqrt(10)
intersect = (x_intersect, f(x_intersect))
print(intersect)
(316.22776601683796, 158113883.008419)
The plotsĀ¶
This is me using seaborn for the first time. A difficulty that I found is that a huge number of methods for the objects created are not documented within seaborn itself, but a part of matplotlib. I get that seaborn classes inherit (or seem to inherit) from matplotlib, but before I realized this I did not have fun with the documentation.
first a utility to write a plot to a file.
def save_axes(ax: Axes, fname: str, **kwargs):
fig = ax.get_figure(root = True)
if fig is None:
raise Exception("Couldn't get figure")
fig.tight_layout()
fig.savefig(fname, **kwargs)
First we plot $f(x)$ only,
xlim = (0, 360)
ylim = (0, 250_000_000)
p = sns.lineplot(data=df_long.filter(pl.col("function") == "f(x)"), x="x", y="y", hue="function")
p.set_yticks(
[
t
for t in range(
50_000_000,
int(df_long["y"].max()), # type: ignore
50_000_000,
)
]
)
p.set_xlim(xlim)
p.set_ylim(ylim)
ylabels = [f"{t // 1_000_000} million" for t in p.get_yticks()]
p.set_yticklabels(ylabels)
save_axes(p, "f-only-plot.pdf")
p
<Axes: xlabel='x', ylabel='y'>
Now we plot $f(x)$, $g(x)$, and $\hat{x}$.
xlim = (0, 360)
ylim = (0, 250_000_000)
p = sns.lineplot(data=df_long, x="x", y="y", hue="function")
p.set_yticks(
[
t
for t in range(
50_000_000,
int(df_long["y"].max()), # type: ignore
50_000_000,
)
]
)
p.set_xlim(xlim)
p.set_ylim(ylim)
ylabels = [f"{t // 1_000_000} million" for t in p.get_yticks()]
p.set_yticklabels(ylabels)
p.axvline(x=intersect[0], ymin=0, ymax=intersect[1]/ylim[1], ls=":")
save_axes(p, "both-plot.pdf")
p
<Axes: xlabel='x', ylabel='y'>
Now we plot for small $x$.
xlim = (0, 100)
ylim = (0, 20_000_000)
p = sns.lineplot(data=df_long, x="x", y="y", hue="function")
p.set_yticks(
[
t
for t in range(
5_000_000,
int(df_long["y"].max()), # type: ignore
5_000_000,
)
]
)
p.set_xlim(xlim)
p.set_ylim(ylim)
ylabels = [f"{t // 1_000_000} million" for t in p.get_yticks()]
p.set_yticklabels(ylabels)
save_axes(p, "small-x-plot.pdf")
p
<Axes: xlabel='x', ylabel='y'>
ymax = df_long['y'].max()
assert isinstance(ymax, float)
xmax = df_long['x'].max()
assert isinstance(xmax, float)
xlim = (0, xmax)
ylim = (-500_000_000, ymax)
p = sns.lineplot(data=df_long, x="x", y="y", hue="function")
p.set_yticks(
[
t
for t in range(
5_000_000_000,
int(df_long["y"].max()), # type: ignore
5_000_000_000,
)
]
)
p.set_xlim(xlim)
p.set_ylim(ylim)
ylabels = [f"{t // 1_000_000_000} billion" for t in p.get_yticks()]
p.set_yticklabels(ylabels)
# I do not know why I need to multiply by 4 below.
# If I don't, the axvline is too short.
p.axvline(x_intersect, ymin=0, ymax= 4 * intersect[1] / ylim[1], ls=":")
save_axes(p, "whole-x-plot.pdf")
p
<Axes: xlabel='x', ylabel='y'>