1 """Plots to compare information between different sources.
2
3 This file contains high level plots which are designed to be used to
4 compare different types of information. The most basic example is comparing
5 two variables in a traditional scatter plot.
6 """
7
8 from reportlab.pdfgen import canvas
9 from reportlab.lib import colors
10 from reportlab.graphics.charts.lineplots import LinePlot
11 from reportlab.lib.pagesizes import letter
12 from reportlab.lib.units import inch
13
14 from reportlab.graphics.shapes import Drawing, String, Group
15 from reportlab.graphics import renderPDF, renderPS
16 from reportlab.graphics.charts.markers import *
17
19 """Display a scatter-type plot comparing two different kinds of info.
20
21 Attributes;
22
23 o display_info -- a 2D list of the information we'll be outputting. Each
24 top level list is a different data type, and each data point is a two-tuple
25 of the coordinates of a point. So if you had two distributions of points,
26 it should look like:
27
28 display_info = [[(1, 2), (3, 4)],
29 [(5, 6), (7, 8)]]
30
31 if everything is just one set of points, display_info can look like:
32
33 display_info = [[(1, 2), (3, 4), (5, 6)]]
34 """
35 - def __init__(self, output_format = 'pdf'):
36
37 self.number_of_columns = 1
38 self.page_size = letter
39 self.title_size = 20
40
41 self.output_format = output_format
42
43
44 self.display_info = []
45
46
47 self.color_choices = [colors.red, colors.green, colors.blue,
48 colors.yellow, colors.orange, colors.black]
49 self.shape_choices = [makeFilledCircle, makeEmptySquare,
50 makeFilledDiamond, makeFilledSquare,
51 makeEmptyCircle, makeSmiley]
52
54 """Write the comparative plot to a file.
55 """
56 width, height = self.page_size
57 cur_drawing = Drawing(width, height)
58
59 self._draw_title(cur_drawing, title, width, height)
60
61 start_x = inch * .5
62 end_x = width - inch * .5
63 end_y = height - 1.5 * inch
64 start_y = .5 * inch
65 self._draw_scatter_plot(cur_drawing, start_x, start_y, end_x, end_y)
66
67 if self.output_format == 'pdf':
68 out_canvas = canvas.Canvas(output_file, pagesize = self.page_size)
69 renderPDF.draw(cur_drawing, out_canvas, 0, 0)
70 out_canvas.showPage()
71 out_canvas.save()
72 elif self.output_format == 'eps':
73 renderPS.drawToFile(cur_drawing, output_file)
74 else:
75 raise ValueError("Invalid output format %s" % self.output_format)
76
77 - def _draw_title(self, cur_drawing, title, width, height):
78 """Add a title to the page we are outputting.
79 """
80 title_string = String(width / 2, height - inch, title)
81 title_string.fontName = 'Helvetica-Bold'
82 title_string.fontSize = self.title_size
83 title_string.textAnchor = "middle"
84
85 cur_drawing.add(title_string)
86
89 """Draw a scatter plot on the drawing with the given coordinates.
90 """
91 scatter_plot = LinePlot()
92
93
94 scatter_plot.x = x_start
95 scatter_plot.y = y_start
96 scatter_plot.width = abs(x_start - x_end)
97 scatter_plot.height = abs(y_start - y_end)
98
99 scatter_plot.data = self.display_info
100
101 scatter_plot.joinedLines = 0
102
103
104 x_min, x_max, y_min, y_max = self._find_min_max(self.display_info)
105 scatter_plot.xValueAxis.valueMin = x_min
106 scatter_plot.xValueAxis.valueMax = x_max
107 scatter_plot.xValueAxis.valueStep = (x_max - x_min) / 10.0
108
109 scatter_plot.yValueAxis.valueMin = y_min
110 scatter_plot.yValueAxis.valueMax = y_max
111 scatter_plot.yValueAxis.valueStep = (y_max - y_min) / 10.0
112
113 self._set_colors_and_shapes(scatter_plot, self.display_info)
114
115 cur_drawing.add(scatter_plot)
116
118 """Set the colors and shapes of the points displayed.
119
120 By default this just sets all of the points according to the order
121 of colors and shapes defined in self.color_choices and
122 self.shape_choices. The first 5 shapes and colors are unique, the
123 rest of them are just set to the same color and shape (since I
124 ran out of shapes!).
125
126 You can change how this function works by either changing the
127 values of the color_choices and shape_choices attributes, or
128 by inheriting from this class and overriding this function.
129 """
130 for value_num in range(len(display_info)):
131
132 if (value_num + 1) < len(self.color_choices):
133 scatter_plot.lines[value_num].strokeColor = \
134 self.color_choices[value_num]
135 scatter_plot.lines[value_num].symbol = \
136 self.shape_choices[value_num]
137
138 else:
139 scatter_plot.lines[value_num].strokeColor = \
140 self.color_choices[-1]
141 scatter_plot.lines[value_num].symbol = \
142 self.shape_choices[-1]
143
145 """Find the min and max for the x and y coordinates in the given data.
146 """
147 x_min = info[0][0][0]
148 x_max = info[0][0][0]
149 y_min = info[0][0][1]
150 y_max = info[0][0][1]
151
152 for two_d_list in info:
153 for x, y in two_d_list:
154 if x > x_max:
155 x_max = x
156 if x < x_min:
157 x_min = x
158 if y > y_max:
159 y_max = y
160 if y < y_min:
161 y_min = y
162
163 return x_min, x_max, y_min, y_max
164