Data Visualization-app met GAE Python, D3.js en Google BigQuery deel 3

In het vorige deel van deze zelfstudie hebben we gezien hoe aan de slag te gaan met D3.js en dynamische schalen en assen gemaakt voor onze visualisatiegrafiek met behulp van een voorbeeldgegevensset. In dit deel van de zelfstudie plotten we de grafiek met behulp van de voorbeeldgegevensset.

Om te beginnen, klone de vorige broncode van de zelfstudie uit GitHub.  

git clone https://github.com/jay3dec/PythonD3jsMashup_Part2.git

Navigeer naar de Google App Engine (GAE) SDK-directory en start de server.

./dev_appserver.py PythonD3jsMashup_Part2 / 

Richt uw browser op http: // localhost: 8080 / displayChart en u zou in staat moeten zijn om de X- en Y-assen te zien die we in de vorige tutorial hebben gemaakt.

Maak voordat u aan de slag gaat een nieuw sjabloon met de naam displayChart_3.html welke hetzelfde zal zijn als displayChart.html. Voeg ook een route toe voor displayChart_3.html. Dit is gedaan om de demo van de vorige tutorial intact te houden, omdat ik hem op dezelfde URL zal hosten.

klasse DisplayChart3 (webapp2.RequestHandler): def get (self): template_data =  template_path = 'Sjablonen / displayChart_3.html' self.response.out.write (template.render (template_path, template_data)) application = webapp2.WSGIApplication ( [('/ chart', ShowChartPage), ('/ displayChart', DisplayChart), ('/ displayChart3', DisplayChart3), ('/', ShowHome),], debug = True)

De visualisatiegrafiek maken (met voorbeeldgegevens)

Van onze voorbeeldgegevensset hebben we een aantal tellen worden geplot over een set van corresponderende jaar.

var data = ["count": "202", "year": "1590", "count": "215", "year": "1592", "count": "179", " year ":" 1593 ", " count ":" 199 "," year ":" 1594 ", " count ":" 134 "," year ":" 1595 ", " count ":" 176 "," jaar ":" 1596 ", " count ":" 172 "," year ":" 1597 ", " count ":" 161 "," year ":" 1598 ", " count ":" 199 "," year ":" 1599 ", " count ":" 181 "," year ":" 1600 ", " count ":" 157 "," year ":" 1602 " , "count": "179", "year": "1603", "count": "150", "year": "1606", "count": "187", "year" : "1607", "count": "133", "year": "1608", "count": "190", "year": "1609", "count": "175" , "jaar": "1610", "count": "91", "year": "1611", "count": "150", "year": "1612"];

We geven elk van de gegevenspunten weer als cirkels in onze visualisatiegrafiek. D3.js biedt API-methoden om verschillende vormen en grootten te maken. 

Eerst gebruiken we d3.select All om cirkels in het visualisatie-element te selecteren. Als er geen elementen worden gevonden, retourneert deze een lege tijdelijke aanduiding waar we later cirkels kunnen toevoegen.

var circles = vis.select All ("circle");

Vervolgens binden we onze dataset aan de cirkels selectie.

var circles = vis.selectAll ("circle"). data (data);

Omdat onze bestaande cirkelselectie leeg is, gebruiken we enter om nieuwe cirkels te maken.

. Circles.enter () toevoegen ( "svg: circle")

Vervolgens definiëren we bepaalde eigenschappen, zoals de afstand van de middelpunten van de cirkels tot de X (cx) en Y (cy) assen, hun kleur, hun straal, enz. Voor het ophalen cx en cy, we zullen gebruiken xScale en yScale om het jaar te transformeren en gegevens in de plotruimte te tellen en de cirkel in het SVG-gebied te tekenen. Hier ziet u hoe de code eruit zal zien:

var circles = vis.selectAll ("circle"). data (data); circles.enter () .append ("svg: circle") .attr ("stroke", "black") // stelt de cirkelrand in .attr ("r", 10) // stelt de radius in .attr ("cx ", functie (d) // transformeert de jaargegevens zodat xscale (d.year) wordt geretourneerd; // kan worden geplot in de svg-ruimte) .attr (" cy ", functie (d) // transformaties de telgegevens zodat deze yScale (d.count) teruggeven; // kan in de svg-ruimte worden geplot) .style ("fill", "red") // stelt de cirkelkleur in

