• No results found

Data Visualization and Graphics

In document PYTHON. Pocket Primer (Page 168-192)

DATA VISUALIZATION AND

GRAPHICS

T

his chapter discusses various Python modules for data visualization, as well as Python modules for manipulating SVG. The information about the Python modules in this chapter is presented in a short and concise manner so that you can quickly decide which modules are useful for your work, and then you can find online resources to help you learn more about those modules.

The first portion of this chapter contains a short description of the Python modules matplotlib, numpy, pylab, and scipy. These modules are designed for scientific calculations, so they provide many Python functions that are well suited for statistical analysis and data analysis. They also enable you to generate render various charts that you can save as PNG files on the file system.

The second part of this chapter discusses TkInter, which is a toolkit for graphical user interface (GUI) development. This section contains some code samples for rendering user interface components and generating bar charts.

The third part of this chapter discusses Python toolkits for managing SVG. You will learn about the svgwrite toolkit, which consists of a Python script for generating SVG documents. You will also learn about a Python-based toolkit for D3.js (a very popular open-source data visualization toolkit).

One interesting technology (unrelated to Python) is R, which is a package for statisticians. Currently there appears to be some initiative for creating Py- thon modules that provide similar functionality. If you are going to participate in projects that require analysis of statistical data, then you stand to benefit from learning about the Python modules that are discussed in this chapter.

Before delving into the various Python modules in this chapter, let’s take a quick look at how to use IPython (discussed in Chapter 1) with some of these modules.

148 • Python Pocket Primer

IPYTHON

IPython supports interactive data processing and GUI toolkits, and you can download a stable version as well as a development version of IPython

from its homepage:

http://ipython.org/

After downloading and installing IPython, you can launch IPython with this command in a command shell:

ipython [options] files

For Python3, use ipython3 in place of ipython.

You can launch IPython with qt via the following command:

ipython --gui=qt

You can launch IPython by first loading matplotlib and qt via the following command:

ipython --matplotlib qt

Navigate to the IPython homepage to learn more about features and de- tails of the IPython notebook.

PYTHON MODULES FOR STATISTICAL AND SCIENTIFIC CALCULATIONS

There are various Python modules for generating plots and performing sci- entific and numeric calculations, such as Matplotlib, NumPy, Pylab, and SciPy.

In brief, these modules provide the following functionalities:

• The matplotlib module is a single module for managing data and gen- erating plots

• The numPy module provides an array type (that augments Python) that is useful for numeric calculations, along with routines for finding eigen- vectors

• pylab is a module for generating and saving plots

• sciPy is a module containing routines for scientific work such as com- puting numeric integrals, solving differential equations, and working with sparse matrices

Fortunately, a large collection of numeric and scientific code based on the preceding modules is also available, which you can use to reduce the complex- ity of your code.

Data Visualization and Graphics • 149

Installing matplotlib, numPy, and scipy

Use pip to install numPy, matplotlib, and scipy for the code sam- ple in this section (scipy is used elsewhere) by executing the following com- mands from the command line:

pip install numpy pip install scipy pip install matplotlib

The following code will work in Python if the preceding modules have been installed correctly:

import numpy

import scipy import matplotlib

WHAT IS MATPLOTLIB?

matplotlib is a very extensive plotting library for Python, and the

NumPy module is its numerical extension. matplotlib provides API for embedding plots into applications using toolkits such as GTKQt, wxPython, and so forth. Matplotlib also contains the matplotlib.pyplot module and the Pylab module for plots.

The pyplot interface is suited for plots in Python scripts, whereas the

pylab interface is suited for interactive calculations and plotting. If you launch the Ipython shell with the -pylab option, it will import everything from pylab, which makes plotting fully interactive.

pylab combines the pyplot functionality with the numpy functionality in a single namespace, which provides an environment similar to matlab. WORKING WITH NUMPY

NumPy is designed for manipulating homogeneous multidimensional ar- rays, which means that the elements in such arrays are all of the same type.

Numpy refers to dimensions as "axes," and the number of axes is called the "rank."

As a simple example, [1,2,3] represents a point in 3D space that: 1) is an array of length 3

2) has one axis

3) is an array of rank 1 because of 2)

As a second example, [[1,2,3], [4,5,6]] represents an array in 3D space that:

1) is two-dimensional

150 • Python Pocket Primer

3) has a second dimension of length 3 4) is an array of rank 2 because of 2)

If you can represent an element as an m x n matrix, then the value of m

