akshayballal commited on
Commit
767e14d
1 Parent(s): 4bb0525

Refactor RTU pipeline for improved scalability and maintainability

Browse files
dashboard.py ADDED
@@ -0,0 +1,368 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ import matplotlib.pyplot as plt
5
+ import mqtt_client
6
+ import time
7
+ from src.rtu.RTUPipeline import RTUPipeline
8
+ from src.rtu.RTUAnomalizer1 import RTUAnomalizer1
9
+ import plotly.express as px
10
+
11
+ rtu_data_pipeline = RTUPipeline(
12
+ scaler1_path="src/rtu/models/scaler_rtu_1_2.pkl",
13
+ scaler2_path="src/rtu/models/scaler_rtu_3_4.pkl",
14
+ )
15
+ rtu_anomalizer1 = RTUAnomalizer1(
16
+ prediction_model_path="src/rtu/models/lstm_2rtu_smooth_04.keras",
17
+ clustering_model_paths=[
18
+ "src/rtu/models/kmeans_rtu_1.pkl",
19
+ "src/rtu/models/kmeans_rtu_2.pkl",
20
+ ],
21
+ pca_model_paths=[
22
+ "src/rtu/models/pca_rtu_1.pkl",
23
+ "src/rtu/models/pca_rtu_2.pkl",
24
+ ],
25
+ num_inputs=rtu_data_pipeline.num_inputs,
26
+ num_outputs=rtu_data_pipeline.num_outputs,
27
+ )
28
+
29
+ print("Kmeans models:")
30
+ print(rtu_anomalizer1.kmeans_models)
31
+
32
+ # Set the layout of the page to 'wide'
33
+ st.set_page_config(layout="wide")
34
+
35
+
36
+ # Energy data generating used in Energy Usage Over Time plot ---- REPLACE WITH ACTUAL DATA ----
37
+ def generate_energy_data():
38
+ times = pd.date_range("2021-01-01", periods=200, freq="1min")
39
+ energy = np.random.randn(200).cumsum()
40
+ return pd.DataFrame({"Time": times, "Energy": energy})
41
+
42
+
43
+ # Create three columns for the header
44
+ header_row1_col1, header_row1_col2, header_row1_col3 = st.columns([0.8, 3, 1])
45
+
46
+ # Add logo to the first column of the header
47
+ with header_row1_col1:
48
+ st.image("logo.png")
49
+
50
+ # Add title to the second column of the header
51
+ with header_row1_col2:
52
+ st.markdown(
53
+ "<h1 style='text-align: center;'>Building 59 - HVAC Dashboard</h1>",
54
+ unsafe_allow_html=True,
55
+ )
56
+
57
+ # Add Time and Date to the third column of the header
58
+ mqtt_client.start_mqtt_client()
59
+ placeholder_header_time = header_row1_col3.empty()
60
+
61
+ # Create three columns for the first row
62
+ row1_col1, row1_col2, row1_col3 = st.columns([1.1, 1, 0.75])
63
+
64
+
65
+ # Use a container for RTU Status
66
+ rtu_status_container = row1_col1.container()
67
+ rtu_status_container.markdown(
68
+ """
69
+ <div style="background-color:#E2F0D9;padding:1px;border-radius:5px;margin-bottom:20px">
70
+ <h3 style="color:black;text-align:center;">RTU Status</h3>
71
+ </div>""",
72
+ unsafe_allow_html=True,
73
+ )
74
+
75
+ rtu_placeholders = []
76
+ rtu_columns = rtu_status_container.columns(4)
77
+
78
+ # Initial placeholder, does not update with streaming
79
+ for i in range(4):
80
+ with rtu_columns[i]:
81
+ placeholder = {"box": st.empty(), "sa_temp": st.empty(), "ra_temp": st.empty()}
82
+ rtu_placeholders.append(placeholder)
83
+ placeholder["box"].markdown(
84
+ f"""
85
+ <div style='background-color:#447F80;padding:3px;border-radius:5px;margin-bottom:10px'>
86
+ <h4 style='color:black;text-align:center;'>RTU{i+1}</h4>
87
+ </div>
88
+ """,
89
+ unsafe_allow_html=True,
90
+ )
91
+ placeholder["sa_temp"].markdown("**SA temp:** -- °C")
92
+ placeholder["ra_temp"].markdown("**RA temp:** -- °C")
93
+
94
+ all_data = []
95
+
96
+
97
+ # Temperatures streaming and updates
98
+ def update_status_boxes(df):
99
+ for i in range(4):
100
+ sa_temp = df[f"rtu_00{i+1}_sa_temp"].iloc[-1]
101
+ ra_temp = df[f"rtu_00{i+1}_ra_temp"].iloc[-1]
102
+ rtu_placeholders[i]["sa_temp"].markdown(f"**SA temp:** {sa_temp} °C")
103
+ rtu_placeholders[i]["ra_temp"].markdown(f"**RA temp:** {ra_temp} °C")
104
+
105
+
106
+ # Zones
107
+ with row1_col2:
108
+ st.markdown(
109
+ """
110
+ <div style="background-color:#E2F0D9;padding:1px;border-radius:5px;margin-bottom:20px">
111
+ <h3 style="color:black;text-align:center;">Zones</h3>
112
+ </div>""",
113
+ unsafe_allow_html=True,
114
+ )
115
+
116
+ tab1, tab2, tab3, tab4 = st.tabs(["RTU 1", "RTU 2", "RTU 3", "RTU 4"])
117
+
118
+ with tab1:
119
+
120
+ zones_ = {36, 37, 38, 39, 40, 41, 42, 64, 65, 66, 67, 68, 69, 70}
121
+
122
+ num_cols = 7
123
+ rows = 2
124
+
125
+ for i in range(rows):
126
+ cols = st.columns(num_cols)
127
+ if i == 0:
128
+ for j in range(num_cols):
129
+ zone_number = (i + 1) * (j + 1) + 35
130
+ if zone_number in zones_:
131
+ button_html = f'<button style="width:100%; height:50px; border:none; color:black; background-color:#FFFFFF">{zone_number}</button>'
132
+ with cols[j]:
133
+ st.markdown(button_html, unsafe_allow_html=True)
134
+ else:
135
+ with cols[j]:
136
+ st.write("")
137
+ else:
138
+ for j in range(num_cols):
139
+ zone_number = (i + 1) * 30 + j + 4
140
+ if zone_number in zones_:
141
+ button_html = f'<button style="width:100%; height:50px; border:none; color:black; background-color:#FFFFFF">{zone_number}</button>'
142
+ with cols[j]:
143
+ st.markdown(button_html, unsafe_allow_html=True)
144
+ else:
145
+ with cols[j]:
146
+ st.write("")
147
+
148
+ with tab2:
149
+ zones_ = [
150
+ 19,
151
+ 20,
152
+ 27,
153
+ 28,
154
+ 29,
155
+ 30,
156
+ 31,
157
+ 32,
158
+ 33,
159
+ 34,
160
+ 35,
161
+ 43,
162
+ 44,
163
+ 49,
164
+ 50,
165
+ 57,
166
+ 58,
167
+ 59,
168
+ 60,
169
+ 62,
170
+ 63,
171
+ 71,
172
+ 72,
173
+ ]
174
+ zones_list = list(zones_)
175
+ num_cols = 7
176
+ rows = 4
177
+ zones_list_rows = [
178
+ zones_list[i * num_cols : (i + 1) * num_cols] for i in range(rows)
179
+ ]
180
+
181
+ for row in zones_list_rows:
182
+ cols = st.columns(num_cols)
183
+ for col, zone_number in zip(cols, row):
184
+ button_html = f'<button style="width:100%; height:50px; border:none; color:black; background-color:#FFFFFF">{zone_number}</button>'
185
+ with col:
186
+ st.markdown(button_html, unsafe_allow_html=True)
187
+
188
+ with tab3:
189
+ zones_ = [18, 25, 26, 45, 48, 55, 56, 61]
190
+ zones_list = sorted(zones_)
191
+ num_cols = 7
192
+ rows = 2
193
+ zones_list_rows = [
194
+ zones_list[i * num_cols : (i + 1) * num_cols] for i in range(rows)
195
+ ]
196
+
197
+ for row in zones_list_rows:
198
+ cols = st.columns(num_cols)
199
+ for col, zone_number in zip(cols, row):
200
+ button_html = f'<button style="width:100%; height:50px; border:none; color:black; background-color:#FFFFFF">{zone_number}</button>'
201
+ with col:
202
+ st.markdown(button_html, unsafe_allow_html=True)
203
+
204
+ with tab4:
205
+ zones_ = [16, 17, 21, 22, 23, 24, 46, 47, 51, 52, 53, 54]
206
+ zones_list = sorted(zones_)
207
+ num_cols = 7
208
+ rows = 2
209
+ zones_list_rows = [
210
+ zones_list[i * num_cols : (i + 1) * num_cols] for i in range(rows)
211
+ ]
212
+
213
+ for row in zones_list_rows:
214
+ cols = st.columns(num_cols)
215
+ for col, zone_number in zip(cols, row):
216
+ button_html = f'<button style="width:100%; height:50px; border:none; color:black; background-color:#FFFFFF">{zone_number}</button>'
217
+ with col:
218
+ st.markdown(button_html, unsafe_allow_html=True)
219
+
220
+ # Faults
221
+ with row1_col3:
222
+ st.markdown(
223
+ """
224
+ <div style="background-color:#E2F0D9;padding:1px;border-radius:5px;margin-bottom:20px">
225
+ <h3 style="color:black;text-align:center;">Faults</h3>
226
+ </div>""",
227
+ unsafe_allow_html=True,
228
+ )
229
+
230
+ fault_data = { # ---- REPLACE WITH ACTUAL DATA ----
231
+ "Start Time": ["28/12/17 10:00", "29/12/17 11:00"],
232
+ "End Time": ["28/12/17 12:00", "29/12/17 15:00"],
233
+ "Issue": ["RTU 3 – Damper stuck", "Zone 6 – Fan failure"],
234
+ }
235
+ df_faults = pd.DataFrame(fault_data)
236
+ st.dataframe(df_faults)
237
+
238
+
239
+ # Details
240
+ with st.container():
241
+ st.markdown(
242
+ """
243
+ <div style="background-color:#E2F0D9;padding:1px;border-radius:5px;margin-bottom:20px">
244
+ <h3 style="color:black;text-align:center;">Details</h3>
245
+ </div>""",
246
+ unsafe_allow_html=True,
247
+ )
248
+
249
+ # Create three columns
250
+ row2_row1_col1, row2_row1_col2 = st.columns([0.9, 1.5])
251
+
252
+ # Floor Plan
253
+ with row2_row1_col1:
254
+ st.subheader("Floor Map")
255
+ st.image("floor_plan.jpg", use_column_width=True)
256
+
257
+ # Energy Comsumption Plots
258
+ with row2_row1_col2:
259
+
260
+ # Create two rows and two columns
261
+ row2_row2_col1, row2_row2_col2 = st.columns(2)
262
+ # cols = st.columns(2)
263
+
264
+ with row2_row2_col1:
265
+ st.subheader("Energy Usage - North Wing")
266
+ df_energy = generate_energy_data() # ---- REPLACE WITH ACTUAL DATA ----
267
+ fig, ax = plt.subplots(figsize=(5, 1.5))
268
+ ax.plot(df_energy["Time"], df_energy["Energy"])
269
+ ax.set_xlabel("Time")
270
+ ax.set_ylabel("Energy (kWh)")
271
+ st.pyplot(fig)
272
+
273
+ # with row2_row2_col2:
274
+ st.subheader("Energy Usage - South Wing")
275
+ df_energy = generate_energy_data() # ---- REPLACE WITH ACTUAL DATA ----
276
+ fig, ax = plt.subplots(figsize=(5, 1.5))
277
+ ax.plot(df_energy["Time"], df_energy["Energy"])
278
+ ax.set_xlabel("Time")
279
+ ax.set_ylabel("Energy (kWh)")
280
+ st.pyplot(fig)
281
+
282
+ # Energy Comsumption Statistics
283
+ with row2_row2_col2:
284
+ st.subheader("Energy Usage Statistics")
285
+ st.text(
286
+ f"Average: 475 kWh\nHighest: 600 kWh"
287
+ ) # ---- REPLACE WITH ACTUAL DATA ----
288
+
289
+
290
+ distance_placeholder = st.empty()
291
+ resid_placeholder = st.empty()
292
+
293
+ distances = []
294
+ while True:
295
+
296
+ if mqtt_client.data_list:
297
+ all_data.extend(mqtt_client.data_list)
298
+ df = pd.DataFrame(all_data)
299
+
300
+ df_time = df["date"].iloc[-1] # Obtain the latest datetime of data
301
+
302
+ with placeholder_header_time:
303
+ placeholder_header_time.markdown(
304
+ f"""
305
+ <h2 style='text-align: center;'> 🕒 {df_time}</h2>
306
+ """,
307
+ unsafe_allow_html=True,
308
+ )
309
+
310
+ # Loop to update
311
+ update_status_boxes(df)
312
+
313
+ dist = None
314
+ resid_pca_list = None
315
+ df_new1, df_trans1, df_new2, df_trans2 = rtu_data_pipeline.fit(df)
316
+ if (
317
+ not df_new1 is None
318
+ and not df_trans1 is None
319
+ and not df_new2 is None
320
+ and not df_trans2 is None
321
+ ):
322
+ actual_list, pred_list, resid_list, resid_pca_list, dist = (
323
+ rtu_anomalizer1.pipeline(df_new1, df_trans1, rtu_data_pipeline.scaler1)
324
+ )
325
+
326
+ if resid_pca_list is not None:
327
+ resid_pca_list = np.array(resid_pca_list)
328
+
329
+ # plot the distances in a scatter chart in streamlit plotly express
330
+ with distance_placeholder:
331
+ if dist is not None:
332
+ distances.append(float(dist[0][0]))
333
+ fig = px.line(
334
+ x=range(len(distances)),
335
+ y=distances,
336
+ labels={"x": "Time", "y": "Distance"},
337
+ title="Distance from Cluster Center",
338
+ )
339
+ st.plotly_chart(fig)
340
+
341
+ with resid_placeholder:
342
+ if resid_pca_list is not None:
343
+ fig = px.scatter(
344
+ x=resid_pca_list[:, 0],
345
+ y=resid_pca_list[:, 1],
346
+ labels={"x": "Time", "y": "Residual"},
347
+ title="Residuals",
348
+ width=800,
349
+ height=800,
350
+ )
351
+ fig.update_layout(
352
+ xaxis_range=[-1, 1],
353
+ yaxis_range=[-1, 1],
354
+ xaxis=dict(showgrid=True, gridwidth=1, gridcolor="lightgray"),
355
+ yaxis=dict(showgrid=True, gridwidth=1, gridcolor="lightgray"),
356
+ margin=dict(l=20, r=20, t=20, b=20),
357
+ hovermode="closest",
358
+ showlegend=False,
359
+ autosize=False,
360
+ hoverlabel=dict(bgcolor="white", font_size=12),
361
+ hoverlabel_align="left",
362
+ hoverlabel_font_color="black",
363
+ hoverlabel_bordercolor="lightgray",
364
+ )
365
+ fig.update_traces(marker=dict(size=5, color="blue"))
366
+ st.plotly_chart(fig)
367
+
368
+ mqtt_client.data_list.clear()
floor_plan.jpg ADDED
logo.png ADDED
mqtt_client.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mqtt_client.py
2
+ import paho.mqtt.client as mqtt
3
+ import json
4
+
5
+ broker = "localhost"
6
+ port = 1883
7
+ topic = "sensor_data"
8
+
9
+ data_list = []
10
+
11
+
12
+ def on_connect(client, userdata, flags, rc):
13
+ print(f"Connected with result code {rc}")
14
+ client.subscribe(topic)
15
+
16
+
17
+ def on_message(client, userdata, msg):
18
+ global data_list
19
+ data = json.loads(msg.payload)
20
+ data_list.append(data)
21
+
22
+
23
+ client = mqtt.Client()
24
+ client.on_connect = on_connect
25
+ client.on_message = on_message
26
+
27
+
28
+ def start_mqtt_client():
29
+ client.connect(broker, port)
30
+ client.loop_start()
31
+
32
+
33
+ if __name__ == "__main__":
34
+ start_mqtt_client()
mqttclient.ipynb DELETED
@@ -1,1100 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 6,
6
- "metadata": {},
7
- "outputs": [
8
- {
9
- "name": "stderr",
10
- "output_type": "stream",
11
- "text": [
12
- "C:\\Users\\jerin\\AppData\\Local\\Temp\\ipykernel_3260\\368714138.py:22: DeprecationWarning: Callback API version 1 is deprecated, update to latest version\n",
13
- " client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1)\n"
14
- ]
15
- },
16
- {
17
- "name": "stdout",
18
- "output_type": "stream",
19
- "text": [
20
- "{'date': '2018-05-02 00:09:00', 'hp_hws_temp': 96.3, 'rtu_003_sa_temp': 64.2, 'rtu_003_oadmpr_pct': 88.4, 'rtu_003_ra_temp': 72.5, 'rtu_003_oa_temp': 61.6, 'rtu_003_ma_temp': 63.5, 'rtu_003_sf_vfd_spd_fbk_tn': 77.8, 'rtu_003_rf_vfd_spd_fbk_tn': 54.3, 'rtu_004_sa_temp': 68.9, 'rtu_004_oadmpr_pct': 54.2, 'rtu_004_ra_temp': 73.3, 'rtu_004_oa_temp': 67.4, 'rtu_004_ma_temp': 67.6, 'rtu_004_sf_vfd_spd_fbk_tn': 75.7, 'rtu_004_rf_vfd_spd_fbk_tn': 78.3, 'air_temp_set_1': 14.9, 'air_temp_set_2': 14.44, 'dew_point_temperature_set_1d': 7.02, 'relative_humidity_set_1': 59.5, 'solar_radiation_set_1': 335.9}\n",
21
- "{'date': '2018-05-02 00:10:00', 'hp_hws_temp': 97.0, 'rtu_003_sa_temp': 64.1, 'rtu_003_oadmpr_pct': 88.4, 'rtu_003_ra_temp': 72.4, 'rtu_003_oa_temp': 61.9, 'rtu_003_ma_temp': 63.3, 'rtu_003_sf_vfd_spd_fbk_tn': 77.2, 'rtu_003_rf_vfd_spd_fbk_tn': 52.5, 'rtu_004_sa_temp': 68.8, 'rtu_004_oadmpr_pct': 80.6, 'rtu_004_ra_temp': 73.3, 'rtu_004_oa_temp': 68.2, 'rtu_004_ma_temp': 66.1, 'rtu_004_sf_vfd_spd_fbk_tn': 75.6, 'rtu_004_rf_vfd_spd_fbk_tn': 67.3, 'air_temp_set_1': 14.9, 'air_temp_set_2': 14.44, 'dew_point_temperature_set_1d': 7.02, 'relative_humidity_set_1': 59.5, 'solar_radiation_set_1': 335.9}\n",
22
- "{'date': '2018-05-02 00:11:00', 'hp_hws_temp': 97.6, 'rtu_003_sa_temp': 64.1, 'rtu_003_oadmpr_pct': 88.4, 'rtu_003_ra_temp': 72.4, 'rtu_003_oa_temp': 62.0, 'rtu_003_ma_temp': 63.8, 'rtu_003_sf_vfd_spd_fbk_tn': 78.2, 'rtu_003_rf_vfd_spd_fbk_tn': 56.7, 'rtu_004_sa_temp': 67.3, 'rtu_004_oadmpr_pct': 76.6, 'rtu_004_ra_temp': 73.4, 'rtu_004_oa_temp': 68.6, 'rtu_004_ma_temp': 64.3, 'rtu_004_sf_vfd_spd_fbk_tn': 78.6, 'rtu_004_rf_vfd_spd_fbk_tn': 77.5, 'air_temp_set_1': 14.9, 'air_temp_set_2': 14.44, 'dew_point_temperature_set_1d': 7.02, 'relative_humidity_set_1': 59.5, 'solar_radiation_set_1': 335.9}\n",
23
- "{'date': '2018-05-02 00:12:00', 'hp_hws_temp': 98.3, 'rtu_003_sa_temp': 64.2, 'rtu_003_oadmpr_pct': 88.4, 'rtu_003_ra_temp': 72.4, 'rtu_003_oa_temp': 62.1, 'rtu_003_ma_temp': 64.1, 'rtu_003_sf_vfd_spd_fbk_tn': 76.4, 'rtu_003_rf_vfd_spd_fbk_tn': 52.9, 'rtu_004_sa_temp': 66.7, 'rtu_004_oadmpr_pct': 51.4, 'rtu_004_ra_temp': 73.4, 'rtu_004_oa_temp': 68.9, 'rtu_004_ma_temp': 65.1, 'rtu_004_sf_vfd_spd_fbk_tn': 79.6, 'rtu_004_rf_vfd_spd_fbk_tn': 82.5, 'air_temp_set_1': 14.9, 'air_temp_set_2': 14.44, 'dew_point_temperature_set_1d': 7.02, 'relative_humidity_set_1': 59.5, 'solar_radiation_set_1': 335.9}\n",
24
- "{'date': '2018-05-02 00:13:00', 'hp_hws_temp': 98.9, 'rtu_003_sa_temp': 64.3, 'rtu_003_oadmpr_pct': 88.4, 'rtu_003_ra_temp': 72.3, 'rtu_003_oa_temp': 62.2, 'rtu_003_ma_temp': 63.8, 'rtu_003_sf_vfd_spd_fbk_tn': 78.5, 'rtu_003_rf_vfd_spd_fbk_tn': 57.0, 'rtu_004_sa_temp': 67.8, 'rtu_004_oadmpr_pct': 52.4, 'rtu_004_ra_temp': 73.4, 'rtu_004_oa_temp': 68.9, 'rtu_004_ma_temp': 67.8, 'rtu_004_sf_vfd_spd_fbk_tn': 78.3, 'rtu_004_rf_vfd_spd_fbk_tn': 73.9, 'air_temp_set_1': 14.9, 'air_temp_set_2': 14.44, 'dew_point_temperature_set_1d': 7.02, 'relative_humidity_set_1': 59.5, 'solar_radiation_set_1': 335.9}\n",
25
- "{'date': '2018-05-02 00:14:00', 'hp_hws_temp': 99.3, 'rtu_003_sa_temp': 64.4, 'rtu_003_oadmpr_pct': 88.4, 'rtu_003_ra_temp': 72.4, 'rtu_003_oa_temp': 62.5, 'rtu_003_ma_temp': 63.9, 'rtu_003_sf_vfd_spd_fbk_tn': 75.9, 'rtu_003_rf_vfd_spd_fbk_tn': 49.8, 'rtu_004_sa_temp': 68.8, 'rtu_004_oadmpr_pct': 52.4, 'rtu_004_ra_temp': 73.3, 'rtu_004_oa_temp': 68.1, 'rtu_004_ma_temp': 68.3, 'rtu_004_sf_vfd_spd_fbk_tn': 76.5, 'rtu_004_rf_vfd_spd_fbk_tn': 74.7, 'air_temp_set_1': 14.9, 'air_temp_set_2': 14.44, 'dew_point_temperature_set_1d': 7.02, 'relative_humidity_set_1': 59.5, 'solar_radiation_set_1': 335.9}\n",
26
- "{'date': '2018-05-02 00:15:00', 'hp_hws_temp': 99.0, 'rtu_003_sa_temp': 63.9, 'rtu_003_oadmpr_pct': 88.4, 'rtu_003_ra_temp': 72.3, 'rtu_003_oa_temp': 62.6, 'rtu_003_ma_temp': 63.6, 'rtu_003_sf_vfd_spd_fbk_tn': 74.3, 'rtu_003_rf_vfd_spd_fbk_tn': 53.5, 'rtu_004_sa_temp': 69.1, 'rtu_004_oadmpr_pct': 79.0, 'rtu_004_ra_temp': 73.3, 'rtu_004_oa_temp': 67.2, 'rtu_004_ma_temp': 66.6, 'rtu_004_sf_vfd_spd_fbk_tn': 75.3, 'rtu_004_rf_vfd_spd_fbk_tn': 69.0, 'air_temp_set_1': 16.0, 'air_temp_set_2': 15.48, 'dew_point_temperature_set_1d': 6.63, 'relative_humidity_set_1': 54.0, 'solar_radiation_set_1': 426.3}\n"
27
- ]
28
- },
29
- {
30
- "ename": "KeyboardInterrupt",
31
- "evalue": "",
32
- "output_type": "error",
33
- "traceback": [
34
- "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
35
- "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
36
- "Cell \u001b[1;32mIn[6], line 26\u001b[0m\n\u001b[0;32m 24\u001b[0m client\u001b[38;5;241m.\u001b[39mconnect(broker_address, broker_port)\n\u001b[0;32m 25\u001b[0m client\u001b[38;5;241m.\u001b[39msubscribe(topic)\n\u001b[1;32m---> 26\u001b[0m \u001b[43mclient\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mloop_forever\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
37
- "File \u001b[1;32mc:\\Users\\jerin\\anaconda3\\envs\\smartbuilding\\Lib\\site-packages\\paho\\mqtt\\client.py:2291\u001b[0m, in \u001b[0;36mClient.loop_forever\u001b[1;34m(self, timeout, retry_first_connection)\u001b[0m\n\u001b[0;32m 2289\u001b[0m rc \u001b[38;5;241m=\u001b[39m MQTTErrorCode\u001b[38;5;241m.\u001b[39mMQTT_ERR_SUCCESS\n\u001b[0;32m 2290\u001b[0m \u001b[38;5;28;01mwhile\u001b[39;00m rc \u001b[38;5;241m==\u001b[39m MQTTErrorCode\u001b[38;5;241m.\u001b[39mMQTT_ERR_SUCCESS:\n\u001b[1;32m-> 2291\u001b[0m rc \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_loop\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 2292\u001b[0m \u001b[38;5;66;03m# We don't need to worry about locking here, because we've\u001b[39;00m\n\u001b[0;32m 2293\u001b[0m \u001b[38;5;66;03m# either called loop_forever() when in single threaded mode, or\u001b[39;00m\n\u001b[0;32m 2294\u001b[0m \u001b[38;5;66;03m# in multi threaded mode when loop_stop() has been called and\u001b[39;00m\n\u001b[0;32m 2295\u001b[0m \u001b[38;5;66;03m# so no other threads can access _out_packet or _messages.\u001b[39;00m\n\u001b[0;32m 2296\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_thread_terminate \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[0;32m 2297\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_out_packet) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m0\u001b[39m\n\u001b[0;32m 2298\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_out_messages) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m0\u001b[39m):\n",
38
- "File \u001b[1;32mc:\\Users\\jerin\\anaconda3\\envs\\smartbuilding\\Lib\\site-packages\\paho\\mqtt\\client.py:1657\u001b[0m, in \u001b[0;36mClient._loop\u001b[1;34m(self, timeout)\u001b[0m\n\u001b[0;32m 1654\u001b[0m rlist \u001b[38;5;241m=\u001b[39m [\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_sock, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_sockpairR]\n\u001b[0;32m 1656\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m-> 1657\u001b[0m socklist \u001b[38;5;241m=\u001b[39m select\u001b[38;5;241m.\u001b[39mselect(rlist, wlist, [], timeout)\n\u001b[0;32m 1658\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m:\n\u001b[0;32m 1659\u001b[0m \u001b[38;5;66;03m# Socket isn't correct type, in likelihood connection is lost\u001b[39;00m\n\u001b[0;32m 1660\u001b[0m \u001b[38;5;66;03m# ... or we called disconnect(). In that case the socket will\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 1663\u001b[0m \u001b[38;5;66;03m# rc != MQTT_ERR_SUCCESS and we don't want state to change from\u001b[39;00m\n\u001b[0;32m 1664\u001b[0m \u001b[38;5;66;03m# mqtt_cs_disconnecting.\u001b[39;00m\n\u001b[0;32m 1665\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_state \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m (_ConnectionState\u001b[38;5;241m.\u001b[39mMQTT_CS_DISCONNECTING, _ConnectionState\u001b[38;5;241m.\u001b[39mMQTT_CS_DISCONNECTED):\n",
39
- "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
40
- ]
41
- }
42
- ],
43
- "source": [
44
- "import paho.mqtt.client as mqtt\n",
45
- "import json\n",
46
- "import pandas as pd\n",
47
- "\n",
48
- "broker_address = \"localhost\"\n",
49
- "broker_port = 1883\n",
50
- "topic = \"sensor_data\"\n",
51
- "\n",
52
- "df = pd.DataFrame(columns=[\"sa_temp\", \"ma_temp\"])\n",
53
- "\n",
54
- "def on_message(client, userdata, message):\n",
55
- " global df\n",
56
- " payload = json.loads(message.payload.decode())\n",
57
- " # sa_temp = payload[\"sa_temp\"]\n",
58
- " # ma_temp = payload[\"ma_temp\"]\n",
59
- " \n",
60
- " print(payload)\n",
61
- " # df.loc[len(df)] = {\"sa_temp\": sa_temp, \"ma_temp\": ma_temp}\n",
62
- " \n",
63
- "\n",
64
- "\n",
65
- "client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1)\n",
66
- "client.on_message = on_message\n",
67
- "client.connect(broker_address, broker_port)\n",
68
- "client.subscribe(topic)\n",
69
- "client.loop_forever()\n",
70
- "\n",
71
- "\n"
72
- ]
73
- },
74
- {
75
- "cell_type": "code",
76
- "execution_count": 25,
77
- "metadata": {},
78
- "outputs": [
79
- {
80
- "data": {
81
- "text/html": [
82
- "<div>\n",
83
- "<style scoped>\n",
84
- " .dataframe tbody tr th:only-of-type {\n",
85
- " vertical-align: middle;\n",
86
- " }\n",
87
- "\n",
88
- " .dataframe tbody tr th {\n",
89
- " vertical-align: top;\n",
90
- " }\n",
91
- "\n",
92
- " .dataframe thead th {\n",
93
- " text-align: right;\n",
94
- " }\n",
95
- "</style>\n",
96
- "<table border=\"1\" class=\"dataframe\">\n",
97
- " <thead>\n",
98
- " <tr style=\"text-align: right;\">\n",
99
- " <th></th>\n",
100
- " <th>sa_temp</th>\n",
101
- " <th>ma_temp</th>\n",
102
- " </tr>\n",
103
- " </thead>\n",
104
- " <tbody>\n",
105
- " <tr>\n",
106
- " <th>0</th>\n",
107
- " <td>68.6</td>\n",
108
- " <td>70.0</td>\n",
109
- " </tr>\n",
110
- " <tr>\n",
111
- " <th>1</th>\n",
112
- " <td>68.6</td>\n",
113
- " <td>70.0</td>\n",
114
- " </tr>\n",
115
- " <tr>\n",
116
- " <th>2</th>\n",
117
- " <td>68.6</td>\n",
118
- " <td>70.0</td>\n",
119
- " </tr>\n",
120
- " <tr>\n",
121
- " <th>3</th>\n",
122
- " <td>68.6</td>\n",
123
- " <td>70.0</td>\n",
124
- " </tr>\n",
125
- " </tbody>\n",
126
- "</table>\n",
127
- "</div>"
128
- ],
129
- "text/plain": [
130
- " sa_temp ma_temp\n",
131
- "0 68.6 70.0\n",
132
- "1 68.6 70.0\n",
133
- "2 68.6 70.0\n",
134
- "3 68.6 70.0"
135
- ]
136
- },
137
- "execution_count": 25,
138
- "metadata": {},
139
- "output_type": "execute_result"
140
- }
141
- ],
142
- "source": [
143
- "df"
144
- ]
145
- },
146
- {
147
- "cell_type": "code",
148
- "execution_count": 4,
149
- "metadata": {},
150
- "outputs": [
151
- {
152
- "ename": "ValueError",
153
- "evalue": "Mime type rendering requires nbformat>=4.2.0 but it is not installed",
154
- "output_type": "error",
155
- "traceback": [
156
- "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
157
- "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
158
- "File \u001b[1;32mc:\\Users\\jerin\\anaconda3\\envs\\smartbuilding\\Lib\\site-packages\\IPython\\core\\formatters.py:925\u001b[0m, in \u001b[0;36mIPythonDisplayFormatter.__call__\u001b[1;34m(self, obj)\u001b[0m\n\u001b[0;32m 923\u001b[0m method \u001b[38;5;241m=\u001b[39m get_real_method(obj, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mprint_method)\n\u001b[0;32m 924\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m method \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m--> 925\u001b[0m \u001b[43mmethod\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 926\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m\n",
159
- "File \u001b[1;32mc:\\Users\\jerin\\anaconda3\\envs\\smartbuilding\\Lib\\site-packages\\plotly\\basedatatypes.py:832\u001b[0m, in \u001b[0;36mBaseFigure._ipython_display_\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 829\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mplotly\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mio\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mpio\u001b[39;00m\n\u001b[0;32m 831\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m pio\u001b[38;5;241m.\u001b[39mrenderers\u001b[38;5;241m.\u001b[39mrender_on_display \u001b[38;5;129;01mand\u001b[39;00m pio\u001b[38;5;241m.\u001b[39mrenderers\u001b[38;5;241m.\u001b[39mdefault:\n\u001b[1;32m--> 832\u001b[0m \u001b[43mpio\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mshow\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 833\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 834\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mrepr\u001b[39m(\u001b[38;5;28mself\u001b[39m))\n",
160
- "File \u001b[1;32mc:\\Users\\jerin\\anaconda3\\envs\\smartbuilding\\Lib\\site-packages\\plotly\\io\\_renderers.py:394\u001b[0m, in \u001b[0;36mshow\u001b[1;34m(fig, renderer, validate, **kwargs)\u001b[0m\n\u001b[0;32m 389\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m 390\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMime type rendering requires ipython but it is not installed\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 391\u001b[0m )\n\u001b[0;32m 393\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m nbformat \u001b[38;5;129;01mor\u001b[39;00m Version(nbformat\u001b[38;5;241m.\u001b[39m__version__) \u001b[38;5;241m<\u001b[39m Version(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m4.2.0\u001b[39m\u001b[38;5;124m\"\u001b[39m):\n\u001b[1;32m--> 394\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m 395\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMime type rendering requires nbformat>=4.2.0 but it is not installed\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 396\u001b[0m )\n\u001b[0;32m 398\u001b[0m ipython_display\u001b[38;5;241m.\u001b[39mdisplay(bundle, raw\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[0;32m 400\u001b[0m \u001b[38;5;66;03m# external renderers\u001b[39;00m\n",
161
- "\u001b[1;31mValueError\u001b[0m: Mime type rendering requires nbformat>=4.2.0 but it is not installed"
162
- ]
163
- },
164
- {
165
- "data": {
166
- "application/vnd.plotly.v1+json": {
167
- "config": {
168
- "plotlyServerURL": "https://plot.ly"
169
- },
170
- "data": [
171
- {
172
- "hovertemplate": "index=%{x}<br>sa_temp=%{y}<extra></extra>",
173
- "legendgroup": "",
174
- "line": {
175
- "color": "#636efa",
176
- "dash": "solid"
177
- },
178
- "marker": {
179
- "symbol": "circle"
180
- },
181
- "mode": "lines",
182
- "name": "",
183
- "orientation": "v",
184
- "showlegend": false,
185
- "type": "scatter",
186
- "x": [],
187
- "xaxis": "x",
188
- "y": [],
189
- "yaxis": "y"
190
- }
191
- ],
192
- "layout": {
193
- "legend": {
194
- "tracegroupgap": 0
195
- },
196
- "margin": {
197
- "t": 60
198
- },
199
- "template": {
200
- "data": {
201
- "bar": [
202
- {
203
- "error_x": {
204
- "color": "#2a3f5f"
205
- },
206
- "error_y": {
207
- "color": "#2a3f5f"
208
- },
209
- "marker": {
210
- "line": {
211
- "color": "#E5ECF6",
212
- "width": 0.5
213
- },
214
- "pattern": {
215
- "fillmode": "overlay",
216
- "size": 10,
217
- "solidity": 0.2
218
- }
219
- },
220
- "type": "bar"
221
- }
222
- ],
223
- "barpolar": [
224
- {
225
- "marker": {
226
- "line": {
227
- "color": "#E5ECF6",
228
- "width": 0.5
229
- },
230
- "pattern": {
231
- "fillmode": "overlay",
232
- "size": 10,
233
- "solidity": 0.2
234
- }
235
- },
236
- "type": "barpolar"
237
- }
238
- ],
239
- "carpet": [
240
- {
241
- "aaxis": {
242
- "endlinecolor": "#2a3f5f",
243
- "gridcolor": "white",
244
- "linecolor": "white",
245
- "minorgridcolor": "white",
246
- "startlinecolor": "#2a3f5f"
247
- },
248
- "baxis": {
249
- "endlinecolor": "#2a3f5f",
250
- "gridcolor": "white",
251
- "linecolor": "white",
252
- "minorgridcolor": "white",
253
- "startlinecolor": "#2a3f5f"
254
- },
255
- "type": "carpet"
256
- }
257
- ],
258
- "choropleth": [
259
- {
260
- "colorbar": {
261
- "outlinewidth": 0,
262
- "ticks": ""
263
- },
264
- "type": "choropleth"
265
- }
266
- ],
267
- "contour": [
268
- {
269
- "colorbar": {
270
- "outlinewidth": 0,
271
- "ticks": ""
272
- },
273
- "colorscale": [
274
- [
275
- 0,
276
- "#0d0887"
277
- ],
278
- [
279
- 0.1111111111111111,
280
- "#46039f"
281
- ],
282
- [
283
- 0.2222222222222222,
284
- "#7201a8"
285
- ],
286
- [
287
- 0.3333333333333333,
288
- "#9c179e"
289
- ],
290
- [
291
- 0.4444444444444444,
292
- "#bd3786"
293
- ],
294
- [
295
- 0.5555555555555556,
296
- "#d8576b"
297
- ],
298
- [
299
- 0.6666666666666666,
300
- "#ed7953"
301
- ],
302
- [
303
- 0.7777777777777778,
304
- "#fb9f3a"
305
- ],
306
- [
307
- 0.8888888888888888,
308
- "#fdca26"
309
- ],
310
- [
311
- 1,
312
- "#f0f921"
313
- ]
314
- ],
315
- "type": "contour"
316
- }
317
- ],
318
- "contourcarpet": [
319
- {
320
- "colorbar": {
321
- "outlinewidth": 0,
322
- "ticks": ""
323
- },
324
- "type": "contourcarpet"
325
- }
326
- ],
327
- "heatmap": [
328
- {
329
- "colorbar": {
330
- "outlinewidth": 0,
331
- "ticks": ""
332
- },
333
- "colorscale": [
334
- [
335
- 0,
336
- "#0d0887"
337
- ],
338
- [
339
- 0.1111111111111111,
340
- "#46039f"
341
- ],
342
- [
343
- 0.2222222222222222,
344
- "#7201a8"
345
- ],
346
- [
347
- 0.3333333333333333,
348
- "#9c179e"
349
- ],
350
- [
351
- 0.4444444444444444,
352
- "#bd3786"
353
- ],
354
- [
355
- 0.5555555555555556,
356
- "#d8576b"
357
- ],
358
- [
359
- 0.6666666666666666,
360
- "#ed7953"
361
- ],
362
- [
363
- 0.7777777777777778,
364
- "#fb9f3a"
365
- ],
366
- [
367
- 0.8888888888888888,
368
- "#fdca26"
369
- ],
370
- [
371
- 1,
372
- "#f0f921"
373
- ]
374
- ],
375
- "type": "heatmap"
376
- }
377
- ],
378
- "heatmapgl": [
379
- {
380
- "colorbar": {
381
- "outlinewidth": 0,
382
- "ticks": ""
383
- },
384
- "colorscale": [
385
- [
386
- 0,
387
- "#0d0887"
388
- ],
389
- [
390
- 0.1111111111111111,
391
- "#46039f"
392
- ],
393
- [
394
- 0.2222222222222222,
395
- "#7201a8"
396
- ],
397
- [
398
- 0.3333333333333333,
399
- "#9c179e"
400
- ],
401
- [
402
- 0.4444444444444444,
403
- "#bd3786"
404
- ],
405
- [
406
- 0.5555555555555556,
407
- "#d8576b"
408
- ],
409
- [
410
- 0.6666666666666666,
411
- "#ed7953"
412
- ],
413
- [
414
- 0.7777777777777778,
415
- "#fb9f3a"
416
- ],
417
- [
418
- 0.8888888888888888,
419
- "#fdca26"
420
- ],
421
- [
422
- 1,
423
- "#f0f921"
424
- ]
425
- ],
426
- "type": "heatmapgl"
427
- }
428
- ],
429
- "histogram": [
430
- {
431
- "marker": {
432
- "pattern": {
433
- "fillmode": "overlay",
434
- "size": 10,
435
- "solidity": 0.2
436
- }
437
- },
438
- "type": "histogram"
439
- }
440
- ],
441
- "histogram2d": [
442
- {
443
- "colorbar": {
444
- "outlinewidth": 0,
445
- "ticks": ""
446
- },
447
- "colorscale": [
448
- [
449
- 0,
450
- "#0d0887"
451
- ],
452
- [
453
- 0.1111111111111111,
454
- "#46039f"
455
- ],
456
- [
457
- 0.2222222222222222,
458
- "#7201a8"
459
- ],
460
- [
461
- 0.3333333333333333,
462
- "#9c179e"
463
- ],
464
- [
465
- 0.4444444444444444,
466
- "#bd3786"
467
- ],
468
- [
469
- 0.5555555555555556,
470
- "#d8576b"
471
- ],
472
- [
473
- 0.6666666666666666,
474
- "#ed7953"
475
- ],
476
- [
477
- 0.7777777777777778,
478
- "#fb9f3a"
479
- ],
480
- [
481
- 0.8888888888888888,
482
- "#fdca26"
483
- ],
484
- [
485
- 1,
486
- "#f0f921"
487
- ]
488
- ],
489
- "type": "histogram2d"
490
- }
491
- ],
492
- "histogram2dcontour": [
493
- {
494
- "colorbar": {
495
- "outlinewidth": 0,
496
- "ticks": ""
497
- },
498
- "colorscale": [
499
- [
500
- 0,
501
- "#0d0887"
502
- ],
503
- [
504
- 0.1111111111111111,
505
- "#46039f"
506
- ],
507
- [
508
- 0.2222222222222222,
509
- "#7201a8"
510
- ],
511
- [
512
- 0.3333333333333333,
513
- "#9c179e"
514
- ],
515
- [
516
- 0.4444444444444444,
517
- "#bd3786"
518
- ],
519
- [
520
- 0.5555555555555556,
521
- "#d8576b"
522
- ],
523
- [
524
- 0.6666666666666666,
525
- "#ed7953"
526
- ],
527
- [
528
- 0.7777777777777778,
529
- "#fb9f3a"
530
- ],
531
- [
532
- 0.8888888888888888,
533
- "#fdca26"
534
- ],
535
- [
536
- 1,
537
- "#f0f921"
538
- ]
539
- ],
540
- "type": "histogram2dcontour"
541
- }
542
- ],
543
- "mesh3d": [
544
- {
545
- "colorbar": {
546
- "outlinewidth": 0,
547
- "ticks": ""
548
- },
549
- "type": "mesh3d"
550
- }
551
- ],
552
- "parcoords": [
553
- {
554
- "line": {
555
- "colorbar": {
556
- "outlinewidth": 0,
557
- "ticks": ""
558
- }
559
- },
560
- "type": "parcoords"
561
- }
562
- ],
563
- "pie": [
564
- {
565
- "automargin": true,
566
- "type": "pie"
567
- }
568
- ],
569
- "scatter": [
570
- {
571
- "fillpattern": {
572
- "fillmode": "overlay",
573
- "size": 10,
574
- "solidity": 0.2
575
- },
576
- "type": "scatter"
577
- }
578
- ],
579
- "scatter3d": [
580
- {
581
- "line": {
582
- "colorbar": {
583
- "outlinewidth": 0,
584
- "ticks": ""
585
- }
586
- },
587
- "marker": {
588
- "colorbar": {
589
- "outlinewidth": 0,
590
- "ticks": ""
591
- }
592
- },
593
- "type": "scatter3d"
594
- }
595
- ],
596
- "scattercarpet": [
597
- {
598
- "marker": {
599
- "colorbar": {
600
- "outlinewidth": 0,
601
- "ticks": ""
602
- }
603
- },
604
- "type": "scattercarpet"
605
- }
606
- ],
607
- "scattergeo": [
608
- {
609
- "marker": {
610
- "colorbar": {
611
- "outlinewidth": 0,
612
- "ticks": ""
613
- }
614
- },
615
- "type": "scattergeo"
616
- }
617
- ],
618
- "scattergl": [
619
- {
620
- "marker": {
621
- "colorbar": {
622
- "outlinewidth": 0,
623
- "ticks": ""
624
- }
625
- },
626
- "type": "scattergl"
627
- }
628
- ],
629
- "scattermapbox": [
630
- {
631
- "marker": {
632
- "colorbar": {
633
- "outlinewidth": 0,
634
- "ticks": ""
635
- }
636
- },
637
- "type": "scattermapbox"
638
- }
639
- ],
640
- "scatterpolar": [
641
- {
642
- "marker": {
643
- "colorbar": {
644
- "outlinewidth": 0,
645
- "ticks": ""
646
- }
647
- },
648
- "type": "scatterpolar"
649
- }
650
- ],
651
- "scatterpolargl": [
652
- {
653
- "marker": {
654
- "colorbar": {
655
- "outlinewidth": 0,
656
- "ticks": ""
657
- }
658
- },
659
- "type": "scatterpolargl"
660
- }
661
- ],
662
- "scatterternary": [
663
- {
664
- "marker": {
665
- "colorbar": {
666
- "outlinewidth": 0,
667
- "ticks": ""
668
- }
669
- },
670
- "type": "scatterternary"
671
- }
672
- ],
673
- "surface": [
674
- {
675
- "colorbar": {
676
- "outlinewidth": 0,
677
- "ticks": ""
678
- },
679
- "colorscale": [
680
- [
681
- 0,
682
- "#0d0887"
683
- ],
684
- [
685
- 0.1111111111111111,
686
- "#46039f"
687
- ],
688
- [
689
- 0.2222222222222222,
690
- "#7201a8"
691
- ],
692
- [
693
- 0.3333333333333333,
694
- "#9c179e"
695
- ],
696
- [
697
- 0.4444444444444444,
698
- "#bd3786"
699
- ],
700
- [
701
- 0.5555555555555556,
702
- "#d8576b"
703
- ],
704
- [
705
- 0.6666666666666666,
706
- "#ed7953"
707
- ],
708
- [
709
- 0.7777777777777778,
710
- "#fb9f3a"
711
- ],
712
- [
713
- 0.8888888888888888,
714
- "#fdca26"
715
- ],
716
- [
717
- 1,
718
- "#f0f921"
719
- ]
720
- ],
721
- "type": "surface"
722
- }
723
- ],
724
- "table": [
725
- {
726
- "cells": {
727
- "fill": {
728
- "color": "#EBF0F8"
729
- },
730
- "line": {
731
- "color": "white"
732
- }
733
- },
734
- "header": {
735
- "fill": {
736
- "color": "#C8D4E3"
737
- },
738
- "line": {
739
- "color": "white"
740
- }
741
- },
742
- "type": "table"
743
- }
744
- ]
745
- },
746
- "layout": {
747
- "annotationdefaults": {
748
- "arrowcolor": "#2a3f5f",
749
- "arrowhead": 0,
750
- "arrowwidth": 1
751
- },
752
- "autotypenumbers": "strict",
753
- "coloraxis": {
754
- "colorbar": {
755
- "outlinewidth": 0,
756
- "ticks": ""
757
- }
758
- },
759
- "colorscale": {
760
- "diverging": [
761
- [
762
- 0,
763
- "#8e0152"
764
- ],
765
- [
766
- 0.1,
767
- "#c51b7d"
768
- ],
769
- [
770
- 0.2,
771
- "#de77ae"
772
- ],
773
- [
774
- 0.3,
775
- "#f1b6da"
776
- ],
777
- [
778
- 0.4,
779
- "#fde0ef"
780
- ],
781
- [
782
- 0.5,
783
- "#f7f7f7"
784
- ],
785
- [
786
- 0.6,
787
- "#e6f5d0"
788
- ],
789
- [
790
- 0.7,
791
- "#b8e186"
792
- ],
793
- [
794
- 0.8,
795
- "#7fbc41"
796
- ],
797
- [
798
- 0.9,
799
- "#4d9221"
800
- ],
801
- [
802
- 1,
803
- "#276419"
804
- ]
805
- ],
806
- "sequential": [
807
- [
808
- 0,
809
- "#0d0887"
810
- ],
811
- [
812
- 0.1111111111111111,
813
- "#46039f"
814
- ],
815
- [
816
- 0.2222222222222222,
817
- "#7201a8"
818
- ],
819
- [
820
- 0.3333333333333333,
821
- "#9c179e"
822
- ],
823
- [
824
- 0.4444444444444444,
825
- "#bd3786"
826
- ],
827
- [
828
- 0.5555555555555556,
829
- "#d8576b"
830
- ],
831
- [
832
- 0.6666666666666666,
833
- "#ed7953"
834
- ],
835
- [
836
- 0.7777777777777778,
837
- "#fb9f3a"
838
- ],
839
- [
840
- 0.8888888888888888,
841
- "#fdca26"
842
- ],
843
- [
844
- 1,
845
- "#f0f921"
846
- ]
847
- ],
848
- "sequentialminus": [
849
- [
850
- 0,
851
- "#0d0887"
852
- ],
853
- [
854
- 0.1111111111111111,
855
- "#46039f"
856
- ],
857
- [
858
- 0.2222222222222222,
859
- "#7201a8"
860
- ],
861
- [
862
- 0.3333333333333333,
863
- "#9c179e"
864
- ],
865
- [
866
- 0.4444444444444444,
867
- "#bd3786"
868
- ],
869
- [
870
- 0.5555555555555556,
871
- "#d8576b"
872
- ],
873
- [
874
- 0.6666666666666666,
875
- "#ed7953"
876
- ],
877
- [
878
- 0.7777777777777778,
879
- "#fb9f3a"
880
- ],
881
- [
882
- 0.8888888888888888,
883
- "#fdca26"
884
- ],
885
- [
886
- 1,
887
- "#f0f921"
888
- ]
889
- ]
890
- },
891
- "colorway": [
892
- "#636efa",
893
- "#EF553B",
894
- "#00cc96",
895
- "#ab63fa",
896
- "#FFA15A",
897
- "#19d3f3",
898
- "#FF6692",
899
- "#B6E880",
900
- "#FF97FF",
901
- "#FECB52"
902
- ],
903
- "font": {
904
- "color": "#2a3f5f"
905
- },
906
- "geo": {
907
- "bgcolor": "white",
908
- "lakecolor": "white",
909
- "landcolor": "#E5ECF6",
910
- "showlakes": true,
911
- "showland": true,
912
- "subunitcolor": "white"
913
- },
914
- "hoverlabel": {
915
- "align": "left"
916
- },
917
- "hovermode": "closest",
918
- "mapbox": {
919
- "style": "light"
920
- },
921
- "paper_bgcolor": "white",
922
- "plot_bgcolor": "#E5ECF6",
923
- "polar": {
924
- "angularaxis": {
925
- "gridcolor": "white",
926
- "linecolor": "white",
927
- "ticks": ""
928
- },
929
- "bgcolor": "#E5ECF6",
930
- "radialaxis": {
931
- "gridcolor": "white",
932
- "linecolor": "white",
933
- "ticks": ""
934
- }
935
- },
936
- "scene": {
937
- "xaxis": {
938
- "backgroundcolor": "#E5ECF6",
939
- "gridcolor": "white",
940
- "gridwidth": 2,
941
- "linecolor": "white",
942
- "showbackground": true,
943
- "ticks": "",
944
- "zerolinecolor": "white"
945
- },
946
- "yaxis": {
947
- "backgroundcolor": "#E5ECF6",
948
- "gridcolor": "white",
949
- "gridwidth": 2,
950
- "linecolor": "white",
951
- "showbackground": true,
952
- "ticks": "",
953
- "zerolinecolor": "white"
954
- },
955
- "zaxis": {
956
- "backgroundcolor": "#E5ECF6",
957
- "gridcolor": "white",
958
- "gridwidth": 2,
959
- "linecolor": "white",
960
- "showbackground": true,
961
- "ticks": "",
962
- "zerolinecolor": "white"
963
- }
964
- },
965
- "shapedefaults": {
966
- "line": {
967
- "color": "#2a3f5f"
968
- }
969
- },
970
- "ternary": {
971
- "aaxis": {
972
- "gridcolor": "white",
973
- "linecolor": "white",
974
- "ticks": ""
975
- },
976
- "baxis": {
977
- "gridcolor": "white",
978
- "linecolor": "white",
979
- "ticks": ""
980
- },
981
- "bgcolor": "#E5ECF6",
982
- "caxis": {
983
- "gridcolor": "white",
984
- "linecolor": "white",
985
- "ticks": ""
986
- }
987
- },
988
- "title": {
989
- "x": 0.05
990
- },
991
- "xaxis": {
992
- "automargin": true,
993
- "gridcolor": "white",
994
- "linecolor": "white",
995
- "ticks": "",
996
- "title": {
997
- "standoff": 15
998
- },
999
- "zerolinecolor": "white",
1000
- "zerolinewidth": 2
1001
- },
1002
- "yaxis": {
1003
- "automargin": true,
1004
- "gridcolor": "white",
1005
- "linecolor": "white",
1006
- "ticks": "",
1007
- "title": {
1008
- "standoff": 15
1009
- },
1010
- "zerolinecolor": "white",
1011
- "zerolinewidth": 2
1012
- }
1013
- }
1014
- },
1015
- "xaxis": {
1016
- "anchor": "y",
1017
- "domain": [
1018
- 0,
1019
- 1
1020
- ],
1021
- "title": {
1022
- "text": "index"
1023
- }
1024
- },
1025
- "yaxis": {
1026
- "anchor": "x",
1027
- "domain": [
1028
- 0,
1029
- 1
1030
- ],
1031
- "title": {
1032
- "text": "sa_temp"
1033
- }
1034
- }
1035
- }
1036
- },
1037
- "text/html": [
1038
- "<div> <script type=\"text/javascript\">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>\n",
1039
- " <script charset=\"utf-8\" src=\"https://cdn.plot.ly/plotly-2.30.0.min.js\"></script> <div id=\"c95365dc-5cdc-4348-87ed-a350f4465ed0\" class=\"plotly-graph-div\" style=\"height:100%; width:100%;\"></div> <script type=\"text/javascript\"> window.PLOTLYENV=window.PLOTLYENV || {}; if (document.getElementById(\"c95365dc-5cdc-4348-87ed-a350f4465ed0\")) { Plotly.newPlot( \"c95365dc-5cdc-4348-87ed-a350f4465ed0\", [{\"hovertemplate\":\"index=%{x}\\u003cbr\\u003esa_temp=%{y}\\u003cextra\\u003e\\u003c\\u002fextra\\u003e\",\"legendgroup\":\"\",\"line\":{\"color\":\"#636efa\",\"dash\":\"solid\"},\"marker\":{\"symbol\":\"circle\"},\"mode\":\"lines\",\"name\":\"\",\"orientation\":\"v\",\"showlegend\":false,\"x\":[],\"xaxis\":\"x\",\"y\":[],\"yaxis\":\"y\",\"type\":\"scatter\"}], {\"template\":{\"data\":{\"histogram2dcontour\":[{\"type\":\"histogram2dcontour\",\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"},\"colorscale\":[[0.0,\"#0d0887\"],[0.1111111111111111,\"#46039f\"],[0.2222222222222222,\"#7201a8\"],[0.3333333333333333,\"#9c179e\"],[0.4444444444444444,\"#bd3786\"],[0.5555555555555556,\"#d8576b\"],[0.6666666666666666,\"#ed7953\"],[0.7777777777777778,\"#fb9f3a\"],[0.8888888888888888,\"#fdca26\"],[1.0,\"#f0f921\"]]}],\"choropleth\":[{\"type\":\"choropleth\",\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}}],\"histogram2d\":[{\"type\":\"histogram2d\",\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"},\"colorscale\":[[0.0,\"#0d0887\"],[0.1111111111111111,\"#46039f\"],[0.2222222222222222,\"#7201a8\"],[0.3333333333333333,\"#9c179e\"],[0.4444444444444444,\"#bd3786\"],[0.5555555555555556,\"#d8576b\"],[0.6666666666666666,\"#ed7953\"],[0.7777777777777778,\"#fb9f3a\"],[0.8888888888888888,\"#fdca26\"],[1.0,\"#f0f921\"]]}],\"heatmap\":[{\"type\":\"heatmap\",\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"},\"colorscale\":[[0.0,\"#0d0887\"],[0.1111111111111111,\"#46039f\"],[0.2222222222222222,\"#7201a8\"],[0.3333333333333333,\"#9c179e\"],[0.4444444444444444,\"#bd3786\"],[0.5555555555555556,\"#d8576b\"],[0.6666666666666666,\"#ed7953\"],[0.7777777777777778,\"#fb9f3a\"],[0.8888888888888888,\"#fdca26\"],[1.0,\"#f0f921\"]]}],\"heatmapgl\":[{\"type\":\"heatmapgl\",\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"},\"colorscale\":[[0.0,\"#0d0887\"],[0.1111111111111111,\"#46039f\"],[0.2222222222222222,\"#7201a8\"],[0.3333333333333333,\"#9c179e\"],[0.4444444444444444,\"#bd3786\"],[0.5555555555555556,\"#d8576b\"],[0.6666666666666666,\"#ed7953\"],[0.7777777777777778,\"#fb9f3a\"],[0.8888888888888888,\"#fdca26\"],[1.0,\"#f0f921\"]]}],\"contourcarpet\":[{\"type\":\"contourcarpet\",\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}}],\"contour\":[{\"type\":\"contour\",\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"},\"colorscale\":[[0.0,\"#0d0887\"],[0.1111111111111111,\"#46039f\"],[0.2222222222222222,\"#7201a8\"],[0.3333333333333333,\"#9c179e\"],[0.4444444444444444,\"#bd3786\"],[0.5555555555555556,\"#d8576b\"],[0.6666666666666666,\"#ed7953\"],[0.7777777777777778,\"#fb9f3a\"],[0.8888888888888888,\"#fdca26\"],[1.0,\"#f0f921\"]]}],\"surface\":[{\"type\":\"surface\",\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"},\"colorscale\":[[0.0,\"#0d0887\"],[0.1111111111111111,\"#46039f\"],[0.2222222222222222,\"#7201a8\"],[0.3333333333333333,\"#9c179e\"],[0.4444444444444444,\"#bd3786\"],[0.5555555555555556,\"#d8576b\"],[0.6666666666666666,\"#ed7953\"],[0.7777777777777778,\"#fb9f3a\"],[0.8888888888888888,\"#fdca26\"],[1.0,\"#f0f921\"]]}],\"mesh3d\":[{\"type\":\"mesh3d\",\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}}],\"scatter\":[{\"fillpattern\":{\"fillmode\":\"overlay\",\"size\":10,\"solidity\":0.2},\"type\":\"scatter\"}],\"parcoords\":[{\"type\":\"parcoords\",\"line\":{\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}}}],\"scatterpolargl\":[{\"type\":\"scatterpolargl\",\"marker\":{\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}}}],\"bar\":[{\"error_x\":{\"color\":\"#2a3f5f\"},\"error_y\":{\"color\":\"#2a3f5f\"},\"marker\":{\"line\":{\"color\":\"#E5ECF6\",\"width\":0.5},\"pattern\":{\"fillmode\":\"overlay\",\"size\":10,\"solidity\":0.2}},\"type\":\"bar\"}],\"scattergeo\":[{\"type\":\"scattergeo\",\"marker\":{\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}}}],\"scatterpolar\":[{\"type\":\"scatterpolar\",\"marker\":{\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}}}],\"histogram\":[{\"marker\":{\"pattern\":{\"fillmode\":\"overlay\",\"size\":10,\"solidity\":0.2}},\"type\":\"histogram\"}],\"scattergl\":[{\"type\":\"scattergl\",\"marker\":{\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}}}],\"scatter3d\":[{\"type\":\"scatter3d\",\"line\":{\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}},\"marker\":{\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}}}],\"scattermapbox\":[{\"type\":\"scattermapbox\",\"marker\":{\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}}}],\"scatterternary\":[{\"type\":\"scatterternary\",\"marker\":{\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}}}],\"scattercarpet\":[{\"type\":\"scattercarpet\",\"marker\":{\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}}}],\"carpet\":[{\"aaxis\":{\"endlinecolor\":\"#2a3f5f\",\"gridcolor\":\"white\",\"linecolor\":\"white\",\"minorgridcolor\":\"white\",\"startlinecolor\":\"#2a3f5f\"},\"baxis\":{\"endlinecolor\":\"#2a3f5f\",\"gridcolor\":\"white\",\"linecolor\":\"white\",\"minorgridcolor\":\"white\",\"startlinecolor\":\"#2a3f5f\"},\"type\":\"carpet\"}],\"table\":[{\"cells\":{\"fill\":{\"color\":\"#EBF0F8\"},\"line\":{\"color\":\"white\"}},\"header\":{\"fill\":{\"color\":\"#C8D4E3\"},\"line\":{\"color\":\"white\"}},\"type\":\"table\"}],\"barpolar\":[{\"marker\":{\"line\":{\"color\":\"#E5ECF6\",\"width\":0.5},\"pattern\":{\"fillmode\":\"overlay\",\"size\":10,\"solidity\":0.2}},\"type\":\"barpolar\"}],\"pie\":[{\"automargin\":true,\"type\":\"pie\"}]},\"layout\":{\"autotypenumbers\":\"strict\",\"colorway\":[\"#636efa\",\"#EF553B\",\"#00cc96\",\"#ab63fa\",\"#FFA15A\",\"#19d3f3\",\"#FF6692\",\"#B6E880\",\"#FF97FF\",\"#FECB52\"],\"font\":{\"color\":\"#2a3f5f\"},\"hovermode\":\"closest\",\"hoverlabel\":{\"align\":\"left\"},\"paper_bgcolor\":\"white\",\"plot_bgcolor\":\"#E5ECF6\",\"polar\":{\"bgcolor\":\"#E5ECF6\",\"angularaxis\":{\"gridcolor\":\"white\",\"linecolor\":\"white\",\"ticks\":\"\"},\"radialaxis\":{\"gridcolor\":\"white\",\"linecolor\":\"white\",\"ticks\":\"\"}},\"ternary\":{\"bgcolor\":\"#E5ECF6\",\"aaxis\":{\"gridcolor\":\"white\",\"linecolor\":\"white\",\"ticks\":\"\"},\"baxis\":{\"gridcolor\":\"white\",\"linecolor\":\"white\",\"ticks\":\"\"},\"caxis\":{\"gridcolor\":\"white\",\"linecolor\":\"white\",\"ticks\":\"\"}},\"coloraxis\":{\"colorbar\":{\"outlinewidth\":0,\"ticks\":\"\"}},\"colorscale\":{\"sequential\":[[0.0,\"#0d0887\"],[0.1111111111111111,\"#46039f\"],[0.2222222222222222,\"#7201a8\"],[0.3333333333333333,\"#9c179e\"],[0.4444444444444444,\"#bd3786\"],[0.5555555555555556,\"#d8576b\"],[0.6666666666666666,\"#ed7953\"],[0.7777777777777778,\"#fb9f3a\"],[0.8888888888888888,\"#fdca26\"],[1.0,\"#f0f921\"]],\"sequentialminus\":[[0.0,\"#0d0887\"],[0.1111111111111111,\"#46039f\"],[0.2222222222222222,\"#7201a8\"],[0.3333333333333333,\"#9c179e\"],[0.4444444444444444,\"#bd3786\"],[0.5555555555555556,\"#d8576b\"],[0.6666666666666666,\"#ed7953\"],[0.7777777777777778,\"#fb9f3a\"],[0.8888888888888888,\"#fdca26\"],[1.0,\"#f0f921\"]],\"diverging\":[[0,\"#8e0152\"],[0.1,\"#c51b7d\"],[0.2,\"#de77ae\"],[0.3,\"#f1b6da\"],[0.4,\"#fde0ef\"],[0.5,\"#f7f7f7\"],[0.6,\"#e6f5d0\"],[0.7,\"#b8e186\"],[0.8,\"#7fbc41\"],[0.9,\"#4d9221\"],[1,\"#276419\"]]},\"xaxis\":{\"gridcolor\":\"white\",\"linecolor\":\"white\",\"ticks\":\"\",\"title\":{\"standoff\":15},\"zerolinecolor\":\"white\",\"automargin\":true,\"zerolinewidth\":2},\"yaxis\":{\"gridcolor\":\"white\",\"linecolor\":\"white\",\"ticks\":\"\",\"title\":{\"standoff\":15},\"zerolinecolor\":\"white\",\"automargin\":true,\"zerolinewidth\":2},\"scene\":{\"xaxis\":{\"backgroundcolor\":\"#E5ECF6\",\"gridcolor\":\"white\",\"linecolor\":\"white\",\"showbackground\":true,\"ticks\":\"\",\"zerolinecolor\":\"white\",\"gridwidth\":2},\"yaxis\":{\"backgroundcolor\":\"#E5ECF6\",\"gridcolor\":\"white\",\"linecolor\":\"white\",\"showbackground\":true,\"ticks\":\"\",\"zerolinecolor\":\"white\",\"gridwidth\":2},\"zaxis\":{\"backgroundcolor\":\"#E5ECF6\",\"gridcolor\":\"white\",\"linecolor\":\"white\",\"showbackground\":true,\"ticks\":\"\",\"zerolinecolor\":\"white\",\"gridwidth\":2}},\"shapedefaults\":{\"line\":{\"color\":\"#2a3f5f\"}},\"annotationdefaults\":{\"arrowcolor\":\"#2a3f5f\",\"arrowhead\":0,\"arrowwidth\":1},\"geo\":{\"bgcolor\":\"white\",\"landcolor\":\"#E5ECF6\",\"subunitcolor\":\"white\",\"showland\":true,\"showlakes\":true,\"lakecolor\":\"white\"},\"title\":{\"x\":0.05},\"mapbox\":{\"style\":\"light\"}}},\"xaxis\":{\"anchor\":\"y\",\"domain\":[0.0,1.0],\"title\":{\"text\":\"index\"}},\"yaxis\":{\"anchor\":\"x\",\"domain\":[0.0,1.0],\"title\":{\"text\":\"sa_temp\"}},\"legend\":{\"tracegroupgap\":0},\"margin\":{\"t\":60}}, {\"responsive\": true} ) }; </script> </div>"
1040
- ],
1041
- "text/plain": [
1042
- "Figure({\n",
1043
- " 'data': [{'hovertemplate': 'index=%{x}<br>sa_temp=%{y}<extra></extra>',\n",
1044
- " 'legendgroup': '',\n",
1045
- " 'line': {'color': '#636efa', 'dash': 'solid'},\n",
1046
- " 'marker': {'symbol': 'circle'},\n",
1047
- " 'mode': 'lines',\n",
1048
- " 'name': '',\n",
1049
- " 'orientation': 'v',\n",
1050
- " 'showlegend': False,\n",
1051
- " 'type': 'scatter',\n",
1052
- " 'x': array([], dtype=int64),\n",
1053
- " 'xaxis': 'x',\n",
1054
- " 'y': array([], dtype=object),\n",
1055
- " 'yaxis': 'y'}],\n",
1056
- " 'layout': {'legend': {'tracegroupgap': 0},\n",
1057
- " 'margin': {'t': 60},\n",
1058
- " 'template': '...',\n",
1059
- " 'xaxis': {'anchor': 'y', 'domain': [0.0, 1.0], 'title': {'text': 'index'}},\n",
1060
- " 'yaxis': {'anchor': 'x', 'domain': [0.0, 1.0], 'title': {'text': 'sa_temp'}}}\n",
1061
- "})"
1062
- ]
1063
- },
1064
- "execution_count": 4,
1065
- "metadata": {},
1066
- "output_type": "execute_result"
1067
- }
1068
- ],
1069
- "source": []
1070
- },
1071
- {
1072
- "cell_type": "code",
1073
- "execution_count": null,
1074
- "metadata": {},
1075
- "outputs": [],
1076
- "source": []
1077
- }
1078
- ],
1079
- "metadata": {
1080
- "kernelspec": {
1081
- "display_name": "smartbuilding",
1082
- "language": "python",
1083
- "name": "python3"
1084
- },
1085
- "language_info": {
1086
- "codemirror_mode": {
1087
- "name": "ipython",
1088
- "version": 3
1089
- },
1090
- "file_extension": ".py",
1091
- "mimetype": "text/x-python",
1092
- "name": "python",
1093
- "nbconvert_exporter": "python",
1094
- "pygments_lexer": "ipython3",
1095
- "version": "3.11.8"
1096
- }
1097
- },
1098
- "nbformat": 4,
1099
- "nbformat_minor": 2
1100
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/__init__.py ADDED
File without changes
src/main.py CHANGED
@@ -9,8 +9,11 @@ import paho.mqtt.client as mqtt
9
 