Sla wijzigingen op en vernieuw uw pagina. Je zou de afbeelding hieronder moeten zien:

Wijzigen van Google BigQuery om relevante gegevens te extraheren

In het eerste deel van deze serie, toen we gegevens verzamelden van BigQuery, selecteerden we ongeveer 1.000 woorden.

SELECTEER woord VAN [publicdata: samples.shakespeare] LIMIT 1000

We hebben een dataset met een lijst van alle woorden die in alle werken van Shakespeare voorkomen. Om de visualisatieapp enige nuttige informatie te laten zien, zullen we onze vraag aanpassen om het aantal keren een bepaald woord te selecteren, bijvoorbeeld Caesar, verschijnt in Shakespeare's werk in verschillende jaren.

Log dus in op Google BigQuery en we hebben een scherm zoals hieronder:

Nadat we zijn ingelogd bij Google BigQuery, hebben we een interface waar we onze SQL-query's kunnen opstellen en controleren. We willen het aantal keren selecteren dat een bepaald woord in alle werken van Shakespeare voorkomt.

Dus onze basisvraag zou er als volgt uitzien:

SELECT SUM (word_count) als WCount, corpus_date FROM [publicdata: samples.shakespeare] WHERE word = "Caesar" GROUP BY corpus_date BESTELLING BY WCount

De bovenstaande query geeft ons een resultaatset zoals hieronder getoond:

Laten we ook de groep werken opnemen die overeenkomt met de telling van Word. Wijzig de vraag zoals getoond om het corpus te omvatten:

SELECTEER SOM (word_count) als WCount, corpus_date, group_concat (corpus) as Work FROM [publicdata: samples.shakespeare] WHERE word = "Caesar" en corpus_date> 0 GROUP BY corpus_date BESTELLING BY WCount

De resulterende resultaatset wordt hieronder getoond:

De gegevens uit Google BigQuery plotten

Open vervolgens app.py en maak een nieuwe klasse genaamd GetChartData. Daarin zit de vraaginstructie die we hierboven hebben gemaakt.

queryData = 'query': 'SELECT SUM (word_count) als WCount, corpus_date, group_concat (corpus) as Work FROM "[publicdata: samples.shakespeare] WHERE word =" God "en corpus_date> 0 GROUP BY corpus_date ORDER BY WCount' 

Maak vervolgens een BigQuery-service aan waartegen we onze service uitvoeren queryData.

tableData = bigquery_service.jobs ()

Voer nu de queryData tegen de BigQuery-service en druk het resultaat af naar de pagina.

dataList = tableData.query (projectId = PROJECT_NUMBER, body = queryData) .execute () self.response.out.write (dataList)

Voeg ook een nieuwe route toe voor GetChartData zoals getoond.

toepassing = webapp2.WSGIA-toepassing ([('/ grafiek', ShowChartPage), ('/ displayChart', DisplayChart), ('/ displayChart3', DisplayChart3), ('/ getChartData', GetChartData), ('/', ShowHome) ,], debug = True)

Werk ten slotte de code bij naar het GAE-platform.

./appcfg.py update PythonD3jsMashup_Part2 /

Richt uw browser op http://YourAppspotUrl.com/getChartData die de resulterende gegevens van BigQuery zou moeten weergeven.

Vervolgens proberen we de gegevens die we hebben ontvangen van Google BigQuery te analyseren en om te zetten in een JSON-gegevensobject en door te geven aan de clientzijde om te verwerken met D3.js.

Eerst controleren we of er rijen in voorkomen DataList teruggekeerd. Als er geen rijen zijn, stellen we de reactie in op nul of nul.

als 'rijen' in dataList: # parse dataList else: resp.append ('count': '0', 'year': '0', 'corpus': '0')

Vervolgens zullen we de DataList door elke rij te herhalen en telling, jaar en corpus op te nemen en ons vereiste JSON-object te maken.

resp = [] als 'rijen' in dataList: voor rij in dataList ['rijen']: voor sleutel, dict_list in row.iteritems (): count = dict_list [0] jaar = dict_list [1] corpus = dict_list [2] resp.append ('count': count ['v'], 'year': year ['v'], 'corpus': corpus ['v']) else: resp.append ('count': '0', 'jaar': '0', 'corpus': '0')

Omdat we de geparseerde gegevens als JSON zullen retourneren, importeer je de JSON-bibliotheek

import json

En retourneer de gemaakte reactie als een JSON-reactie.

