Stap 17: Ontwerp - grafiek
Gegevens is groot, maar de visualisaties zijn beter. In deze stap zullen wij onze opgeslagen geschiedenis manipuleren zodat we echt leuk grafieken kunt maken!
Eerste we beginnen door onze sensoren genoemd, zodat het makkelijker voor ons om bij te houden die is wat. Vervolgens zullen we kijken naar onze grafiek opties en gegevensindelingen. Ten slotte zullen we opnieuw formatteren van onze gegevens zodat het klaar voor graphing
De sensor namen configureren
Zijn geen leuk gegevens gemarkeerd als "sensor #1" dus ik voegde een 'config' pagina waar de app motor code welke sensor nummers bekijkt gegevens naar de database verzonden hebben en vervolgens kunt u een naam geven. Natuurlijk, wilt u dat de sensor op en verzenden van gegevens - eerst - voordat dit zal werken
Het configure scherm kijkt iets zoals naar de spiegelbeeld onder.
Deze code gebruikt krijg wanneer het echt POST moet gebruiken. Ik ben kinda oud en houd niet debuggen met POST so... yeah.
klasse configureren (webapp. RequestHandler):
def get(self):
# make de gebruiker inloggen als geen gebruikersnaam is opgegeven
als self.request.get('user'):
account = users. User(Self.Request.Get('user'))
anders:
zoniet users.get_current_user():
Self.Redirect(users.create_login_url(Self.Request.URI))
account = users.get_current_user()
Self.Response.out.write ("< html >< lichaam > Set up uw sensornode namen hier: < p >')
# find alle sensoren tot #10
Sensorset =]
voor ik in range(10):
c = db. GqlQuery ("SELECT * FROM Powerusage waar Auteur =: 1 en sensornum =: 2", users.get_current_user(), i)
als c.get():
Sensorset.Append(i)
Self.Response.out.write ("< vormen actie =" / config "methode ="get">")
voor sensor in sensorset:
naam = ""
currnamequery = db. GqlQuery ("SELECT * FROM Sensorname waar Auteur =: 1 en sensornum =: 2", users.get_current_user(), sensor)
currname = currnamequery.get()
# eerst zien als we het instellen van het!
als self.request.get('sensornum'+str(sensor)):
naam = self.request.get('sensornum'+str(sensor))
zoniet currname:
currname = Sensorname() # Maak een nieuwe vermelding
currname.sensornum = sensor
currname.Author = users.get_current_user()
currname.sensorname = naam
currname.put()
anders:
# we niet instelt het zo Haal huidige vermelding
Als currname:
naam = currname.sensorname
Self.Response.out.write ('Sensor #' + str(sensor) +': < input type = "text" name="sensornum'+str(sensor) +" "waarde =""+ naam +" ">< / tekst >< p >')
Self.Response.out.write ("" "< div >< input type =" submit"waarde ="Wijzig namen">< / div >
< / form >
< / body >
< / html > "" ")
Nu kunnen we meer nuttige gegevens in de geschiedenis-dump
Nu we zien kunnen dat Phil meestal te wijten aan onze energierekening is!
Google Visualizer
Dus hebben we gegevens en wij zou graag zien dat de geschiedenis van onze macht gebruik. Graphing gegevens is veel werk, en ik ben lui. Dus ik kijk online en vind dat Google heeft - ook - een visualization API! Dit betekent dat ik niet moet schrijven een heleboel grafische code, en kan gewoon aansluiten op hun systeem. Sweet!
OK checking out de galerij van beschikbare visualisaties, ben ik dol op dit één, de Geannoteerde Time Line
Merk op hoe u gemakkelijk kunt zien van de grafieken, scroll rond, in-en uitzoomen en ieder waarnemingspunt heet. Perfect voor het uitzetten van gegevens van de macht!
Gegevensopmaak
Theres een paar beperkingen aan hoe we de gegevens naar de visualisatie api en onze beste optie is JSon-gegevens. Voor zover ik vertellen kan, is JSON wat er gebeurde toen iedereen zei: "wow, XML is echt omvangrijk en verspilling". Hoe dan ook, als theres 4 lagen van kader en interpretatieve gegevens structions en uiteindelijk er een vrij makkelijk te gebruiken bibliotheek geschreven door het team van Google visualisaties die me was laat 'gewoon doen' met een enkele aanroep door de invoering van de gegevens in een python "dictionary" in een bepaald formaat.
Laat gaan door de code in secties, aangezien de functie vrij lang is
klasse JSONout(webapp. RequestHandler):
def get(self):
# make de gebruiker inloggen als geen gebruikersnaam is opgegeven
als self.request.get('user'):
account = users. User(Self.Request.Get('user'))
anders:
zoniet users.get_current_user():
Self.Redirect(users.create_login_url(Self.Request.URI))
account = users.get_current_user()
# Neem aan dat we 24 uur van gegevens wilt
historytimebegin = 24
als self.request.get('bhours'):
historytimebegin = int(self.request.get('bhours'))
# Neem aan dat we wilt gegevens vanaf 0 uur geleden
historytimeend = 0
als self.request.get('ehours'):
historytimeend = int(self.request.get('ehours'))
notatie van de gegevens van de # voor JSON geluk
datastore =]
matrices ColumnNames = ["datum"]
columnset = set(columnnames)
Beschrijving = {"datum": ("datetime", "Datum")}
# de namen van elke sensor, als geconfigureerd
sensornames = [geen] * 10
Eerst krijgen we van de gebruiker die we gonna worden de gegevens voor opzoeken. Dan hebben we twee variabelen voor het definiëren van de hoeveelheid gegevens te grijpen. Een "ehours" (einde uur) is en de andere is "bhours". Dus als je de laatste 5 uur wilde, bhours zou 5 en ehours 0 zou zijn. Als je wilde de 5 uur van de ene dag geleden, bhours zou 29 en ehours zou 24. datastore is waar we corall zullen alle gegevens. matrices ColumnNames en beschrijving worden de 'names' van elke kolom. We hebben altijd een datumkolom en een andere kolom voor elke sensor-stream. We hebben ook een aparte matrix naar de speciale sensor namen in de cache.
naar de volgende sectie! Hier is waar we eigenlijk grijpen gegevens uit de database. Nu app motor dit vervelende beperking heeft, kunt je alleen maar 1000 punten van de gegevens tegelijk dus wat ik doe is doorlopen het 12 uur op een moment. De definitieve datastore heeft alle punten maar zijn gemakkelijker op de database, veronderstel ik. Een ding dat is verwarrend misschien is elke kolom heeft een naam en een beschrijving. De naam is kort, zeggen "watts3" voor sensor #3, maar de omschrijving "Van Limor workbench" zou kunnen zijn. Ik weet niet eens herinneren dus misschien dat u het kunt uitzoeken op uw eigen schrijven van deze code?
# we meer dan 1000 datapoints, dankzij de gratis-app-engine beperking niet grijpen
# dat is ongeveer 3 sensoren van waarde in één dag
# dus we beperken zullen tot alleen grijpen 12 uren van gegevens op een moment, ongeveer 7 sensoren waard
terwijl (historytimebegin > historytimeend):
Als (historytimebegin - historytimeend) > 12:
timebegin = datetime.timedelta (uren = - historytimebegin)
timeend = datetime.timedelta (uren =-(historytimebegin-12))
historytimebegin-= 12
anders:
timebegin = datetime.timedelta (uren = - historytimebegin)
historytimebegin = 0
timeend = datetime.timedelta (uren = - historytimeend)
# Pak alle sensorgegevens voor dat stuk van de tijd
powerusages = db. GqlQuery ("Selecteer * uit Powerusage waar datum >: 1 en datum <: 2 en Auteur =: 3 ORDER BY datum", datetime.datetime.now () timebegin, (datetime.datetime.now) + timeend, account)
# sorteren hen in de juiste indeling en sensor namen uit die DB toevoegen als nog niet klaar
voor powerused in powerusages:
Coln = "watt" + str(powerused.sensornum)
post = {"datum": powerused.date.replace(tzinfo=utc).astimezone(est), coln: powerused.watt}
zoniet (coln in columnset):
ColumnNames.Append(Coln)
columnset = set(columnnames)
# de naam van de sensor, vinden als we kunnen
Als (len(sensornames) < powerused.sensornum) of (niet sensornames[powerused.sensornum]):
currnamequery = db. GqlQuery ("SELECT * FROM Sensorname waar Auteur =: 1 en sensornum =: 2", account, powerused.sensornum)
naam = currnamequery.get()
Als niet een naam geven:
sensornames[powerused.sensornum] = "sensor #"+str(powerused.sensornum)
anders:
sensornames[powerused.sensornum] = name.sensorname
beschrijving [coln] = ("nummer", sensornames[powerused.sensornum])
#self.response.out.write(sensornames)
# één post tegelijk toevoegen
datastore.Append(entry)
Ten slotte aan het einde van de lus, we noemen de magische functie die het woordenboek in JSON verandert, wikkel het in de juiste Google Visualization pakket, dan spuug het uit!
# OK alle gegevens is klaar om te gaan, uitprinten in JSON-formaat!
data_table = gviz_api. DataTable(description)
data_table. LoadData(datastore)
Self.Response.headers ['Content-Type'] = ' text/plain'
Self.Response.out.write (data_table. ToJSonResponse(columns_order=(columnnames),
order_by = "datum"))
Als u moest http://wattcher.appspot.com/visquery.json?user=adawattz bezoek zou het zoiets output:
google.visualization.Query.setResponse({'version':'0.5', 'reqId':'0', 'status':'OK', 'table': {cols: [{id:'date',label:'Date',type:'datetime'},{id:'watts1',label:'Limor',type:'number'},{id:'watts5',label:'Workbench',type:'number'},{id:'watts2',label:'Adafruit',type:'number'},{id:'watts4',label:'Phil2',type:'number'}],rows: [{c:[{v:new Date(2009,1,25,21,20,2)},{v:64.8332291619},,,{v:null}]},{c:[{v:new Date(2009,1,25,21,20,3)},,{v:230.122099757},,{v:null}]},{c:[{v:new Date(2009,1,25,21,20,3)} ,,, {v: 65.4923925044}, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,20,4)},,, {v: 48.6947643311}]}, {c: [{v: nieuwe Date(2009,1,25,21,25,3)},, {v: 228.409810208},, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,25,3)}, {v: 67.3574917331},,, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,25,3)},,, {v: 66.0046383897}, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,25,4)},,, {v: 47.3892235642}]}, {c: [{v: nieuwe Date(2009,1,25,21,30,2)}, {v: 84.9379517795},,, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,30,3)},,, {v: 99.7553490071}]} , {c: [{v: nieuwe Date(2009,1,25,21,30,5)},, {v: 229.73642288},, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,30,6)},,, {v: 66.6556291818}, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,35,2)},,, {v: 67.3146052998}, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,35,3)}, {v: 96.2322216676},,, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,35,3)},, {v: 226.678267688},, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,35,4)},,, {v: 158.428422765}]}, {c: [{v: nieuwe Date(2009,1,25,21,40,3)},, {v: 232.644574879},, {v: null}]} , {c: [{v: nieuwe Date(2009,1,25,21,40,4)},,, {v: 153.666193493}]}, {c: [{v: nieuwe Date(2009,1,25,21,40,6)},,, {v: 66.7874343225}, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,40,12)}, {v: 95.0019590395},,, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,40,21)}, {v: 95.0144043571},,, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,40,23)},,, {v: 66.8060307611}, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,45,2)},,, {v: 66.9814723201}, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,45,3)},, {v: 226.036818816},, {v: null}]} , {c: [{v: nieuwe Date(2009,1,25,21,45,3)}, {v: 99.2775581827},,, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,45,4)},,, {v: 154.261889366}]}, {c: [{v: nieuwe Date(2009,1,25,21,50,4)}, {v: 102.104642018},,, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,50,4)},,, {v: 155.441084531}]}, {c: [{v: nieuwe Date(2009,1,25,21,50,5)},,, {v: 67.0087146687}, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,50,5)},, {v: 230.678636915},, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,55,3)}, {v: 103.493297176},,, {v: null}]}, {c: [{v : nieuwe Date(2009,1,25,21,55,3)},,, {v: 151.309223916}]}, {c: [{v: nieuwe Date(2009,1,25,21,55,4)},,, {v: 66.9174858741}, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,21,55,4)},, {v: 227.765325835},, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,22,0,3)},,, {v: 67.0004310254}, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,22,0,3)},,, {v: 150.389989112}]}, {c: [{v: nieuwe Date(2009,1,25,22,0,3)},, {v: 230.892049553},, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,22,0,4)}, {v: 92.2432771363},,, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,22,15,3)} {v: 97.5910440774},,, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,22,15,3)},,, {v: 143.722595861}]}, {c: [{v: nieuwe Date(2009,1,25,22,15,4)},,, {v: 64.4898008851}, {v: null}]}, {c: [{v: nieuwe Date(2009,1,25,22,15,4)},,{v:222.357617868},,{v:null}]}]}});
Hoe dan ook, u kunt kinda de gegevens bekijken, er ook rekening mee zijn eigenlijk een functie-aanroep, dit spul is echt kinky!
Ga nu naar de Google Visualisaties Speeltuin en voer in die URL in de zandbak
En je ziet de visualisatie zelf pop uit! (dit is gewoon een scherm schot dus ga doen yerself wilt u prutsen)
OK gaan prutsen, bhours en ehours toevoegen en wijzigen
Het verpakken omhoog de visualisatie
OK zijn we bijna klaar. Nu we alleen moeten in feite grijpen de code uit de zandbak en maak het een subpagina in onze app engine... als volgt:
klasse visualiseren (webapp. RequestHandler):
def get(self):
# make de gebruiker inloggen als geen gebruikersnaam is opgegeven
als self.request.get('user'):
account = users. User(Self.Request.Get('user'))
anders:
zoniet users.get_current_user():
Self.Redirect(users.create_login_url(Self.Request.URI))
account = users.get_current_user()
historytimebegin = 24 # 24 uur nemen
als self.request.get('bhours'):
historytimebegin = int(self.request.get('bhours'))
historytimeend = 0 # veronderstellen 0 uur geleden
als self.request.get('ehours'):
historytimeend = int(self.request.get('ehours'))
# krijgen uit het eerste deel, headers,
Self.Response.out.write)
<! DOCTYPE html publiek "-//W3C//DTD XHTML 1.0 Strict / / nl" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >
< html xmlns = "http://www.w3.org/1999/xhtml" >
< head >
< meta http-equiv = "content-type" content = "text/html; charset = utf-8 "/ >
< titel > Google Visualization API steekproef < / title >
< script type = ' text/javascript' src = "http://www.google.com/jsapi" >< / script >
< script type = "text/javascript" >
Google.load ("visualization", "1", {pakketten: ["annotatedtimeline"]});
functie drawVisualizations() {}
)
# Maak onze visualisatie
Self.Response.out.write (nieuwe google.visualization.Query ("http://wattcher.appspot.com/visquery.json?user=+
account.email() +& bhours =+ str(historytimebegin) +") .send (
function(Response) {}
nieuwe google.visualization.AnnotatedTimeLine)
document.getElementById("visualization")).
draw(Response.getDataTable(), {"displayAnnotations": true});
});
)
Self.Response.out.write (}
google.setOnLoadCallback(drawVisualizations);
< / script >
< / head >
< body style = "lettertype-familie: Arial; rand: 0 geen;" >
< div id = "Visualisatie" style = "width: 800px; hoogte: 250px; " >< / div >
< / body >
< / html >)
Het eerste deel is vrij ongecompliceerd, krijgen de gebruikersnaam of login. Vervolgens zullen we veronderstellen dat de gebruiker wil 1 van de laatste dag van gegevens, dus stel bhours en ehours. Vervolgens afdrukken we letterlijk net uit de code die we gekopieerd uit Google Visualization zandbak, gedaan!
Viz Viz Viz
Het enige wat ik niet kon achterhalen hoe krijg ik 3 visualisaties tegelijk gaande is (laatste uur, dag en week) met de bovenstaande code. Het is gewoon een beetje brak. Dus moest ik voor de triple weergave gebruiken iframes :(
klasse VisualizeAll(webapp. RequestHandler):
def get(self):
# make de gebruiker inloggen als geen gebruikersnaam is opgegeven
als self.request.get('user'):
account = users. User(Self.Request.Get('user'))
anders:
zoniet users.get_current_user():
Self.Redirect(users.create_login_url(Self.Request.URI))
account = users.get_current_user()
Self.Response.out.write)
< h2 > stroomverbruik over het afgelopen uur: < / h2 >
< iframe src = "grafiek? user = adawattz frameborder ="0"width ="100% "height ="300px">
< p > uw browser ondersteunt geen iframes. < /p >
< / iframe >
< h2 > energieverbruik over de laatste dag: < / h2 >
< iframe src = "grafiek? user = adawattz frameborder ="0"width ="100% "height ="300px">
< p > uw browser ondersteunt geen iframes. < /p >
< / iframe >
< h2 > stroomverbruik de afgelopen week: < / h2 >
< iframe src = "grafiek? user = adawattz frameborder ="0"width ="300% "height ="500px">
< p > uw browser ondersteunt geen iframes. < /p >
< / iframe >
)
Hoe dan ook, het werkt prima.
Tijdcodes!
Het laatste ding dat niet zal worden herzien hier is hoe ik de datum en de tijdstippen als EST in plaats van UTC. Voor zover ik kan vertellen, zijn soort gebroken en mysterieus. Controleer de code als u wilt uitzoeken.