In this recipe, we will diverge from the desktop environment and show how we can output for the Web. Although the main language for the web frontend is not Python but HTML, CSS, and JavaScript, we can still use Python for heavy lifting: fetch data, process it, perform intensive computations, and render data in a format(s) suitable for web output, that is, create HTML pages with the required JavaScript version to render our visualization(s).
We will use Google Data Visualization Library for Python to help us prepare data for the frontend interface, where we will use another Google Visualization API to render data in the desired visualization, that is, a map and a table.
Before we start, we need to install the google-visualization-python
module. Download the latest stable version from Github and install the module. The following actions demonstrate how to do this:
$ git clone https://github.com/google/google-visualization-python.git $ cd google-visualization-python/ $ sudo python setup.py install
Note that we have to become a super user (that is, gain administrator privileges) to install this module on our system.
A better option, if you don't want to pollute your OS packages, is to create a virtualenv
environment to install the packages just for this recipe. We explained how to deal with virutalenv
environments in Chapter 1, Preparing Your Working Environment.
For the frontend library we don't have to install anything, as that library will be loaded from the web page directly from the Google servers.
We need active access to the Internet for this recipe, because the output of it will be a web page that will, when opened in a web browser, pull the JavaScript libraries directly from remote servers.
In this recipe, you will learn how to use Google Data Visualization Library for Python and JavaScript to combine them for creating web visualization.
The following example shows how to visualize Disposable Median Monthly Salary per Country on the world map projection using Google Geochart and Table Visualization, loading the data from a .csv
file using Python and the gdata_viz
module. We will:
csv
module to load the data from the local .csv
file.DataTable
to describe the data and LoadData
to load the data from the Python dictionary.This can be achieved with the following code:
import csv import gviz_api def get_page_template(): page_template = """ <html> <script src="https://www.google.com/jsapi" type="text/javascript"></script> <script> google.load('visualization', '1', {packages:['geochart', 'table']}); google.setOnLoadCallback(drawMap); function drawMap() { var json_data = new google.visualization.DataTable(%s, 0.6); var options = {colorAxis: {colors: ['#eee', 'green']}}; var mymap = new google.visualization.GeoChart( document.getElementById('map_div')); mymap.draw(json_data, options); var mytable = new google.visualization.Table( document.getElementById('table_div')); mytable.draw(json_data, {showRowNumber: true}) } </script> <body> <H1>Median Monthly Disposable Salary World Countries</H1> <div id="map_div"></div> <hr /> <div id="table_div"></div> <div id="source"> <hr /> <small> Source: <a href="http://www.numbeo.com/cost-of-living/prices_by_country.jsp?displayCurrency=EUR&itemId=105"> http://www.numbeo.com/cost-of-living/prices_by_country.jsp?displayCurrency=EUR&itemId=105 </a> </small> </div> </body> </html> """ return page_template def main(): # Load data from CVS file afile = "median-dpi-countries.csv" datarows = [] with open(afile, 'r') as f: reader = csv.reader(f) reader.next() # skip header for row in reader: datarows.append(row) # Describe data description = {"country": ("string", "Country"), "dpi": ("number", "EUR"), } # Build list of dictionaries from loaded data data = [] for each in datarows: data.append({"country": each[0], "dpi": (float(each[1]), each[1])}) # Instantiate DataTable with structure defined in 'description' data_table = gviz_api.DataTable(description) # Load it into gviz_api.DataTable data_table.LoadData(data) # Creating a JSon string json = data_table.ToJSon(columns_order=("country", "dpi"), order_by="country", ) # Put JSON string into the template # and save to output.html with open('output.html', 'w') as out: out.write(get_page_template() % (json,)) if __name__ == '__main__': main()
This will produce the output.html
file, which we can open in our favorite web browser. The page should look like the following screenshot:
The main entry point here is our main()
function. First, we use the csv
module to load our data. This data is obtained from the public website www.numbeo.com, and the data is put in the .csv
format. The final file is available in the repository for this chapter in the Chapter06
folder. To be able to use Google Data Visualization Library, we need to describe the data to it. We describe data using the Python dictionaries, where we define the ID of the columns, their data type, and an optional label. In the following example, the data is defined in this constraint:
{"name": ("data_type", "Label")}: description = {"country": ("string", "Country"), "dpi": ("number", "EUR"), }
Then we need to fit our loaded .csv
rows in this format. We will build a list of dictionaries in the data variable.
Now we have everything to instantiate our data_table
with gviz_data.DataTable
with the described structure. We then load the data into it and output in the JSON format to our page_template
.
The get_page_template()
function contains the other part of this equation. It contains a client (frontend) code to produce an HTML web page and a JavaScript code to load Google Data Visualization Library from Google servers. The line that loads the Google JavaScript API is:
<script src="https://www.google.com/jsapi" type="text/javascript"></script>
After this follows another pair of <script>...</script>
tags that contains an additional setup. First, we load Google Data Visualization Library and the required package—geochart and table:
google.load('visualization', '1', {packages:['geochart', 'table']});
Then we set up a function that will be called when the pages are loaded. This event in the web world is registered as onLoad
, so callback is set up via setOnLoadCallback
function:
google.setOnLoadCallback(drawMap);
This defines that when a page is loaded, the Google instance will call the custom function drawMap()
that we defined. The drawMap
function loads a JSON string into the JavaScript version of the DataTable
instance:
var json_data = new google.visualization.DataTable(%s, 0.6);
Following that, we create a geochart instance in an HTML element with the ID map_div
:
var mymap = new google.visualization.GeoChart( document.getElementById('map_div'));
Draw the map using json_data
and provided custom options:
mymap.draw(json_data, options);
Similarly, Google's JavaScript table is rendered below the map:
var mytable = new google.visualization.Table( document.getElementById('table_div')); mytable.draw(json_data, {showRowNumber: true})
We save this output as an HTML file that we can open in a browser. This is not so useful for the dynamic rendering of a web service. There is a better option for this—to output the HTTP response directly from Python, and thus build a background service responding to client web requests with JSON that a client can load and render.
If you want to understand more on reading HTTP responses, please read more on HTTP Protocol and Response messages at http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Response_message.
We do this by replacing the ToJson()
call with the ToJSonResponse()
with the same signature. This call will respond with a proper HTTP response containing the payload—our JSON-ified data_table
ready to be consumed by our JavaScript client.
This, of course, is just one example of how we can combine Python as a backend language, sitting on our server, doing the data fetch and processing, while the frontend is left to the universal HTML/JavaScript/CSS set of languages. This enables us to provide interactive and dynamic interfaces with visualizations to a wide audience without requiring them to install anything (well, apart from a web browser, but that is usually installed on a computer or smartphone). Saying that, we must note that the quality of these outputs is not as high as that of matplotlib; the strength of matplotlib lies in its high-quality output.
To work more with the web (and Python), you would have to learn more about the web technologies and languages used. This book does not cover such topics but does give an insight into how to achieve one possible solution using well-known third-party libraries that produce pleasing web outputs, with as little web coding as possible.
More documentation is available on the Google Developer portal at https://developers.google.com/chart/interactive/docs/dev/gviz_api_lib.