self.response.headers ['Content-type'] = 'application / json' self.response.out.write (json.dumps (resp))

Laten we ook het zoekwoord dynamisch maken, zodat het als parameter kan worden doorgegeven.

inputData = self.request.get ("inputData") queryData = 'query': 'SELECT SUM (word_count) als WCount, corpus_date, group_concat (corpus) as Work FROM "[publicdata: samples.shakespeare] WHERE word ="' + inputData + '"en corpus_date> 0 GROUP BY corpus_date ORDER BY WCount'

Hier is hoe de klas GetChartData eindelijk ziet er:

klasse GetChartData (webapp2.RequestHandler): def get (self): inputData = self.request.get ("inputData") queryData = 'query': 'SELECT SUM (word_count) als WCount, corpus_date, group_concat (corpus) as Work FROM "[publicdata: samples.shakespeare] WHERE word =" '+ inputData +' "GROUP BY corpus_date ORDER BY WCount ' tableData = bigquery_service.jobs () dataList = tableData.query (projectId = PROJECT_NUMBER, body = queryData) .execute ( ) resp = [] als 'rijen' in dataList: voor rij in dataList ['rijen']: voor sleutel, dict_list in row.iteritems (): count = dict_list [0] year = dict_list [1] corpus = dict_list [2 ] resp.append ('count': count ['v'], 'year': year ['v'], 'corpus': corpus ['v']) else: resp.append ('count' : '0', 'jaar': '0', 'corpus': '0') self.response.headers ['Content-type'] = 'application / json' self.response.out.write (json. stortplaatsen (resp))

Werk de app bij in GAE en wijs uw browser naar http://YourAppspotUrl.com/getChartData en u kunt het geretourneerde JSON-antwoord bekijken.

Vervolgens maken we een interface om dynamisch de query van de Google BigQuery-dataset van onze app te doen. Doe open Templates / displayChart_3.html en een invoervak ​​bevatten waarin we trefwoorden invoeren om de dataset te bevragen.

Voeg een jQuery-script toe aan de pagina en in de DOM-ready-gebeurtenis zullen we de Python-methode ondervragen GetChartData op Enter toets druk op.

