diff options
| author | Priyansh <[email protected]> | 2021-12-17 01:39:25 -0500 |
|---|---|---|
| committer | Priyansh <[email protected]> | 2021-12-17 01:39:25 -0500 |
| commit | ffc269114a8c460f9289a58e73e9bb5fe3d78951 (patch) | |
| tree | f4cec963248ff0abfffe8549b353fb2f0887f309 | |
| parent | e4969ef5b151b6d48c54f0cbc3fe05cc261c147e (diff) | |
| download | temp_pred_arima-ffc269114a8c460f9289a58e73e9bb5fe3d78951.tar.xz temp_pred_arima-ffc269114a8c460f9289a58e73e9bb5fe3d78951.zip | |
Plotly Integration in JS and Predict using building models
| -rw-r--r-- | app.py | 10 | ||||
| -rw-r--r-- | predictor.py | 62 | ||||
| -rw-r--r-- | static/js/prediction.js | 125 | ||||
| -rw-r--r-- | static/js/search.js | 13 | ||||
| -rw-r--r-- | templates/index.html | 59 |
5 files changed, 223 insertions, 46 deletions
@@ -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 = `<span class="text-sm font-semibold">${result.item.city}</span>`; 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 @@ <ul id="results" class="list-reset h-full block"></ul> </div> </div> - <p class="flex items-center space-x-2 py-2 px-4"><span><strong>Start Date: </strong></span><input - type="date" class="rounded bg-gray-600 w-full" id="startDate" /><span></p> - <p class="flex items-center space-x-2 py-2 px-4"><strong>End Date: </strong></span><input - type="date" class="rounded bg-gray-600 w-full" id="endDate" /></p> + <!-- <p class="flex items-center space-x-2 py-2 px-4"><span><strong>Date: </strong></span><input + type="date" class="rounded bg-gray-600 w-full" id="startDate" /><span></p> --> + <!-- <p class="flex items-center space-x-2 py-2 px-4"><strong>End Date: </strong></span><input --> + <!-- type="date" class="rounded bg-gray-600 w-full" id="endDate" /></p> --> <p class="flex items-center space-x-2 py-2 px-4"> <button id="displayData" - class="text-center px-6 py-2 border border-transparent text-base font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 w-full"> - Display Data + class="inline-flex items-center px-4 py-2 font-semibold leading-6 text-sm shadow rounded-md text-white bg-indigo-600 hover:bg-indigo-700 transition ease-in-out duration-150 w-full text-center"> + Predict for Next 7 Days </button> </p> </nav> @@ -53,7 +53,7 @@ </aside> <main id="content" class="flex-1 p-6 lg:px-8 h-screen overflow-y-auto"> - <div class="mx-auto px-3 py-6"> + <!-- <div class="mx-auto px-3 py-6"> <button class="text-center px-6 py-2 border border-gray-400 text-xl font-medium rounded-md text-white bg-gray-700"> Map @@ -62,46 +62,39 @@ class="text-center px-6 py-2 border border-gray-400 text-xl font-medium rounded-md bg-gray-100 hover:bg-gray-200"> Graph </button> - </div> + </div> --> <div class="h-3/4 mx-auto"> <div class="border-4 border-dashed border-gray-200 rounded-lg h-full"> <div id="map"></div> </div> </div> + <div class="mx-auto px-3 py-6 text-center"> + <button type="button" + class="inline-flex items-center px-4 py-2 font-semibold leading-6 text-sm shadow rounded-md text-white bg-indigo-500 hover:bg-indigo-400 transition ease-in-out duration-150 cursor-not-allowed hidden" + disabled="" id="processingButton"> + <svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" + fill="none" viewBox="0 0 24 24"> + <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"> + </circle> + <path class="opacity-75" fill="currentColor" + d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"> + </path> + </svg> + Processing... + </button> + <div id="predictionImage" class="w-full"></div> + </div> </main> </div> </body> +<script src="https://cdn.plot.ly/plotly-2.6.3.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script type="text/javascript"> const cities = JSON.parse('{{cities_list | tojson}}'); - console.log(cities); </script> <script src="../static/js/map.js" defer></script> <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script> <script src="../static/js/search.js" defer></script> - -<script> - var displayDataButton = document.getElementById('displayData'); - var startDate = document.getElementById('startDate'); - var endDate = document.getElementById('endDate'); - - displayDataButton.addEventListener('click', e => { - e.preventDefault(); - var startDateValue = startDate.value; - var endDateValue = endDate.value; - if (startDateValue == '' || endDateValue == '') { - alert('Please enter a start and end date'); - } else if (endDateValue < startDateValue) { - alert('Please enter a valid date range'); - } else { - $.post("/receiveDates", { - start_date: startDateValue, - end_date: endDateValue - }, data => { - console.log(data); - }); - } - }) -</script> +<script src="../static/js/prediction.js" defer></script> </html>
\ No newline at end of file |