(the number of rows) is the axis and the value of n (the number of columns) is the rank. You can use this analogy to help you remember the difference be- tween an axis and rank.

numpy provides the function array() for creating arrays, with an option for specifying the type of each element in the array, as shown here:

>>> from numpy import * >>> arr1 = array([1,2,3]) >>> arr1

array([1, 2, 3])

>>> arr2 = array([1,2,3], dtype=float) >>> arr2 array([ 1., 2., 3.]) >>> arr3 = zeros((2,3)) >>> arr3 array([[ 0., 0., 0.], [ 0., 0., 0.]])

To create sequences of numbers, NumPy provides the function arange(), analogous to the range() function, that returns arrays instead of lists.

>>> arange( 10, 30, 5 ) array([10, 15, 20, 25])

>>> arange( 0, 2, 0.3 ) # it accepts float arguments array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])

The numpy function reshape() allows you to change the display of an array of elements by “reshaping” them, as shown here:

>>> from numpy import * >>> a = arange(1,21) >>> print a [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20] >>> b = arange(1,21).reshape(4,5) >>> print b [[ 1 2 3 4 5] [ 6 7 8 9 10] [11 12 13 14 15] [16 17 18 19 20]] >>> c = arange(1,21).reshape(2,2,5) >>> print c [[[ 1 2 3 4 5] [ 6 7 8 9 10]] [[11 12 13 14 15] [16 17 18 19 20]]]

Another very useful function is linspace(initial, final, count)

Data Visualization and Graphics • 151

of count numbers, where the first number has the value initial, the last number has the value final, and the difference between any pair of con- secutive numbers is the same and equal to the quantity (final- initial)/ count. Some examples are here:

>> from numpy import * >>> linspace(0,10,5)

array([ 0. , 2.5, 5. , 7.5, 10. ]) >> linspace(20,30,11)

array([ 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30.])

You can use the linspace() function to define a set of points for plotting functions, as shown here:

>>> x = linspace(0, 2*pi, 360) >>> y = cos(x)

Later in this chapter you will see an example of plotting trigonometric functions.

The next section shows you how to use the pylab module to render some trigonometric functions.

WORKING WITH PYLAB

pylab also contains an arange() function (similar to the one in numpy) and a plot() function that enables you to plot functions. You can also label the horizontal and vertical axes and then use the savefig() function to save the plot as a PNG file.

Listing 7.1 displays the contents of TrigFunctions.py that illustrates how to render a sine wave and a cosine wave using the Python pylab module and saving the output to a PNG file.

LISTING 7.1 Trigfunctions.py

from pylab import * linewidth = '4'

x = arange(0.0, 4.0, 0.01) y1 = 10*sin(3*x)

plot(x, y1, linewidth) y2 = 5*cos(5*pi*x) plot(x, y2, linewidth) xlabel('Radians') ylabel('Amplitude') title('Trigonometric Functions') grid(True) savefig("TrigFunctions.png") show()

152 • Python Pocket Primer

Listing 7.1 contains one import statement, followed by the variable

linewidth that specifies the width of the curve that is rendered. The vari- ables x and y1 are used for rendering a sine wave, and the variables x and y2

represent a cosine wave. The xlabel() and ylabel() functions enable you to label the horizontal and vertical axes, respectively. The title() func- tion provides a title for the rendered graph. Finally, the savefig() function saves the rendered graph as a PNG file.

Figure 7.1 displays the result of launching Listing 7.1 from the command line on a Macbook Pro.

FIGURE 7.1 Trigonometric functions using pylab.

WORKING WITH SCIPY

scipy is open-source software for mathematics, science, and engineering.

SciPy depends on NumPy, which provides convenient and fast N- dimensional array manipulation. SciPy is built to work with NumPy arrays, and it provides many user-friendly and efficient numerical routines, such as routines for nu- merical integration and optimization.

The next section shows you how to use the Python modules numpy,

pylab, and scipy to render an oscillating wave pattern. RENDERING AN OSCILLATING WAVE

The combination of the numpy, pylab, and scipy modules enables you to create very compact Python scripts that can create complex plots. However, these scripts are often too terse unless you have in-depth knowledge of the scientific modules for Python.

As an illustration, Listing 7.2 displays the contents of Oscillate.py that renders a plot of an oscillating wave that is saved as a PNG file.

LISTING 7.2 Oscillate.py

from scipy import special, optimize from numpy import sin,pi,linspace from pylab import *

Data Visualization and Graphics • 153