$ (document) .ready (function () $ ("# txtKeyword"). keyup (function (event) if (event.keyCode == 13) // Druk op Enter-toets DisplayChart ();); InitChart (); // Init-diagram met as);

Maak een andere functie DisplayChart aan de kant van de klant, waarbinnen we een Ajax-oproep doen aan de Python GetChartData methode.

function DisplayChart () var keyword = $ ('# txtKeyword'). val (); $ .ajax (type: "GET", url: "/ getChartData", data: inputData: keyword, ​​dataType: "json", success: function (response) console.log (response);, error: functie (xhr, errorType, uitzondering) console.log ('Fout opgetreden');); 

Werk de code bij tot GAE en wijs uw browser naar http://YourAppspotUrl.com/displayChart3. Voer bijvoorbeeld een trefwoord in Caesar, en druk op invoeren. Controleer uw browserconsole en u zou de geretourneerde JSON-reactie moeten zien.

Laten we vervolgens de cirkels uitzetten met behulp van de geretourneerde reactie. Dus maak een andere JavaScript-functie aan genaamd CreateChart. Deze functie is vergelijkbaar met de InitChart functie, maar de gegevens worden als parameter doorgegeven. Hier is hoe het eruit ziet:

functie CreateChart (data) var vis = d3.select ("# visualization"), WIDTH = 1000, HEIGHT = 500, MARGINS = top: 20, right: 20, bottom: 20, left: 50, xScale = d3 .scale.linear (). bereik ([MARGINS.links, WIDTH - MARGES.rechts]). domein ([d3.min (data, functie (d) return (parseInt (d.year, 10) - 5); ), d3.max (gegevens, functie (d) return parseInt (d.year, 10);)]), yScale = d3.scale.linear (). bereik ([HEIGHT - MARGINS.top, MARGINS. bottom]). domain ([d3.min (data, functie (d) return (parseInt (d.count, 10) - 5);), d3.max (data, functie (d) return parseInt (d .count, 10);)]), xAxis = d3.svg.axis () .scale (xScale), yAxis = d3.svg.axis () .scale (yScale) .orient ("left"); vis.append ("svg: g") .attr ("class", "x axis") .attr ("transform", "translate (0," + (HEIGHT - MARGINS.bottom) + ")") .call (xAs); vis.append ("svg: g") .attr ("class", "y axis") .attr ("transform", "translate (" + (MARGINS.left) + ", 0)"). call (yAxis ); var circles = vis.selectAll ("circle"). data (data); circles.enter () .append ("svg: circle") .attr ("stroke", "black") .attr ("r", 10) .attr ("cx", functie (d) return xScale (d .jaar);) .attr ("cy", functie (d) retourneer yScale (d.count);) .style ("fill", "red")

Van de InitChart functie, verwijder het gedeelte voor het maken van een cirkel omdat het nu niet nodig is. Hier is hoe InitChart ziet:

functie InitChart () var data = ["count": "202", "year": "1590", "count": "215", "year": "1592", "count": "179", "jaar": "1593", "count": "199", "year": "1594", "count": "134", "year": "1595",  "count": "176", "year": "1596", "count": "172", "year": "1597", "count": "161", "year": "1598 ", " count ":" 199 "," year ":" 1599 ", " count ":" 181 "," year ":" 1600 ", " count ":" 157 "," year ":" 1602 ", " count ":" 179 "," year ":" 1603 ", " count ":" 150 "," year ":" 1606 ", " count ":" 187 "," jaar ":" 1607 ", " count ":" 133 "," year ":" 1608 ", " count ":" 190 "," year ":" 1609 ", " count ":" 175 "," year ":" 1610 ", " count ":" 91 "," year ":" 1611 ", " count ":" 150 "," year ":" 1612 " ]; var color = d3.scale.category20 (); var vis = d3.select ("# visualization"), WIDTH = 1000, HEIGHT = 500, MARGE = top: 20, right: 20, bottom: 20, left: 50, xScale = d3.scale.linear () .range ([MARGINS.links, WIDTH - MARGES.rechts]). domein ([d3.min (data, functie (d) return (parseInt (d.year, 10) - 5);), d3.max (data, functie (d) return parseInt (d.jaar, 10);)]), yScale = d3.scale.linear (). bereik ([HEIGHT - MARGINS.top, MARGINS.bottom]). domain ( [d3.min (data, functie (d) return (parseInt (d.count, 10) - 5);), d3.max (data, functie (d) return parseInt (d.count, 10); )]), xAxis = d3.svg.axis () .scale (xScale), yAxis = d3.svg.axis () .scale (yScale) .orient ("left"); vis.append ("svg: g") .attr ("class", "x axis") .attr ("transform", "translate (0," + (HEIGHT - MARGINS.bottom) + ")") .call (xAs); vis.append ("svg: g") .attr ("class", "y axis") .attr ("transform", "translate (" + (MARGINS.left) + ", 0)"). call (yAxis ); 

Vanaf nu laden we het / displayChart3 pagina worden kringen niet weergegeven. Kringen worden alleen weergegeven als het trefwoord is doorzocht. Dus, over het succes callback van de DisplayChart Ajax call, geef antwoord op de CreateChart functie.

succes: functie (respons) console.log (antwoord); CreateChart (respons); 

Werk de code bij tot GAE en zoek naar het sleutelwoord Caesar. OK, dus nu krijgen we het resultaat te zien als cirkels in de grafiek. Maar er is één probleem: beide assen worden overschreven.

Dus om dat te voorkomen, controleren we het binnenin CreateChart functie als de assen al aanwezig zijn of niet.

var hasAxis = vis.select ('. as') [0] [0]; if (! hasAxis) vis.append ("svg: g") .attr ("class", "x axis") .attr ("transform", "translate (0," + (HEIGHT - MARGINS.bottom) + ")"). call (xAxis); vis.append ("svg: g") .attr ("class", "y axis") .attr ("transform", "translate (" + (MARGINS.left) + ", 0)"). call (yAxis ); 

Zoals u kunt zien, hebben we net gecontroleerd of het SVG-element assen heeft, en zo niet, dan maken we ze opnieuw. Werk de code bij tot GAE en probeer opnieuw te zoeken naar het sleutelwoord, en je zou zoiets als dit moeten zien:

Inpakken

Hoewel alles er nu goed uitziet, zijn er nog een paar problemen die we in het volgende deel van deze tutorial zullen bespreken. We introduceren ook D3.js-overgangen en enkele andere functies in onze D3.js-grafiek en proberen deze interactiever te maken.

De broncode van deze tutorial is beschikbaar op GitHub.