10
 
11
  def main():
12
- rtu_data_pipeline = RTUPipeline(scaler1_path="src/rtu/models/scaler_rtu_1_2.pkl",scaler2_path="src/rtu/models/scaler_rtu_3_4.pkl")
13
- #RTU - 1, 2
 
 
 
14
  rtu_anomalizer1 = RTUAnomalizer1(
15
  prediction_model_path="src/rtu/models/lstm_2rtu_smooth_04.keras",
16
  clustering_model_paths=[
@@ -24,7 +27,8 @@ def main():
24
  num_inputs=rtu_data_pipeline.num_inputs,
25
  num_outputs=rtu_data_pipeline.num_outputs,
26
  )
27
- #RTU - 3,4
 
28
  rtu_anomalizer2 = RTUAnomalizer2(
29
  prediction_model_path="src/rtu/models/lstm_2rtu_smooth_03.keras",
30
  clustering_model_paths=[
@@ -52,9 +56,6 @@ def main():
52
 
53
  # print(len(vav_pipeline.output_col_names))
54
 
55
-
56
-
57
-
58
  def on_message(client, userdata, message):
59
  df_new_vav, df_trans_vav = vav_pipeline.fit(message)
60
  vav_anomalizer.num_inputs = vav_pipeline.num_inputs
@@ -63,12 +64,21 @@ def main():
63
  out_vav = vav_anomalizer.pipeline(
64
  df_new_vav, df_trans_vav, vav_pipeline.scaler
65
  )
66
-
67
- df_new1, df_trans1, df_new2, df_trans2 = rtu_data_pipeline.fit(message)
68
- if not df_new1 is None and not df_trans1 is None and not df_new2 is None and not df_trans2 is None:
69
- out1,out2,out3,out4 = rtu_anomalizer1.pipeline(df_new1, df_trans1, rtu_data_pipeline.scaler1)
70
- out5,out6,out7,out8 = rtu_anomalizer2.pipeline(df_new2, df_trans2, rtu_data_pipeline.scaler2)
71
- #print(out2)
 
 
 
 
 
 
 
 
 
72
 
73
  broker_address = "localhost"
74
  broker_port = 1883
 
9
 
10
 
11
  def main():
12
+ rtu_data_pipeline = RTUPipeline(
13
+ scaler1_path="src/rtu/models/scaler_rtu_1_2.pkl",
14
+ scaler2_path="src/rtu/models/scaler_rtu_3_4.pkl",
15
+ )
16
+ # RTU - 1, 2
17
  rtu_anomalizer1 = RTUAnomalizer1(
18
  prediction_model_path="src/rtu/models/lstm_2rtu_smooth_04.keras",
19
  clustering_model_paths=[
 
27
  num_inputs=rtu_data_pipeline.num_inputs,
28
  num_outputs=rtu_data_pipeline.num_outputs,
29
  )
30
+ print(rtu_anomalizer1.kmeans_models)
31
+ # RTU - 3,4
32
  rtu_anomalizer2 = RTUAnomalizer2(
33
  prediction_model_path="src/rtu/models/lstm_2rtu_smooth_03.keras",
34
  clustering_model_paths=[
 
56
 
57
  # print(len(vav_pipeline.output_col_names))
58
 
 
 
 
59
  def on_message(client, userdata, message):
60
  df_new_vav, df_trans_vav = vav_pipeline.fit(message)
61
  vav_anomalizer.num_inputs = vav_pipeline.num_inputs
 
64
  out_vav = vav_anomalizer.pipeline(
65
  df_new_vav, df_trans_vav, vav_pipeline.scaler
66
  )
67
+
68
+ df_new1, df_trans1, df_new2, df_trans2 = rtu_data_pipeline.fit(message)
69
+ if (
70
+ not df_new1 is None
71
+ and not df_trans1 is None
72
+ and not df_new2 is None
73
+ and not df_trans2 is None
74
+ ):
75
+ out1, out2, out3, out4 = rtu_anomalizer1.pipeline(
76
+ df_new1, df_trans1, rtu_data_pipeline.scaler1
77
+ )
78
+ out5, out6, out7, out8 = rtu_anomalizer2.pipeline(
79
+ df_new2, df_trans2, rtu_data_pipeline.scaler2
80
+ )
81
+ # print(out2)
82
 
83
  broker_address = "localhost"
84
  broker_port = 1883
src/rtu/RTUAnomalizer1.py CHANGED
@@ -8,10 +8,6 @@ class RTUAnomalizer1:
8
  Class for performing anomaly detection on RTU (Roof Top Unit) data.
9
  """
10
 
11
- model = None
12
- kmeans_models = []
13
- pca_models = []
14
-
15
  def __init__(
16
  self,
17
  prediction_model_path=None,
@@ -29,12 +25,24 @@ class RTUAnomalizer1:
29
  num_inputs (int): Number of input features.
30
  num_outputs (int): Number of output features.
31
  """
 
 
 
 
32
  self.num_inputs = num_inputs
33
  self.num_outputs = num_outputs
34
- if prediction_model_path is not None and clustering_model_paths is not None and pca_model_paths is not None:
35
- self.load_models(prediction_model_path, clustering_model_paths, pca_model_paths)
36
-
37
- self.actual_list, self.pred_list, self.resid_list = self.initialize_lists()
 
 
 
 
 
 
 
 
38
 
39
  def initialize_lists(self, size=30):
40
  """
@@ -46,10 +54,18 @@ class RTUAnomalizer1:
46
  Returns:
47
  tuple: A tuple containing three lists initialized with zeros.
48
  """
49
- initial_values = [[0]*self.num_outputs] * size
50
- return initial_values.copy(), initial_values.copy(), initial_values.copy()
 
 
 
 
 
 
51
 
52
- def load_models(self, prediction_model_path, clustering_model_paths, pca_model_paths):
 
 
53
  """
54
  Load the prediction and clustering models.
55
 
@@ -61,7 +77,7 @@ class RTUAnomalizer1:
61
 
62
  for path in clustering_model_paths:
63
  self.kmeans_models.append(joblib.load(path))
64
-
65
  for path in pca_model_paths:
66
  self.pca_models.append(joblib.load(path))
67
 
@@ -75,7 +91,7 @@ class RTUAnomalizer1:
75
  Returns:
76
  array: Predicted values.
77
  """
78
- return self.model.predict(df_new,verbose=0)
79
 
80
  def calculate_residuals(self, df_trans, pred):
81
  """
@@ -161,14 +177,24 @@ class RTUAnomalizer1:
161
  array: Array of distances.
162
  """
163
  dist = []
 
164
  for i, model in enumerate(self.kmeans_models):
 
 
 
 
 
 
165
  dist.append(
166
  np.linalg.norm(
167
- self.pca_models[i].transform(resid[:, (i * 7) + 1 : (i * 7) + 8]) - model.cluster_centers_[0],
168
  ord=2,
169
  axis=1,
170
  )
171
  )
 
 
 
172
 
173
  return np.array(dist)
174
 
@@ -184,12 +210,11 @@ class RTUAnomalizer1:
184
  Returns:
185
  tuple: A tuple containing the lists of actual, predicted, and residual values, and the distances.
186
  """
187
-
188
  pred = self.predict(df_new)
189
  actual, resid = self.calculate_residuals(df_trans, pred)
190
  pred = self.resize_prediction(pred, df_trans)
191
  actual, pred = self.inverse_transform(scaler, pred, df_trans)
192
- actual_list, pred_list, resid_list = self.update_lists(
193
- actual, pred, resid)
194
  dist = self.calculate_distances(resid)
195
- return actual_list, pred_list, resid_list, dist
 
8
  Class for performing anomaly detection on RTU (Roof Top Unit) data.
9
  """
10
 
 
 
 
 
11
  def __init__(
12
  self,
13
  prediction_model_path=None,
 
25
  num_inputs (int): Number of input features.
26
  num_outputs (int): Number of output features.
27
  """
28
+ self.model = None
29
+ self.kmeans_models = []
30
+ self.pca_models = []
31
+
32
  self.num_inputs = num_inputs
33
  self.num_outputs = num_outputs
34
+ if (
35
+ prediction_model_path is not None
36
+ and clustering_model_paths is not None
37
+ and pca_model_paths is not None
38
+ ):
39
+ self.load_models(
40
+ prediction_model_path, clustering_model_paths, pca_model_paths
41
+ )
42
+
43
+ self.actual_list, self.pred_list, self.resid_list, self.resid_pca_list = (
44
+ self.initialize_lists()
45
+ )
46
 
47
  def initialize_lists(self, size=30):
48
  """
 
54
  Returns:
55
  tuple: A tuple containing three lists initialized with zeros.
56
  """
57
+ initial_values = [[0] * self.num_outputs] * size
58
+ initial_values1 = [[0] * 4] * size
59
+ return (
60
+ initial_values.copy(),
61
+ initial_values.copy(),
62
+ initial_values.copy(),
63
+ initial_values1.copy(),
64
+ )
65
 
66
+ def load_models(
67
+ self, prediction_model_path, clustering_model_paths, pca_model_paths
68
+ ):
69
  """
70
  Load the prediction and clustering models.
71
 
 
77
 
78
  for path in clustering_model_paths:
79
  self.kmeans_models.append(joblib.load(path))
80
+
81
  for path in pca_model_paths:
82
  self.pca_models.append(joblib.load(path))
83
 
 
91
  Returns:
92
  array: Predicted values.
93
  """
94
+ return self.model.predict(df_new, verbose=0)
95
 
96
  def calculate_residuals(self, df_trans, pred):
97
  """
 
177
  array: Array of distances.
178
  """
179
  dist = []
180
+ resid_pcas = []
181
  for i, model in enumerate(self.kmeans_models):
182
+ resid_pca = self.pca_models[i].transform(
183
+ resid[:, (i * 7) + 1 : (i * 7) + 8]
184
+ )
185
+
186
+ resid_pcas = resid_pcas + resid_pca.tolist()
187
+
188
  dist.append(
189
  np.linalg.norm(
190
+ resid_pca - model.cluster_centers_[0],
191
  ord=2,
192
  axis=1,
193
  )
194
  )
195
+ resid_pcas = np.array(resid_pcas).flatten().tolist()
196
+ self.resid_pca_list.pop(0)
197
+ self.resid_pca_list.append(resid_pcas)
198
 
199
  return np.array(dist)
200
 
 
210
  Returns:
211
  tuple: A tuple containing the lists of actual, predicted, and residual values, and the distances.
212
  """
213
+
214
  pred = self.predict(df_new)
215
  actual, resid = self.calculate_residuals(df_trans, pred)
216
  pred = self.resize_prediction(pred, df_trans)
217
  actual, pred = self.inverse_transform(scaler, pred, df_trans)
218
+ actual_list, pred_list, resid_list = self.update_lists(actual, pred, resid)
 
219
  dist = self.calculate_distances(resid)
220
+ return actual_list, pred_list, resid_list, self.resid_pca_list, dist
src/rtu/RTUPipeline.py CHANGED
@@ -7,10 +7,10 @@ import numpy as np
7
 
8
 
9
  class RTUPipeline:
10
- scaler1 = None # RTU 1,2
11
- scaler2 = None # RTU 3,4
12
 
13
- def __init__(self, rtus=[1, 2, 3, 4], scaler1_path=None,scaler2_path=None):
14
 
15
  outputs = [
16
  "sa_temp",
@@ -28,11 +28,11 @@ class RTUPipeline:
28
  for rtu in rtus:
29
  for output in outputs:
30
  self.output_col_names.append(f"rtu_00{rtu}_{output}")
31
-
32
  self.input_col_names = []
33
-
34
  for rtu in rtus:
35
- self.input_col_names.append(f"rtu_00{rtu}_sat_sp_tn")
36
 
37
  self.input_col_names = self.input_col_names + [
38
  "air_temp_set_1",
@@ -41,53 +41,50 @@ class RTUPipeline:
41
  "relative_humidity_set_1",
42
  "solar_radiation_set_1",
43
  ]
44
- self.num_inputs = len(self.input_col_names)-2
45
- self.num_outputs = len(self.output_col_names)-14
46
  self.column_names = self.output_col_names + self.input_col_names
47
 
48
  if scaler1_path:
49
  self.scaler1 = self.get_scaler(scaler1_path)
50
  if scaler2_path:
51
  self.scaler2 = self.get_scaler(scaler2_path)
52
-
53
  self.df = pd.DataFrame(columns=self.column_names)
54
 
55
  def get_scaler(self, scaler_path):
56
  return joblib.load(scaler_path)
57
 
58
- def get_window(self, df):
59
- len_df = len(df)
60
- print(len_df)
61
- if len_df > 30:
62
- df = df.rolling(window=30,min_periods=1).mean()
63
- return df[len_df - 31 : len_df].astype("float32")
64
- else:
65
- return None
66
-
67
  def transform_window(self, df_window):
68
- columns_scaler1 = [0] + list(range(1,15)) + [29,30] + list(range(33, 38))
69
- columns_scaler2 = [0] + list(range(15, 29)) + [31,32] + list(range(33, 38))
70
- return self.scaler1.transform(df_window.iloc[:, columns_scaler1]),self.scaler2.transform(df_window.iloc[:, columns_scaler2])
 
 
71
 
72
  def prepare_input(self, df_trans):
73
- return df_trans[:30, :].reshape((1, 30, len(self.column_names)-16))
74
-
75
- def extract_data_from_message(self, message):
76
- payload = json.loads(message.payload.decode())
77
 
 
 
78
  len_df = len(self.df)
 
 
 
 
 
 
 
 
 
 
 
79
 
80
- k = {}
81
- for col in self.column_names:
82
- k[col] = payload[col]
83
- self.df.loc[len_df] = k
84
- return self.df
85
 
86
- def fit(self, message):
87
- df = self.extract_data_from_message(message)
88
- df_window = self.get_window(df)
89
  if df_window is not None:
90
- df_trans1,df_trans2 = self.transform_window(df_window)
91
  df_new1 = self.prepare_input(df_trans1)
92
  df_new2 = self.prepare_input(df_trans2)
93
  else:
 
7
 
8
 
9
  class RTUPipeline:
10
+ scaler1 = None # RTU 1,2
11
+ scaler2 = None # RTU 3,4
12
 
13
+ def __init__(self, rtus=[1, 2, 3, 4], scaler1_path=None, scaler2_path=None):
14
 
15
  outputs = [
16
  "sa_temp",
 
28
  for rtu in rtus:
29
  for output in outputs:
30
  self.output_col_names.append(f"rtu_00{rtu}_{output}")
31
+
32
  self.input_col_names = []
33
+
34
  for rtu in rtus:
35
+ self.input_col_names.append(f"rtu_00{rtu}_sat_sp_tn")
36
 
37
  self.input_col_names = self.input_col_names + [
38
  "air_temp_set_1",
 
41
  "relative_humidity_set_1",
42
  "solar_radiation_set_1",
43
  ]
44
+ self.num_inputs = len(self.input_col_names) - 2
45
+ self.num_outputs = len(self.output_col_names) - 14
46
  self.column_names = self.output_col_names + self.input_col_names
47
 
48
  if scaler1_path:
49
  self.scaler1 = self.get_scaler(scaler1_path)
50
  if scaler2_path:
51
  self.scaler2 = self.get_scaler(scaler2_path)
52
+
53
  self.df = pd.DataFrame(columns=self.column_names)
54
 
55
  def get_scaler(self, scaler_path):
56
  return joblib.load(scaler_path)
57
 
 
 
 
 
 
 
 
 
 
58
  def transform_window(self, df_window):
59
+ columns_scaler1 = [0] + list(range(1, 15)) + [29, 30] + list(range(33, 38))
60
+ columns_scaler2 = [0] + list(range(15, 29)) + [31, 32] + list(range(33, 38))
61
+ return self.scaler1.transform(
62
+ df_window.iloc[:, columns_scaler1].values
63
+ ), self.scaler2.transform(df_window.iloc[:, columns_scaler2].values)
64
 
65
  def prepare_input(self, df_trans):
66
+ return df_trans[:30, :].reshape((1, 30, len(self.column_names) - 16))
 
 
 
67
 
68
+ def extract_data_from_message(self, df: pd.DataFrame):
69
+ df = df[self.column_names]
70
  len_df = len(self.df)
71
+ if len(self.df) != 0:
72
+ self.df = pd.concat([self.df, df], axis=0)
73
+ else:
74
+ self.df = df
75
+
76
+ if len_df > 31:
77
+ self.df = self.df.iloc[len_df - 31 : len_df]
78
+ self.df.loc[len_df] = self.df.mean()
79
+ return self.df
80
+ else:
81
+ return None
82
 
83
+ def fit(self, df: pd.DataFrame):
 
 
 
 
84
 
85
+ df_window = self.extract_data_from_message(df)
 
 
86
  if df_window is not None:
87
+ df_trans1, df_trans2 = self.transform_window(df_window)
88
  df_new1 = self.prepare_input(df_trans1)
89
  df_new2 = self.prepare_input(df_trans2)
90
  else: