aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPriyansh <[email protected]>2021-12-17 01:39:25 -0500
committerPriyansh <[email protected]>2021-12-17 01:39:25 -0500
commitffc269114a8c460f9289a58e73e9bb5fe3d78951 (patch)
treef4cec963248ff0abfffe8549b353fb2f0887f309
parente4969ef5b151b6d48c54f0cbc3fe05cc261c147e (diff)
downloadtemp_pred_arima-ffc269114a8c460f9289a58e73e9bb5fe3d78951.tar.xz
temp_pred_arima-ffc269114a8c460f9289a58e73e9bb5fe3d78951.zip
Plotly Integration in JS and Predict using building models
-rw-r--r--app.py10
-rw-r--r--predictor.py62
-rw-r--r--static/js/prediction.js125
-rw-r--r--static/js/search.js13
-rw-r--r--templates/index.html59
5 files changed, 223 insertions, 46 deletions
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 = `<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