From ffc269114a8c460f9289a58e73e9bb5fe3d78951 Mon Sep 17 00:00:00 2001 From: Priyansh Date: Fri, 17 Dec 2021 01:39:25 -0500 Subject: Plotly Integration in JS and Predict using building models --- app.py | 10 +++- predictor.py | 62 ++++++++++++++++++++---- static/js/prediction.js | 125 ++++++++++++++++++++++++++++++++++++++++++++++++ static/js/search.js | 13 ++++- templates/index.html | 59 ++++++++++------------- 5 files changed, 223 insertions(+), 46 deletions(-) create mode 100644 static/js/prediction.js diff --git a/app.py b/app.py index f17fd5c..3e5115e 100644 --- a/app.py +++ b/app.py @@ -1,8 +1,11 @@ from flask import Flask, render_template -from flask import request +from flask import request, jsonify import pandas as pd import json +from libs.decompressor import decompress_arima +from predictor import render_plot +decompress_arima() app = Flask(__name__) @app.route("/") @@ -17,11 +20,14 @@ def index(): def receive_dates(): start_date = request.form["start_date"] end_date = request.form["end_date"] + city_id = request.form["city_id"] dates_unmf = pd.date_range(start_date, end_date, freq='d') dates = [] for i in dates_unmf: dates.append(i.strftime('%Y-%m-%d')) - return 'OK' + plot_data = render_plot(dates, city_id) + return jsonify(plot_data) + if __name__ == '__main__': app.run(debug=True) diff --git a/predictor.py b/predictor.py index 18a1708..ecf2519 100644 --- a/predictor.py +++ b/predictor.py @@ -1,17 +1,38 @@ import pandas as pd +import matplotlib +import numpy as np +from functions.sql_functions import execute_sql_statement +import pmdarima as pm +import io +import base64 +matplotlib.use('Agg') import matplotlib.pyplot as plt -import pickle -from libs.decompressor import decompress_arima -decompress_arima() -with open('arima.pkl', 'rb') as pkl: - n_periods = 30 - fc, confint = pickle.load(pkl).predict( +def render_plot(dates, city_id): + sql_stmt = "select date, city_id, cast(avg_temperature as real) as temp from temperature where date is not null and temp is not null and city_id = " + str(city_id) + result = execute_sql_statement(sql_stmt) + data = pd.DataFrame(result, columns=["date", "city_id", "temp"]) + data.set_index(["date", "city_id"], inplace=True) + ts_model = pm.auto_arima(data.temp, start_p=1, start_q=1, + test='adf', + max_p=3, max_q=3, + m=5, + d=None, + seasonal=False, + start_P=0, + D=0, + trace=True, + error_action='ignore', + suppress_warnings=True, + stepwise=True) + + n_periods = len(dates) + n_years = dates + city_ids = np.repeat(city_id, n_periods) + fc, confint = ts_model.predict( n_periods=n_periods, return_conf_int=True) - n_years = ['1960-12-02', '1960-12-03', '1960-12-04', '1960-12-05', '1960-12-06', '1960-12-07', '1960-12-08', '1960-12-09', '1960-12-10', '1960-12-11', '1960-12-12', '1960-12-13', '1960-12-14', '1960-12-15', '1960-12-16', - '1960-12-17', '1960-12-18', '1960-12-19', '1960-12-20', '1960-12-21', '1960-12-22', '1960-12-23', '1960-12-24', '1960-12-25', '1960-12-26', '1960-12-27', '1960-12-28', '1960-12-29', '1960-12-30', '1960-12-31'] - city_ids = ["1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031", "1031"] + fc_ind = pd.Series(n_years, city_ids) fc_series = pd.Series(fc, index=fc_ind) @@ -23,4 +44,25 @@ with open('arima.pkl', 'rb') as pkl: lower_series, upper_series, color="k", alpha=.35) - plt.show() + plt.title("Temperature Forecast") + plt.xlabel("Date") + plt.ylabel("Temperature (°C)") + plt.xticks(rotation=45) + plt.tight_layout() + ax = plt.gca() + line = ax.lines[0] + x_data = line.get_xdata().tolist() + y_data = line.get_ydata().tolist() + upper_bound = upper_series.tolist() + lower_bound = lower_series.tolist() + + # Convert x_data, y_data, upper_bound, lower_bound to dict + data = { + "x_data": x_data, + "y_data": y_data, + "upper_bound": upper_bound, + "lower_bound": lower_bound + } + + return data + diff --git a/static/js/prediction.js b/static/js/prediction.js new file mode 100644 index 0000000..499cba9 --- /dev/null +++ b/static/js/prediction.js @@ -0,0 +1,125 @@ +var displayDataButton = document.getElementById('displayData'); + +var today = new Date(); +var dd = today.getDate(); +var mm = today.getMonth() + 1; //January is 0! +var yyyy = today.getFullYear(); + +if (dd < 10) { + dd = '0' + dd; +} + +if (mm < 10) { + mm = '0' + mm; +} + +var startDate = yyyy + '-' + mm + '-' + dd; + +// get date 7 days from today +var date = new Date(); +date.setDate(date.getDate() + 7); +var dd = date.getDate(); +var mm = date.getMonth() + 1; //January is 0! +var yyyy = date.getFullYear(); + +if (dd < 10) { + dd = '0' + dd; +} + +if (mm < 10) { + mm = '0' + mm; +} + +var endDate = yyyy + '-' + mm + '-' + dd; + +predictData(startDate, endDate, 1018, 'Buffalo'); + +displayDataButton.addEventListener('click', e => { + e.preventDefault(); + var cityId = document.getElementById('citySearch').getAttribute('data-city-id'); + var cityName = document.getElementById('citySearch').value; + predictData(startDate, endDate, cityId, cityName); +}) + +function predictData(startDate, endDate, cityId, cityName) { + var startDateValue = startDate; + var endDateValue = endDate; + if (startDateValue == '' || endDateValue == '') { + alert('Please enter a start and end date'); + } else if (endDateValue < startDateValue) { + alert('Please enter a valid date range'); + } else { + displayDataButton.classList.add('hidden'); + document.getElementById("processingButton").classList.remove('hidden'); + document.getElementById('predictionImage').innerHTML = ""; + $.post("/receiveDates", { + start_date: startDateValue, + end_date: endDateValue, + city_id: cityId + }, data => { + console.log(data); + var x = data.x_data; + + var y = data.y_data.map(function (item) { + return Math.round(item * 100) / 100; + }); + + + var upperBound = data.upper_bound.map(function (item) { + return Math.round(item * 100) / 100; + }); + var lowerBound = data.lower_bound.map(function (item) { + return Math.round(item * 100) / 100; + }); + + var trace1 = { + x: x, + y: lowerBound, + line: { width: 1 }, + mode: "lines", + name: "Lower Bound", + type: "scatter", + line: { color: "rgb(0,100,80)" } + }; + + var trace2 = { + x: x, + y: y, + type: "scatter", + fillcolor: "rgba(231,107,243,0.0)", + mode: "lines", + fill: "tozerox", + line: { color: "rgb(31, 119, 180)" }, + name: "Prediction" + }; + + var trace3 = { + x: x, + y: upperBound, + line: { width: 1 }, + mode: "lines", + name: "Upper Bound", + type: "scatter", + line: { color: "rgb(0,176,246)" } + }; + + var data = [trace1, trace2, trace3]; + var layout = { + showlegend: true, + xaxis: { + type: 'date', + title: 'Date' + }, + yaxis: { + title: 'Daily Mean Temperature (˚C)' + }, + title: '7 Day Weather Forecast for ' + cityName + }; + + Plotly.newPlot('predictionImage', data, layout); + + document.getElementById("processingButton").classList.add('hidden'); + displayDataButton.classList.remove('hidden'); + }); + } +} \ No newline at end of file diff --git a/static/js/search.js b/static/js/search.js index 05ddb8c..c96e003 100644 --- a/static/js/search.js +++ b/static/js/search.js @@ -8,7 +8,15 @@ citySearch.addEventListener('keyup', (e) => { if (results.length > 0) { const resultContainer = document.getElementById('result_container'); resultContainer.classList.remove('hidden'); - document.getElementById('results').innerHTML = ""; + try { + document.getElementById('results').innerHTML = ""; + } catch (e) { + // Create the results container + const results = document.createElement('ul'); + results.id = 'results'; + results.classList.add('list-reset', 'h-full', 'block'); + resultContainer.appendChild(results); + } for (var result of results) { const listElement = document.createElement('li'); listElement.classList.add('flex', 'items-center', 'space-x-2', 'py-2', 'px-4', 'relative', 'w-full', 'hover:bg-blue-600', 'hover:text-white', 'cursor-pointer'); @@ -17,8 +25,11 @@ citySearch.addEventListener('keyup', (e) => { listElement.setAttribute('cityId', result.item.cityId); listElement.innerHTML = `${result.item.city}`; listElement.addEventListener('click', (e) => { + citySearch.removeAttribute('data-city-id'); citySearch.value = e.target.innerText; + citySearch.setAttribute('data-city-id', e.target.getAttribute('cityId')); resultContainer.classList.add('hidden'); + resultContainer.innerHTML = ""; city = { city: e.target.innerText, latitude: e.target.getAttribute('latitude'), diff --git a/templates/index.html b/templates/index.html index ac2d321..789babf 100644 --- a/templates/index.html +++ b/templates/index.html @@ -38,14 +38,14 @@ -

Start Date:

-

End Date:

+ + +

@@ -53,7 +53,7 @@
-
+
+
+ +
+
+ - - + \ No newline at end of file -- cgit v1.2.3