func = lambda x: -exp(-(x-10)**2) sol = optimize.minimize(func, 8.0) x = linspace(0, 200, 5000)

plot(x, special.jv(3, x), '-', sol.x, -sol.fun, 'o') savefig('scipy1.png')

The first part of Listing 7.2 contains import statements, followed by the definition of the lambda function func. In case you have not heard about lambda functions, they are anonymous functions (discussed briefly in Chap- ter 2 and also in Chapter 8). In this example, func is defined as an exponential function.

The next portion of Listing 7.2 defines the variable sol that is based on the

minimize() function that belongs to the scipy module. The variable x is a set of values defined in terms of the linspace() function that we discussed earlier in this chapter.

The last two lines of code in Listing 7.2 generate and save a plot based on the variables in this code sample.

Figure 7.2 displays the result of launching Listing 7.2 from the com- mand line on a Macbook Pro.

The next portion of this chap- ter discusses TkInter and shows you examples of rendering various GUI controls and how to render bar charts in 2D and 3D.

WHAT IS TKINTER?

Python supports TkInter, which is a toolkit for GUI development.

TkInter provides support for various GUI controls or widgets (such as but- tons, labels, and text boxes) that are used in GUI applications. TkInter pro- vides widgets called Button, Canvas, Checkbutton, Entry, Frame,

Label, Listbox, Menubutton, Menu, Message, Radiobutton,

Scale, Scrollbar, Text, Toplevel, Spinbox, PanedWindow,

LabelFrame, and tkMessageBox.

Some of their common attributes include Dimensions, Colors,

Fonts, Anchors, Relief styles, Bitmaps, and Cursors.

TkInter Geometry Management

All TkInter widgets have access to specific geometry management methods that organize the layout of widgets. TkInter exposes the geometry manager classes pack, grid, and place that enable you to control the layout of widgets.

154 • Python Pocket Primer

RENDERING A BUTTON WITH TKINTER

Listing 7.3 displays the contents of Button1.py that illustrates how to render a button that responds to user click events.

LISTING 7.3 Button1.py

from Tkinter import * master = Tk()

def callback():

print "You clicked the button"

btn = Button(master, text="OK", command=callback) btn.pack()

mainloop()

Listing 7.3 contains an import statement and the variable master that is an instance of the Tk object. The function callback() is executed when users click on the button on the screen, which is defined via the variable btn. (Notice that its callback specifies the callback() function.) The pack()

method essentially “packs” the widgets into a compact rectangle, and then the function mainloop() enters a loop and waits for user input.

DISPLAYING A 2D BAR CHART IN PYTHON AND TKINTER

Listing 7.4 displays the contents of the Python script BarChart1.py that illustrates how to use TkInter to render a bar chart.

LISTING 7.4: BarChart1.py

from Tkinter import * import random root = Tk() width = 600 height = 500

canvas = Canvas(root, bg='#d0d0d0', height=500, width=600) # set-up variables upperX = 40 upperY = 40 deltaX = 10 deltaY = 10 barCount = 10 barWidth = 20 barHeight = 0 minBarHeight = 20 maxBarHeight = 300 lineWidth = 3

Data Visualization and Graphics • 155

lineColor = "#000000" rectColor = ""

# main loop

# render horizontal axis

lId = canvas.create_line(upperX-deltaX,

upperY+maxBarHeight+deltaY,

upperX+2*deltaX+barCount*barWidth, upperY+maxBarHeight+deltaY,

fill=lineColor,width=lineWidth) # render vertical axis

lId = canvas.create_line(upperX-deltaX, upperY-deltaY, upperX-deltaX,

upperY+maxBarHeight+deltaY, fill=lineColor,width=lineWidth) # render bar elements

for b in range(0,barCount): if(b % 2 == 0): rectColor = "#" + "FF0000" else: rectColor = "#" + "FFFF00" upperLX = upperX+b*barWidth upperLY = upperY

barHeight = random.randrange(0, maxBarHeight) if(barHeight < minBarHeight): barHeight = minBarHeight rId = canvas.create_rectangle(upperLX, upperLY+(maxBarHeight-barHeight), upperLX+barWidth, upperLY+maxBarHeight, fill=rectColor,width=1) canvas.pack() root.mainloop()

Listing 7.4 initializes a set of variables, followed by a code block that renders the horizontal and vertical axes. The next portion of code contains a

