# Author: Howard Webb # Data: 7/25/2017 # NOTE: this chart bins data into timestamp groups and uses multiple lines of data # This is a test of combining temp, humidity and dewpoint import pygal from couchdb import Server import json from DewPoint import getDewPoint import pandas as pd import math from datetime import datetime from MVP_Util import UTCStrToLDT #Use a view in CouchDB to get the data #use the first key for attribute type #order descending so when limit the results will get the latest at the top def getResults(): # header={"Content-Type":"application/json"} ts = datetime.utcnow().isoformat()[:19] payload={"selector":{"start_date.timestamp":{"$lt":ts},"status.status_qualifier":{"$eq": "Success"}, "activity_type":{"$eq":"Environment_Observation"}, "subject.name":{"$eq": "Air"}, "$or":[{"subject.attribute.name":"Humidity"}, {"subject.attribute.name":"Temperature"}]}, "fields":["start_date.timestamp", "subject.attribute.name", "subject.attribute.value"], "sort":[{"start_date.timestamp":"desc"}], "limit":250} server = Server() db_name = 'mvp_data' db = server[db_name] return db.find(payload) def cleanData(data, test=False): '''Flatten structure to three columns''' out=[] for row in data: # print row hold={} # bin the timestamp into 20 minute groups # get only the first 19 characters of the timestamp d=UTCStrToLDT(row["start_date"]["timestamp"]) d=d.replace(second=0, minute=int(math.floor(d.minute/20))) hold['timestamp']=str(d) hold["name"]=row["subject"]["attribute"]["name"] hold["value"]=row["subject"]["attribute"]["value"] out.append(hold) return out def buildChart(data, test=False): # Build dataframe from array df = pd.DataFrame.from_dict(data) df.set_index(['timestamp', 'name']) # Check for duplicates df = df.drop_duplicates(subset=['timestamp', 'name']) # Pivot the data by timestamp-bin with name groupings for columns df=df.pivot(index='timestamp', columns='name', values='value') if test: print df # print df # Fill missing data with dummy value df=df.fillna(11.1) #put in descending order d1=df.iloc[::-1] #pull off only 120 rows # d1 = d1[:][:120] # Reorder again d1=d1.iloc[::-1] # Make numeric (except for dates) - this does not seem to be working d1.apply(pd.to_numeric, errors='ignore') # print d1 # Calculate dew point dp=[] for idx, row in d1.iterrows(): # print row dp.append(getDewPoint(float(row['Temperature']), float(row['Humidity']))) d1['Dewpoint']=dp # Clear index so all are columns d3=d1.reset_index() if test: print d3 #build chart line_chart = pygal.Line(range=(0, 40)) line_chart.title = 'Temperature,Humidity and Dew Point' line_chart.y_title="Degrees C" line_chart.x_title="Timestamp (hover over to display date)" line_chart.x_labels = d3['timestamp'] line_chart.add('Humidity', [float(row) for row in d3['Humidity']], secondary=True) line_chart.add('Temperature',[float(row) for row in d3['Temperature']]) line_chart.add('Dewpoint', d3['Dewpoint']) line_chart.render_to_file('/home/pi/MVP/web/humidity_chart.svg') def getDewPointChart(test=False): data=getResults() r_cnt = len(data) if r_cnt>0: print "Records: ", r_cnt data=cleanData(data, test) buildChart(data, test) else: print "No Data" def test(): data=getResults() r_cnt = len(data) if r_cnt>0: print "Records: ", r_cnt data=cleanData(data, test) buildChart(data, test) else: print "No Data" if __name__=="__main__": getDewPointChart()