diff options
author | mounderfod <mounderfod@gmail.com> | 2023-07-20 17:11:14 +0200 |
---|---|---|
committer | mounderfod <mounderfod@gmail.com> | 2023-07-20 17:11:14 +0200 |
commit | 44d18b0ddd81736f938ac75a96ae519195c01c20 (patch) | |
tree | cca1ab702986f465576f4fa31d0b0b7e404aabf0 | |
download | pyMathEngine-44d18b0ddd81736f938ac75a96ae519195c01c20.tar.gz |
Initial commit
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | .idea/.gitignore | 8 | ||||
-rw-r--r-- | .idea/flaskProject.iml | 21 | ||||
-rw-r--r-- | .idea/inspectionProfiles/Project_Default.xml | 12 | ||||
-rw-r--r-- | .idea/inspectionProfiles/profiles_settings.xml | 6 | ||||
-rw-r--r-- | .idea/misc.xml | 4 | ||||
-rw-r--r-- | .idea/modules.xml | 8 | ||||
-rw-r--r-- | Discovery.md | 12 | ||||
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | Spacefile | 12 | ||||
-rw-r--r-- | app.py | 46 | ||||
-rw-r--r-- | icon.png | bin | 0 -> 33676 bytes | |||
-rw-r--r-- | requirements.txt | 3 | ||||
-rw-r--r-- | templates/index.html | 146 |
14 files changed, 287 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..97861c9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.space \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/flaskProject.iml b/.idea/flaskProject.iml new file mode 100644 index 0000000..688ba73 --- /dev/null +++ b/.idea/flaskProject.iml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="PYTHON_MODULE" version="4"> + <component name="Flask"> + <option name="enabled" value="true" /> + </component> + <component name="NewModuleRootManager"> + <content url="file://$MODULE_DIR$"> + <excludeFolder url="file://$MODULE_DIR$/venv" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> + <component name="TemplatesService"> + <option name="TEMPLATE_CONFIGURATION" value="Jinja2" /> + <option name="TEMPLATE_FOLDERS"> + <list> + <option value="$MODULE_DIR$/../flaskProject\templates" /> + </list> + </option> + </component> +</module> \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..d4a00d6 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,12 @@ +<component name="InspectionProjectProfileManager"> + <profile version="1.0"> + <option name="myName" value="Project Default" /> + <inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true"> + <option name="ignoredErrors"> + <list> + <option value="E302" /> + </list> + </option> + </inspection_tool> + </profile> +</component> \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ +<component name="InspectionProjectProfileManager"> + <settings> + <option name="USE_PROJECT_PROFILE" value="false" /> + <version value="1.0" /> + </settings> +</component> \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..7e09807 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11 (flaskProject)" project-jdk-type="Python SDK" /> +</project> \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..2c2d842 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/.idea/flaskProject.iml" filepath="$PROJECT_DIR$/.idea/flaskProject.iml" /> + </modules> + </component> +</project> \ No newline at end of file diff --git a/Discovery.md b/Discovery.md new file mode 100644 index 0000000..7d3c460 --- /dev/null +++ b/Discovery.md @@ -0,0 +1,12 @@ +--- +app_name: "pyMathEngine" +title: "pyMathEngine" +tagline: "A mathematical engine in the style of Wolfram Alpha" +git: <https://github.com/mounderfod/pyMathEngine> +--- + +A mathematical engine in the style of Wolfram Alpha. +Very useful for homework, assignments, etc. +Currently, the engine can only take univariate expressions, but additional features are being added over time. + +[(view screenshot)](https://cdn.discordapp.com/attachments/838048982873538572/1131593838285295637/image.png) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e699297 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# pyMathEngine +[<img width="200" src="https://deta.space/buttons/dark.svg">](https://deta.space/discovery/@mounderfod/pymathengine) + +A mathematical engine in the style of Wolfram Alpha. +Very useful for homework, assignments, etc. +Currently, the engine can only take univariate expressions, but additional features are being added over time. + +![(A screenshot of the app)](https://cdn.discordapp.com/attachments/838048982873538572/1131593838285295637/image.png) \ No newline at end of file diff --git a/Spacefile b/Spacefile new file mode 100644 index 0000000..9b8a42e --- /dev/null +++ b/Spacefile @@ -0,0 +1,12 @@ +# Spacefile Docs: https://go.deta.dev/docs/spacefile/v0 +v: 0 + +micros: + - name: python-app + src: . + engine: python3.9 + primary: true + run: flask run + public: true + +icon: ./icon.png diff --git a/app.py b/app.py new file mode 100644 index 0000000..51b158b --- /dev/null +++ b/app.py @@ -0,0 +1,46 @@ +import base64 +import os + +from sympy import diff, integrate, print_latex, latex, pretty, solve, Eq +from sympy.parsing.sympy_parser import * +from sympy.plotting import plot +from io import BytesIO + +from flask import Flask, request, render_template + +app = Flask(__name__) + + +@app.route('/') +def hello_world(): # put application's code here + return render_template("index.html", HOSTNAME=os.getenv("DETA_SPACE_APP_HOSTNAME")) + +@app.route('/api/univariate') +def plotter(): + args = request.args + + try: + exp = parse_expr(args['func'], transformations=standard_transformations + (split_symbols, implicit_multiplication, function_exponentiation, convert_xor)) + + buf = BytesIO() + + p = plot(exp, show=False) + p._backend = p.backend(p) + p._backend.process_series() + p._backend.fig.savefig(buf, format="png") + + data = base64.b64encode(buf.getbuffer()).decode("ascii") + return { + "variable": pretty(exp.atoms(Symbol).pop()), + "expression": latex(exp), + "plot": data, + "diff": latex(diff(exp)), + "integral": latex(integrate(exp)), + "solution": [latex(i) for i in solve(Eq(exp, 0))] + } + except Exception as e: + print(e) + return f"Bad Request", 400 + +if __name__ == '__main__': + app.run() diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..54ac929 --- /dev/null +++ b/icon.png Binary files differdiff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..7b99323 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +sympy~=1.12 +Flask~=2.3.2 +matplotlib~=3.7.2 \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..e87e7e4 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,146 @@ +<!DOCTYPE html> +<html> + <head> + <title>pyMathEngine</title> + <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> + <script + id="MathJax-script" + async + src="https://cdn.jsdelivr.net/npm/mathjax@3.0.1/es5/tex-mml-chtml.js" + ></script> + <link + href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" + rel="stylesheet" + integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" + crossorigin="anonymous" + /> + <script + src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" + integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" + crossorigin="anonymous" + ></script> + <link + rel="icon" + type="image/png" + href="https://cdn.discordapp.com/attachments/838048982873538572/1131593508759814287/favicon.png" + /> + </head> + <body> + <div class="m-3"> + <div class="alert alert-info mb-2" role="alert"> + Welcome to <b>pyMathEngine</b>, a mathematical engine in the style of + Wolfram Alpha. <br /> + Currently the engine can only take univariate expressions (e.g. \( + x^2+2x+3 \)), but additional features are being added over time.<br /> + Some notes: + <ul> + <li>Euler's number (\(e\)) is written as "E" in the box</li> + <li>Pi (\(\pi\)) is written as "pi" in the box</li> + </ul> + </div> + <div class="input-group mb-3"> + <input + id="expression" + type="text" + class="form-control" + placeholder="Enter a univariate expression..." + aria-label="Enter a univariate expression..." + aria-describedby="button-addon" + /> + <button + class="btn btn-secondary" + type="button" + onclick="get()" + id="button-addon" + > + Search + </button> + </div> + </div> + <div id="response" class="m-5"></div> + </body> + <script> + function get() { + let exp = document.getElementById("expression").value; + fetch( + `https://${"{{ HOSTNAME }}"}/api/univariate?func=${encodeURIComponent( + exp + )}` + ) + .then((response) => { + if (!response.ok) { + // create error object and reject if not a 2xx response code + let err = new Error("HTTP status code: " + response.status); + err.response = response; + err.status = response.status; + throw err; + } else { + response.json().then((data) => { + console.log(data); + let responseBox = document.getElementById("response"); + responseBox.innerHTML = ""; + responseBox.innerHTML += ` + <div class="card mt-2"> + <div class="card-header">Input</div> + <div class="card-body"> + <p>$$ f(${data.variable}) = ${data.expression} $$</p> + </div> + </div> + + <div class="card mt-2"> + <div class="card-header">Solutions (where \\(f(${data.variable}) = 0\\))</div> + <div class="card-body overflow-auto"><p> + $$ ${data.solution} $$ + </p></div> + </div> + + <div class="card mt-2"> + <div class="card-header">Plot</div> + <div class="card-body text-center"> + <img src="data:image/png;base64,${data.plot}" /> + </div> + </div> + + <div class="card mt-2"> + <div class="card-header">Differential</div> + <div class="card-body"> + <p>$$ \\frac{\\mathrm{d} f(${data.variable}) }{\\mathrm{d} ${data.variable}} = ${data.diff} $$</p> + </div> + </div> + + <div class="card mt-2"> + <div class="card-header">Integral</div> + <div class="card-body"> + <p>$$ \\int f(${data.variable})\\, \\mathrm{d}${data.variable} = ${data.integral} + c$$</p> + </div> + </div> + + `; + MathJax.typeset(); + }); + } + }) + .catch((err) => { + let responseBox = document.getElementById("response"); + + responseBox.innerHTML = ""; + responseBox.innerHTML += ` + <div class="card mt-2"> + <div class="card-header bg-danger text-white">Error</div> + <div class="card-body"> + <p>${err.message}</p> + <p>This is likely because you have entered an invalid expression.</p> + </div> + </div> + `; + }); + } + </script> + <script type="text/x-mathjax-config"> + MathJax.Hub.Config({ + "CommonHTML": { linebreaks: { automatic: true, width: "container" } }, + "HTML-CSS": { linebreaks: { automatic: true, width: "container" } }, + "SVG": { linebreaks: { automatic: true, width: "container" } } + }); + </script> +</html> |