Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interactive lorenz #3151

Merged
merged 7 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion examples/browser/lorenz.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@
<script src="../../lib/browser/math.js"></script>

<script src="https://cdn.plot.ly/plotly-2.25.2.min.js" charset="utf-8"></script>
<style>
html, body {
width: 100%;
height: 100vh;
padding: 0;
margin: 0;
}
body {
display: flex;
flex-direction: column;
}

#LorenzGraph {
flex: 1;
}
</style>
</head>

<body>
Expand Down Expand Up @@ -36,7 +52,11 @@
type: "scatter3d",
mode: "lines"
}],
{ width: 800, height: 600 }
{
responsive: true,
uirevision: 'true',
title:"Lorenz Attractor",
}
)

// define the lorenz attractor
Expand Down
192 changes: 192 additions & 0 deletions examples/browser/lorenz_interactive.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>math.js | Lorenz Attractor</title>
<script src="../../lib/browser/math.js"></script>

<script src="https://cdn.plot.ly/plotly-2.28.0.min.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.js"
integrity="sha512-LQNxIMR5rXv7o+b1l8+N1EZMfhG7iFZ9HhnbJkTp4zjNr5Wvst75AqUeFDxeRUa7l5vEDyUiAip//r+EFLLCyA=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css"
integrity="sha512-fHwaWebuwA7NSF5Qg/af4UeDx9XqUpYpOGgubo3yWu+b2IQR4UeQwbb42Ti7gVAjNtVoI/I9TEoYeu9omwcC6g=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<style>
body,
html {
width: 100%;
height: 100vh;
padding: 0;
margin: 0;
}

body {
display: flex;
flex-direction: column;
}

#LorenzGraph {
flex: 1;
}

#inputsDiv {
z-index: 1;
position: absolute;
}
</style>
</head>

<body>
<div id="LorenzGraph"></div>
<div id="inputsDiv">
<fieldset name="inputs" id="inputs">
<legend for="inputs">Inputs:</legend>
<table>
<tr>
<td>
<label for="sigma" id="sigmaLabel">sigma</label>
</td>
<td>
<input type="range" id="sigma" name="sigma" value=10 min=9 max=11 step=0.01>
</td>
<td>
<label for="beta" id="betaLabel">beta</label>
</td>
<td>
<input type="range" id="beta" name="beta" value=8/3 min=2 max=4 step=0.01>
</td>
<td>
<label for="rho" id="rhoLabel">rho</label>
</td>
<td>
<input type="range" id="rho" name="rho" value=28 min=20 max=30 step=0.01>
</td>
</tr>
<tr>
<td>
<label for="x0" id="x0Label">x0</label>
</td>
<td>
<input type="range" id="x0" name="x0" value=1 min=-5 max=5 step=0.01>
</td>
<td>
<label for="y0" id="y0Label">y0</label>
</td>
<td>
<input type="range" id="y0" name="y0" value=1 min=-5 max=5 step=0.01>

</td>
<td>
<label for="z0" id="z0Label">z0</label>
</td>
<td>
<input type="range" id="z0" name="z0" value=0 min=-5 max=5 step=0.01>
</td>
</tr>
<tr>
<td>
<label for="epsilon" id="epsilonLabel">epsilon</label>
</td>
<td>
<input type="range" id="epsilon" name="epsilon" value=0.01 min=0.0001 max=0.1 step=0.0001>
</td>
</tr>
</table>
</fieldset>
</div>
</body>
<script defer>
katex.render(String.raw`\sigma`, document.querySelector("#sigmaLabel"))
katex.render(String.raw`\beta`, document.querySelector("#betaLabel"))
katex.render(String.raw`\rho`, document.querySelector("#rhoLabel"))
katex.render(String.raw`x_0`, document.querySelector("#x0Label"))
katex.render(String.raw`y_0`, document.querySelector("#y0Label"))
katex.render(String.raw`z_0`, document.querySelector("#z0Label"))
katex.render(String.raw`\epsilon`, document.querySelector("#epsilonLabel"))

const inputs = document.querySelector("#inputs")

// define the constants for the Lorenz attractor
const sigma = document.querySelector("#sigma")
const beta = document.querySelector("#beta")
const rho = document.querySelector("#rho")

// define the initial location
const x0 = document.querySelector('#x0')
const y0 = document.querySelector('#y0')
const z0 = document.querySelector('#z0')

// define the tolerance for the solution
const epsilon = document.querySelector('#epsilon')

const layout = {
interactive: true,
title: 'Lorenz Attractor',
uirevision: 'true',
sliders: [{
name: 'sigma',
currentvalue: {
xanchor: 'right',
prefix: 'color: ',
font: {
color: '#888',
size: 20
}
},
steps: [{ label: 'g', method: "updateSolution" }, { label: 'f' }]
}]
}

const t_span = [0, 100]

inputs.addEventListener("change", updateSolution)

let trace
// solve the Lorenz attractor with the initial values
updateSolution()

// crates a trace in the format needed for plotly
function createTrace(sol) {
// make colors that represents time differences in the solution
const diff = math.diff(sol.t)
const color = [diff[0], ...diff]
const trace = [{
x: sol.y.map(u => u[0]),
y: sol.y.map(u => u[1]),
z: sol.y.map(u => u[2]),
line: {
color,
colorscale: 'Jet'
},
type: "scatter3d",
mode: "lines"
}]
return trace
}

function createLorenz(sigma, rho, beta) {
// define the lorenz attractor as a function of t and u in the format needed for solveODE
return function lorenz(t, u) {
const [x, y, z] = u
// return x', y', z'
return [
sigma * (y - x),
x * (rho - z) - y,
x * y - beta * z
]
}
}

function updateSolution() {
const y_0 = [x0.value, y0.value, z0.value]
const sol = math.solveODE(createLorenz(sigma.value, rho.value, beta.value), t_span, y_0, { tol: epsilon.value })
trace = createTrace(sol)
// reactively render the plot on update
Plotly.react('LorenzGraph', trace, layout)
}

</script>

</html>