Merge in dev to Master #1
7
README.md
Normal file
7
README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# BEER SG data storer
|
||||||
|
|
||||||
|
This container will store SG data for beer runs in Mongo and then use that data to calculate Alchohol Content of each beer
|
||||||
|
|
||||||
|
It's pretty loose and requires the Data Entry operator to know whats happening
|
||||||
|
|
||||||
|
Luck for me... That's me!
|
@ -1,4 +1,5 @@
|
|||||||
FROM git.aridgwayweb.com/armistace/beer_base_image AS flask
|
#FROM git.aridgwayweb.com/armistace/beer_base_image AS flask
|
||||||
|
FROM beer_base_image AS flask
|
||||||
|
|
||||||
COPY requirements.txt .
|
COPY requirements.txt .
|
||||||
|
|
||||||
@ -8,6 +9,6 @@ ENV FLASK_ENV production
|
|||||||
ENV FLASK_DEBUG 1
|
ENV FLASK_DEBUG 1
|
||||||
|
|
||||||
|
|
||||||
ENTRYPOINT ["flask", "--app", "/pool_data/src/flask/beer_data", "run", "--host=0.0.0.0"]
|
ENTRYPOINT ["flask", "--app", "/beer_data/src/flask/beer_data", "run", "--host=0.0.0.0"]
|
||||||
|
|
||||||
#ENTRYPOINT ["python", "/pool_data/src/flask/pool_data.py"]
|
#ENTRYPOINT ["python", "/pool_data/src/flask/pool_data.py"]
|
||||||
|
@ -7,3 +7,5 @@ Flask-WTF
|
|||||||
bootstrap-flask
|
bootstrap-flask
|
||||||
waitress
|
waitress
|
||||||
bokeh
|
bokeh
|
||||||
|
pandas
|
||||||
|
duckdb
|
@ -20,7 +20,7 @@ def main(username, password):
|
|||||||
"password" : f"{password}"
|
"password" : f"{password}"
|
||||||
}
|
}
|
||||||
if user_collection.user_exists(new_record["username"]):
|
if user_collection.user_exists(new_record["username"]):
|
||||||
user_collect.update_user(user_collection.existing_record["_id"], new_record["password"])
|
user_collection.update_user(user_collection.existing_record["_id"], new_record["password"])
|
||||||
else:
|
else:
|
||||||
user_collection.add_user(new_record["username"], new_record["password"])
|
user_collection.add_user(new_record["username"], new_record["password"])
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
from bokeh.core.enums import SpatialUnitsType
|
from bokeh.core.enums import SpatialUnitsType
|
||||||
import mongo.build_db as pool_database
|
import mongo.build_db as beer_database
|
||||||
import mongo.query_db as pool_database_query
|
import mongo.query_db as beer_database_query
|
||||||
|
from table import table_builder
|
||||||
|
|
||||||
from flask import Flask, render_template, request, jsonify, redirect, session
|
from flask import Flask, render_template, request, jsonify, redirect, session
|
||||||
from flask_wtf import FlaskForm, CSRFProtect
|
from flask_wtf import FlaskForm, CSRFProtect
|
||||||
from flask_bootstrap import Bootstrap5
|
from flask_bootstrap import Bootstrap5
|
||||||
from wtforms import StringField, SubmitField, DateField, IntegerField, PasswordField, DecimalField, RadioField, TextAreaField
|
from wtforms import StringField, SubmitField, DateField, IntegerField, PasswordField, DecimalField, RadioField, TextAreaField, BooleanField
|
||||||
from wtforms.validators import DataRequired, Length, Optional
|
from wtforms.validators import DataRequired, Length, Optional
|
||||||
from waitress import serve
|
from waitress import serve
|
||||||
from bokeh.models.layouts import HBox
|
from bokeh.models.layouts import HBox
|
||||||
@ -14,6 +15,7 @@ from charts import BeerCharts
|
|||||||
from bokeh.io import output_file, show
|
from bokeh.io import output_file, show
|
||||||
from bokeh.layouts import row
|
from bokeh.layouts import row
|
||||||
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = 'testsecret' #this value will change
|
app.secret_key = 'testsecret' #this value will change
|
||||||
|
|
||||||
@ -26,7 +28,7 @@ output_file("/beer_data/src/flask/static/data_plot.html")
|
|||||||
def create_graphs():
|
def create_graphs():
|
||||||
chart = BeerCharts.BeerCharts()
|
chart = BeerCharts.BeerCharts()
|
||||||
sg = chart.line_chart("SG", "sg", 30)
|
sg = chart.line_chart("SG", "sg", 30)
|
||||||
show(row(column(sg)))
|
show(column(sg))
|
||||||
|
|
||||||
|
|
||||||
class userForm(FlaskForm):
|
class userForm(FlaskForm):
|
||||||
@ -39,6 +41,7 @@ class dataForm(FlaskForm):
|
|||||||
beer_run_type = TextAreaField("Beer Type")
|
beer_run_type = TextAreaField("Beer Type")
|
||||||
Date = DateField("Date:")
|
Date = DateField("Date:")
|
||||||
sg = IntegerField("SG Reading")
|
sg = IntegerField("SG Reading")
|
||||||
|
final_run = BooleanField("Final Reading?")
|
||||||
comment = TextAreaField("Any Comments?", validators=[Optional()])
|
comment = TextAreaField("Any Comments?", validators=[Optional()])
|
||||||
submit = SubmitField("Write it, Write it REAAAAAAL GOOOD")
|
submit = SubmitField("Write it, Write it REAAAAAAL GOOOD")
|
||||||
|
|
||||||
@ -48,7 +51,7 @@ def index():
|
|||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
username = form.username.data
|
username = form.username.data
|
||||||
password = form.password.data
|
password = form.password.data
|
||||||
db = pool_database_query.pool_query()
|
db = beer_database_query.pool_query()
|
||||||
if db.user_check(username, password):
|
if db.user_check(username, password):
|
||||||
session['logged_in'] = True
|
session['logged_in'] = True
|
||||||
return redirect("/updater")
|
return redirect("/updater")
|
||||||
@ -61,18 +64,24 @@ def index():
|
|||||||
def updater():
|
def updater():
|
||||||
if 'logged_in' not in session:
|
if 'logged_in' not in session:
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
create_graphs()
|
predicted_alc_table = table_builder.TableBuilder().table_build()
|
||||||
query_db = pool_database_query.pool_query()
|
tr_replace_string = '<tr align="center" style="border-bottom:1pt solid black;">'
|
||||||
|
beer_html = predicted_alc_table.to_html(col_space='75px', index=False,
|
||||||
|
justify='center', border=3).replace('<tr>', tr_replace_string)
|
||||||
|
query_db = beer_database_query.pool_query()
|
||||||
query = query_db.get_top(10, "sg")
|
query = query_db.get_top(10, "sg")
|
||||||
form = dataForm()
|
form = dataForm()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
database = pool_database.pool_data()
|
database = beer_database.beer_data()
|
||||||
new_record = {
|
new_record = {
|
||||||
"date": f'{form.Date.data}',
|
"date": f'{form.Date.data}',
|
||||||
"beer_run_id": f'{form.beer_run_id.data}',
|
"beer_run_id": f'{form.beer_run_id.data}',
|
||||||
"beer_type": f'{form.beer_run_type.data}',
|
"beer_type": f'{form.beer_run_type.data}',
|
||||||
"sg" : f'{form.sg.data}',
|
"sg" : f'{form.sg.data}',
|
||||||
|
"final_reading" : F'{form.final_run.data}',
|
||||||
"comment": f'{form.comment.data}'
|
"comment": f'{form.comment.data}'
|
||||||
}
|
}
|
||||||
if database.record_exists(new_record["date"], new_record["beer_run_id"]):
|
if database.record_exists(new_record["date"], new_record["beer_run_id"]):
|
||||||
@ -82,34 +91,40 @@ def updater():
|
|||||||
if database.existing_record[field] != new_record[field]:
|
if database.existing_record[field] != new_record[field]:
|
||||||
database.update_re_record(database.existing_record["_id"], field, new_record[field])
|
database.update_re_record(database.existing_record["_id"], field, new_record[field])
|
||||||
else:
|
else:
|
||||||
database.create_re_record(new_record["beer_run_id"], new_record["beer_type"], new_record["sg"],
|
if new_record["final_reading"] == "True":
|
||||||
new_record["date"], new_record["comment"])
|
final_run_value = True
|
||||||
|
|
||||||
return render_template("updater.html", list=query, form=form, success=True, updater_name = new_record["test_user"])
|
|
||||||
else:
|
|
||||||
return render_template("updater.html", list=query, form=form, sucess=False)
|
|
||||||
|
|
||||||
@app.route("/update_db", methods=["POST"])
|
|
||||||
def pool_data_update():
|
|
||||||
database = pool_database.pool_data()
|
|
||||||
new_record = request.json
|
|
||||||
if database.record_exists(new_record["date"], new_record["test_user"]):
|
|
||||||
for field in database.existing_record:
|
|
||||||
for new_field in new_record:
|
|
||||||
if field == new_field:
|
|
||||||
if database.existing_record[field] != new_record[field]:
|
|
||||||
database.update_re_record(database.existing_record["_id"], field, new_record[field])
|
|
||||||
else:
|
else:
|
||||||
|
final_run_value = False
|
||||||
database.create_re_record(new_record["beer_run_id"], new_record["beer_type"], new_record["sg"],
|
database.create_re_record(new_record["beer_run_id"], new_record["beer_type"], new_record["sg"],
|
||||||
new_record["date"], new_record["comment"])
|
new_record["date"], final_run_value, new_record["comment"])
|
||||||
|
|
||||||
|
return render_template("updater.html", beer_data = beer_html
|
||||||
|
, list=query, form=form, success=True, updater_name = "Saucy Beer Maker")
|
||||||
|
else:
|
||||||
|
return render_template("updater.html", beer_data = beer_html
|
||||||
|
, list=query, form=form, sucess=False)
|
||||||
|
|
||||||
|
# @app.route("/update_db", methods=["POST"])
|
||||||
|
# def beer_data_update():
|
||||||
|
# database = beer_database.beer_data()
|
||||||
|
# new_record = request.json
|
||||||
|
# if database.record_exists(new_record["date"], new_record["test_user"]):
|
||||||
|
# for field in database.existing_record:
|
||||||
|
# for new_field in new_record:
|
||||||
|
# if field == new_field:
|
||||||
|
# if database.existing_record[field] != new_record[field]:
|
||||||
|
# database.update_re_record(database.existing_record["_id"], field, new_record[field])
|
||||||
|
# else:
|
||||||
|
# database.create_re_record(new_record["beer_run_id"], new_record["beer_type"], new_record["sg"],
|
||||||
|
# new_record["date"], new_record["comment"])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/pool_top/<int:return_number>/<string:field>")
|
# @app.route("/pool_top/<int:return_number>/<string:field>")
|
||||||
def user_detail(id):
|
# def user_detail(id):
|
||||||
query_db = pool_database_query.pool_query()
|
# query_db = beer_database_query.pool_query()
|
||||||
query = query_db.get_top(return_number, field)
|
# query = query_db.get_top(return_number, field)
|
||||||
return jsonify([row.to_json() for row in query])
|
# return jsonify([row.to_json() for row in query])
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
#app.run(host='0.0.0.0')
|
#app.run(host='0.0.0.0')
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Bokeh Plot</title>
|
|
||||||
<style>
|
|
||||||
html, body {
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flow-root;
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-3.5.0.min.js"></script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
Bokeh.set_log_level("info");
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="bb5c0e1d-dc95-4d96-9cbc-a29ed2eade5c" data-root-id="p1001" style="display: contents;"></div>
|
|
||||||
|
|
||||||
<script type="application/json" id="af8187ed-c6d3-40c3-84a3-bbe58799b466">
|
|
||||||
{"00bec54e-f52e-4b7f-b2b6-8e6e4eb73c82":{"version":"3.5.0","title":"Bokeh Application","roots":[{"type":"object","name":"Figure","id":"p1001","attributes":{"height":250,"x_range":{"type":"object","name":"FactorRange","id":"p1011","attributes":{"factors":["2024-03-27","2024-03-25","2024-03-15","2024-03-13"]}},"y_range":{"type":"object","name":"DataRange1d","id":"p1003","attributes":{"start":6}},"x_scale":{"type":"object","name":"CategoricalScale","id":"p1012"},"y_scale":{"type":"object","name":"LinearScale","id":"p1013"},"title":{"type":"object","name":"Title","id":"p1004","attributes":{"text":"Pool data"}},"renderers":[{"type":"object","name":"GlyphRenderer","id":"p1030","attributes":{"data_source":{"type":"object","name":"ColumnDataSource","id":"p1024","attributes":{"selected":{"type":"object","name":"Selection","id":"p1025","attributes":{"indices":[],"line_indices":[]}},"selection_policy":{"type":"object","name":"UnionRenderers","id":"p1026"},"data":{"type":"map","entries":[["x",["2024-03-27","2024-03-25","2024-03-15","2024-03-13"]],["y",[7.25,7.5,7.6,7.0]]]}}},"view":{"type":"object","name":"CDSView","id":"p1031","attributes":{"filter":{"type":"object","name":"AllIndices","id":"p1032"}}},"glyph":{"type":"object","name":"Line","id":"p1027","attributes":{"x":{"type":"field","field":"x"},"y":{"type":"field","field":"y"},"line_color":"#1f77b4"}},"nonselection_glyph":{"type":"object","name":"Line","id":"p1028","attributes":{"x":{"type":"field","field":"x"},"y":{"type":"field","field":"y"},"line_color":"#1f77b4","line_alpha":0.1}},"muted_glyph":{"type":"object","name":"Line","id":"p1029","attributes":{"x":{"type":"field","field":"x"},"y":{"type":"field","field":"y"},"line_color":"#1f77b4","line_alpha":0.2}}}}],"toolbar":{"type":"object","name":"Toolbar","id":"p1010"},"toolbar_location":null,"left":[{"type":"object","name":"LinearAxis","id":"p1019","attributes":{"ticker":{"type":"object","name":"BasicTicker","id":"p1020","attributes":{"mantissas":[1,2,5]}},"formatter":{"type":"object","name":"BasicTickFormatter","id":"p1021"},"major_label_policy":{"type":"object","name":"AllLabels","id":"p1022"}}}],"below":[{"type":"object","name":"CategoricalAxis","id":"p1014","attributes":{"ticker":{"type":"object","name":"CategoricalTicker","id":"p1015"},"formatter":{"type":"object","name":"CategoricalTickFormatter","id":"p1016"},"major_label_policy":{"type":"object","name":"AllLabels","id":"p1017"}}}],"center":[{"type":"object","name":"Grid","id":"p1018","attributes":{"axis":{"id":"p1014"},"grid_line_color":null}},{"type":"object","name":"Grid","id":"p1023","attributes":{"dimension":1,"axis":{"id":"p1019"}}}]}}]}}
|
|
||||||
</script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
(function() {
|
|
||||||
const fn = function() {
|
|
||||||
Bokeh.safely(function() {
|
|
||||||
(function(root) {
|
|
||||||
function embed_document(root) {
|
|
||||||
const docs_json = document.getElementById('af8187ed-c6d3-40c3-84a3-bbe58799b466').textContent;
|
|
||||||
const render_items = [{"docid":"00bec54e-f52e-4b7f-b2b6-8e6e4eb73c82","roots":{"p1001":"bb5c0e1d-dc95-4d96-9cbc-a29ed2eade5c"},"root_ids":["p1001"]}];
|
|
||||||
root.Bokeh.embed.embed_items(docs_json, render_items);
|
|
||||||
}
|
|
||||||
if (root.Bokeh !== undefined) {
|
|
||||||
embed_document(root);
|
|
||||||
} else {
|
|
||||||
let attempts = 0;
|
|
||||||
const timer = setInterval(function(root) {
|
|
||||||
if (root.Bokeh !== undefined) {
|
|
||||||
clearInterval(timer);
|
|
||||||
embed_document(root);
|
|
||||||
} else {
|
|
||||||
attempts++;
|
|
||||||
if (attempts > 100) {
|
|
||||||
clearInterval(timer);
|
|
||||||
console.log("Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 10, root)
|
|
||||||
}
|
|
||||||
})(window);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
if (document.readyState != "loading") fn();
|
|
||||||
else document.addEventListener("DOMContentLoaded", fn);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,17 +0,0 @@
|
|||||||
from bokeh.models.layouts import HBox
|
|
||||||
from bokeh.plotting import column
|
|
||||||
from charts import PoolCharts
|
|
||||||
from bokeh.io import output_file, show
|
|
||||||
from bokeh.layouts import row
|
|
||||||
|
|
||||||
output_file("static/data_plot.html")
|
|
||||||
|
|
||||||
chart = PoolCharts.PoolCharts()
|
|
||||||
|
|
||||||
ph = chart.line_chart("Pool PH", "ph", 50)
|
|
||||||
|
|
||||||
total_chlorine = chart.line_chart("Pool Total Chlorine", "total_chlorine", 50)
|
|
||||||
|
|
||||||
free_chlorine = chart.line_chart("Pool Free Chlorine", "free_chlorine", 50)
|
|
||||||
|
|
||||||
show(column(ph, total_chlorine, free_chlorine))
|
|
@ -9,9 +9,12 @@ class BeerCharts():
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.db = db_conn()
|
self.db = db_conn()
|
||||||
|
|
||||||
|
def bar_chart(self, items, data):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def line_chart(self, title, field, limit):
|
def line_chart(self, title, field, limit):
|
||||||
data = self.db.pool_db
|
data = self.db.beer_db
|
||||||
data = data.find({}).sort("date", -1).limit(limit)
|
data = data.find({}).sort("date", -1).limit(limit)
|
||||||
dates = []
|
dates = []
|
||||||
data_list = []
|
data_list = []
|
||||||
|
@ -15,14 +15,14 @@ class beer_data:
|
|||||||
#we can get self.db.real_db etc
|
#we can get self.db.real_db etc
|
||||||
self.db = db_conn()
|
self.db = db_conn()
|
||||||
|
|
||||||
def record_exists(self, date, test_user):
|
def record_exists(self, date, beer_run_id):
|
||||||
"""
|
"""
|
||||||
This function will accept an address
|
This function will accept an address
|
||||||
if it find that address in the database it will return True
|
if it find that address in the database it will return True
|
||||||
and set set the existing_record variable of the class to the
|
and set set the existing_record variable of the class to the
|
||||||
queried record
|
queried record
|
||||||
"""
|
"""
|
||||||
query = { "date" : f"{date}", "test_user": f"{test_user}"}
|
query = { "date" : f"{date}", "beer_run_id": f"{beer_run_id}"}
|
||||||
record = self.db.beer_db.find_one(query)
|
record = self.db.beer_db.find_one(query)
|
||||||
if record:
|
if record:
|
||||||
self.existing_record = record
|
self.existing_record = record
|
||||||
@ -31,7 +31,7 @@ class beer_data:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def create_re_record(self, beer_run_id, beer_type, sg, date, comment=""):
|
def create_re_record(self, beer_run_id, beer_type, sg, date, final_reading=False, comment=""):
|
||||||
"""
|
"""
|
||||||
create_re_record creates a whole new record
|
create_re_record creates a whole new record
|
||||||
takes the required 7 inputs
|
takes the required 7 inputs
|
||||||
@ -51,6 +51,7 @@ class beer_data:
|
|||||||
"beer_type": f"{beer_type}",
|
"beer_type": f"{beer_type}",
|
||||||
"sg": f"{sg}",
|
"sg": f"{sg}",
|
||||||
"date": f"{date}",
|
"date": f"{date}",
|
||||||
|
"final_reading": f"{final_reading}",
|
||||||
"comment": f"{comment}"
|
"comment": f"{comment}"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ class db_conn:
|
|||||||
self.db_host = os.getenv('MONGO_HOST')
|
self.db_host = os.getenv('MONGO_HOST')
|
||||||
self.client = self.get_client()
|
self.client = self.get_client()
|
||||||
self.db = self.client['beer_db']
|
self.db = self.client['beer_db']
|
||||||
self.pool_db = self.db['beer_data']
|
self.beer_db = self.db['beer_data']
|
||||||
self.users = self.db['users']
|
self.users = self.db['users']
|
||||||
self.inspections = self.db['inspections_db']
|
self.inspections = self.db['inspections_db']
|
||||||
|
|
||||||
|
0
src/flask/table/__init__.py
Normal file
0
src/flask/table/__init__.py
Normal file
54
src/flask/table/table_builder.py
Normal file
54
src/flask/table/table_builder.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from mongo.get_conn import db_conn
|
||||||
|
import pandas as pd
|
||||||
|
import duckdb
|
||||||
|
|
||||||
|
class TableBuilder():
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.db = db_conn()
|
||||||
|
|
||||||
|
def table_build(self, limit=10) -> pd.DataFrame:
|
||||||
|
data = self.db.beer_db
|
||||||
|
data = data.find({}).sort("date", -1)
|
||||||
|
df_dict = {}
|
||||||
|
df_dict["beer_run_id"]=[]
|
||||||
|
df_dict["sg"] = []
|
||||||
|
df_dict["date"] = []
|
||||||
|
df_dict["final_reading"] = []
|
||||||
|
|
||||||
|
for record in data:
|
||||||
|
df_dict["beer_run_id"].append(record["beer_run_id"])
|
||||||
|
df_dict["sg"].append(record["sg"])
|
||||||
|
df_dict["date"].append(record["date"])
|
||||||
|
df_dict["final_reading"].append(record["final_reading"])
|
||||||
|
df = pd.DataFrame(data=df_dict)
|
||||||
|
sql = f"""
|
||||||
|
SELECT x.beer_run_id as beer_run_id,
|
||||||
|
max(sg) as max,
|
||||||
|
min(sg) as min,
|
||||||
|
y.date as final_reading_date
|
||||||
|
FROM df x
|
||||||
|
JOIN
|
||||||
|
( SELECT DISTINCT beer_run_id, date
|
||||||
|
FROM df
|
||||||
|
WHERE final_reading = 'True'
|
||||||
|
) y ON x.beer_run_id = y.beer_run_id
|
||||||
|
GROUP BY x.beer_run_id, y.date
|
||||||
|
ORDER BY x.beer_run_id desc
|
||||||
|
LIMIT {limit}
|
||||||
|
"""
|
||||||
|
df_sum = duckdb.sql(sql).df()
|
||||||
|
sql = f"""
|
||||||
|
SELECT x.beer_run_id as "Beer Run",
|
||||||
|
x.max as "Max",
|
||||||
|
x.min as "Min",
|
||||||
|
ROUND(((CAST (max AS INTEGER) - CAST(min AS INTEGER)) / 7.36) + 0.5, 2) AS "Alcohol Prediction",
|
||||||
|
cast(final_reading_date as DATE) + INTERVAL 14 DAY as "Ready Date"
|
||||||
|
|
||||||
|
FROM df_sum x
|
||||||
|
"""
|
||||||
|
df_calc = duckdb.sql(sql).df()
|
||||||
|
return df_calc
|
||||||
|
|
||||||
|
|
@ -46,17 +46,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td> -->
|
</td> -->
|
||||||
<td>
|
<!--<iframe style="width: 100vw; height: 40vh;" src="static/data_plot.html" frameborder="0" allowfullscreen>
|
||||||
<div class="container">
|
<!--<iframe style="width: 100vw;height: 80vh;position: relative;" src="static/data_plot.html" frameborder="0" allowfullscreen>-->
|
||||||
<div class= "col-xs-12 col-sm-12 col-md-12">
|
|
||||||
<iframe style="width: 100vw;height: 80vh;position: relative;" src="static/data_plot.html" frameborder="0" allowfullscreen>
|
|
||||||
</iframe>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{{ beer_data | safe }}
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
5
src/flask/test.py
Normal file
5
src/flask/test.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import table.table_builder as table_builder
|
||||||
|
|
||||||
|
test = table_builder.TableBuilder()
|
||||||
|
|
||||||
|
print(test.table_build())
|
Loading…
x
Reference in New Issue
Block a user