for loop that renders a set of bar elements in a bar chart. The if/else code block uses the modulus (“%”) function to alternate between red (FF0000) and blue (0000FF). Next, the upper left vertex of the current bar element is calculated and assigned to upperLX and upperLY. The barHeight vari- able is assigned a random number between 0 and maxBarHeight, followed by a simple if statement that ensures that the barHeight value is at least

minBarHeight.

The next portion of code in the for loop invokes the create_ rectangle() method with the (x,y) coordinates of the upper left vertex of the current rectangle, its width, its height, and its fill color.

156 • Python Pocket Primer

Figure 7.3 displays the result of launch- ing the code in BarChart1.py in a Chrome browser on a Macbook Pro.

Now that you understand how to create a 2D bar chart, the next section shows you how to create a 3D bar chart in Python with

TkInter.

A 3D BAR CHART IN PYTHON AND

TKINTER

Listing 7.5 displays the contents of the Python script BarChart13D1.py that illus- trates how to render a 3D bar chart.

LISTING 7.5: BarChart13D1.py

from Tkinter import * import random root = Tk() width = 600 height = 500 canvas = Canvas(root, bg='#d0d0d0', height=500, width=600) # set-up variables upperX = 40 upperY = 40 deltaX = 10 deltaY = 10 barCount = 10 barWidth = 40 slantX = barWidth/2 slantY = barWidth/4 barHeight = 0 minBarHeight = 20 maxBarHeight = 300 lineWidth = 3 lineColor = "#000000" rectColor = "" topColor = "#eeeeee" rightColor = "#444444" rectColors = ["#FF0000", "#0000FF"] points = [] pGramWidth = 1 # main loop

# render horizontal axis

lId = canvas.create_line(upperX-deltaX,

upperY+maxBarHeight+deltaY,

FIGURE 7.3 A bar chart in Python and TkInter.

Data Visualization and Graphics • 157

upperX+2*deltaX+barCount*barWidth, upperY+maxBarHeight+deltaY,

fill=lineColor,width=lineWidth) # render vertical axis

lId = canvas.create_line(upperX-deltaX, upperY-deltaY, upperX-deltaX,

upperY+maxBarHeight+deltaY, fill=lineColor,width=lineWidth) # render bar elements

for b in range(0,barCount): rectColor = rectColors[b % 2]; upperLX = upperX+b*barWidth upperLY = upperY

barHeight = random.randrange(0, maxBarHeight) if(barHeight < minBarHeight):

barHeight = minBarHeight # render front face

rId = canvas.create_rectangle(upperLX,

upperLY+(maxBarHeight-barHeight), upperLX+barWidth,

upperLY+maxBarHeight, fill=rectColor,width=1) # render top face (CCW from lower-left vertex) points = [] points.append(upperLX) points.append(upperLY+(maxBarHeight-barHeight)) points.append(upperLX+barWidth) points.append(upperLY+(maxBarHeight-barHeight)) points.append(upperLX+barWidth+slantX) points.append(upperLY+(maxBarHeight-barHeight)-slantY) points.append(upperLX+0*barWidth+slantX) points.append(upperLY+(maxBarHeight-barHeight)-slantY) tId = canvas.create_polygon(points, outline='red',

fill=topColor, width=pGramWidth) # render right face (CCW from upper-left vertex)

points = [] points.append(upperLX+barWidth) points.append(upperLY+(maxBarHeight-barHeight)) points.append(upperLX+barWidth) points.append(upperLY+(maxBarHeight-barHeight)+barHeight) points.append(upperLX+barWidth+slantX)

158 • Python Pocket Primer

points.append(upperLY+(maxBarHeight-barHeight)+barHeight-slantY) points.append(upperLX+barWidth+slantX)

points.append(upperLY+(maxBarHeight-barHeight)-slantY) tId = canvas.create_polygon(points, outline='red',

fill=rightColor, width=pGramWidth) canvas.pack()

root.mainloop()

Listing 7.5 “generalizes” the code in List- ing 7.4 in the sense that the front “face” of each bar element is calculated in the same manner. The top “face” and the right “face” are both parallelograms: each one consists of four vertices that are calculated based on the position of the current front “face” in the loop.

Figure 7.4 displays the result of launching Listing 7.5 from the command line.

DISPLAYING A LINE GRAPH IN PYTHON AND TKINTER

Listing 7.6 displays the contents of the Python script LineGraph1.py

that illustrates how to use Tkinter to render a line graph. LISTING 7.6: LineGraph1.py

from Tkinter import * import random root = Tk() width = 600 height = 500 canvas = Canvas(root, bg='#d0d0d0', height=500, width=600) # set-up variables upperX = 40 upperY = 40 deltaX = 10 deltaY = 10 barCount = 10 barWidth = 40 barHeight = 0 barHeights = [] minBarHeight = 20 maxBarHeight = 300 lineWidth = 3 lineColor = "#000000" rectColor = ""

FIGURE 7.4 A 3D bar chart in Python and TkInter.

Data Visualization and Graphics • 159

# main loop

# render horizontal axis

lId = canvas.create_line(upperX-deltaX,

upperY+maxBarHeight+deltaY,

upperX+2*deltaX+barCount*barWidth, upperY+maxBarHeight+deltaY,

fill=lineColor,width=lineWidth) # render vertical axis

lId = canvas.create_line(upperX-deltaX, upperY-deltaY, upperX-deltaX, upperY+maxBarHeight+deltaY, fill=lineColor,width=lineWidth) for b in range(0,barCount):

randHeight = random.randrange(0, maxBarHeight) if(randHeight < minBarHeight):

randHeight = minBarHeight barHeights.append(randHeight) print barHeights

# render line segments

for b in range(1,barCount-1): if(b % 2 == 0): rectColor = "#" + "FF0000" else: rectColor = "#" + "FFFF00" pointX1 = upperX+(b-1)*barWidth pointY1 = upperY+barHeights[b-1] pointX2 = upperX+b*barWidth pointY2 = upperY+barHeights[b]

rId = canvas.create_line(pointX1, pointY1, pointX2, pointY2,

fill=rectColor,width=lineWidth) canvas.pack()

root.mainloop()

Listing 7.6 contains logic similar to that in Listing 7.5, except that Listing 7.6 renders a set of line segments instead of bar elements. Specifically, Listing 7.6 invokes the create_ line() function with a pair of consecutive points that represent the left “edge” and the right “edge” of the bar elements that are ren- dered in Listing 7.5.

Figure 7.5 displays the result of launching Listing 7.6 from the command line.

FIGURE 7.5 A line graph in Python and TkInter.

160 • Python Pocket Primer

TRIGONOMETRIC CURVES IN PYTHON AND TKINTER

Listing 7.7 displays the contents of the Python script TrigFunctions1. py that illustrates how to render various trigonometric functions in Python and

TkInter.

LISTING 7.7: TrigFunctions1.py

from math import sin, cos from Tkinter import * sWidth = 700 sHeight = 500 Amplitude = 150 frequency = 1 deltaY = 20 deltaX = 20 basePointX = 10 basePointY = Amplitude+deltaY currentX = 0 currentY = 0 currentY1 = 0 currentY2 = 0 rectColor = "#ff0000" rWidth = 20 rHeight = 40 maxAngle = 720 PI = 3.1415296 rectColors = ["#FF0000", "#FFFF00", "#00FF00", "#0000FF"]; root = Tk() canvas = Canvas(root, bg='#d0d0d0', height=sHeight, width=sWidth) for x in range(0,maxAngle): # sine wave rectColor = rectColors[x % 2] currentX = basePointX + x

currentY = basePointY + Amplitude*sin(frequency*x*PI/180) canvas.create_rectangle(currentX, currentY, currentX+rWidth, currentY+rHeight, fill=rectColor,width=0) # cosine wave currentX = basePointX + x

currentY = basePointY + Amplitude*cos(2*frequency*x*PI/180) rectColor = rectColors[2*((x+1) % 2)] canvas.create_rectangle(currentX, currentY, currentX+rWidth, currentY+rHeight, fill=rectColor,width=0)

Data Visualization and Graphics • 161 # tangent wave currentX1 = basePointX + x currentY1 = sin(frequency*x*PI/180) currentY2 = cos(2*frequency*x*PI/180) if(currentY2 != 0):

currentY = basePointY + Amplitude*currentY1/currentY2 else:

currentY = BasePointY + Amplitude*currentY1 rectColor = rectColors[x % 3] # canvas.create_rectangle(currentX, canvas.create_oval(currentX, currentY, currentX+rWidth, currentY+rHeight, fill=rectColor,width=0) canvas.pack() root.mainloop()

Listing 7.7 initializes a set of variables, followed by a for loop that iter- ates through a set of values between 0 and maxAngle. During each loop iteration, the position of a rectangle is calculated that is based on the value in a sine function. A second rectangle and a third rectangle are also calculated based on a cosine function and a

tangent function. Thus, each loop

In document PYTHON. Pocket Primer (Page 168-192)

Related documents