Merge "Change PTL informatin in INFO"
[bottlenecks.git] / testsuites / vstf / vstf_scripts / vstf / controller / reporters / report / pdf / element.py
1 ##############################################################################
2 # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10
11 __doc__ = """
12 it contains the base element for pdf
13 eImage is used to draw picture on the pdf document
14 eDataTable is used to draw table on the pdf document
15 eGraphicsTable is used to draw plot on the pdf document
16 eParagraph is used to draw text on the pdf document
17 """
18 from reportlab.platypus import Image, Table
19 from reportlab.graphics.shapes import Drawing
20 from reportlab.graphics.charts.lineplots import LinePlot
21 from reportlab.graphics.charts.linecharts import HorizontalLineChart
22 from reportlab.platypus.paragraph import Paragraph
23 from reportlab.graphics.widgets.markers import makeMarker
24 from reportlab.graphics.charts.legends import Legend
25 from reportlab.graphics.charts.textlabels import Label
26 from reportlab.graphics.charts.axes import XValueAxis
27 from reportlab.graphics.shapes import Group
28 from reportlab.graphics.charts.barcharts import VerticalBarChart
29 from vstf.controller.reporters.report.pdf.styles import *
30
31
32 class eImage(Image):
33     """ an image(digital picture)which contains the function of auto zoom picture """
34
35     def __init__(
36             self,
37             filename,
38             width=None,
39             height=None,
40             kind='direct',
41             mask="auto",
42             lazy=1,
43             hAlign='CENTRE',
44             vAlign='BOTTOM'):
45         Image.__init__(self, filename, None, None, kind, mask, lazy)
46         print height, width
47         print self.drawHeight, self.drawWidth
48         if self.drawWidth * height > self.drawHeight * width:
49             self.drawHeight = width * self.drawHeight / self.drawWidth
50             self.drawWidth = width
51         else:
52             self.drawWidth = height * self.drawWidth / self.drawHeight
53             self.drawHeight = height
54         self.hAlign = hAlign
55         self.vAlign = vAlign
56         print self.drawHeight, self.drawWidth
57
58
59 class eTable(object):
60     """ an abstract table class, which is contains the base functions to create table """
61
62     def __init__(self, data, style=TableStyle(name="default")):
63         self._tablestyle = style
64         self._table = []
65         self._spin = False
66         self._colWidths = None
67         self._data = self.analysisData(data)
68         if self._data:
69             self.create()
70
71     def analysisData(self, data):
72         raise NotImplementedError("abstract eTable")
73
74     def create(self):
75         self._table = Table(self._data, style=self._style, splitByRow=1)
76         self._table.hAlign = self._tablestyle.table_hAlign
77         self._table.vAlign = self._tablestyle.table_vAlign
78         self._table.colWidths = self._tablestyle.table_colWidths
79         if self._spin or self._colWidths:
80             self._table.colWidths = self._colWidths
81         self._table.rowHeights = self._tablestyle.table_rowHeights
82
83     @property
84     def table(self):
85         return self._table
86
87
88 class eCommonTable(eTable):
89
90     def analysisData(self, data):
91         self._style = [
92             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
93             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
94             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
95             ('BOX', (0, 0), (-1, -1), 1.2, colors.black)
96         ]
97         return data
98
99
100 class eConfigTable(eTable):
101
102     def analysisData(self, data):
103         self._style = [
104             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
105             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
106             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
107             ('BOX', (0, 0), (-1, -1), 1, colors.black),
108             ('SPAN', (2, 0), (3, 0)),
109             ('SPAN', (2, 1), (3, 1)),
110             ('SPAN', (2, 8), (3, 8)),
111             ('SPAN', (2, 9), (3, 9)),
112             ('SPAN', (2, 10), (3, 10)),
113             ('SPAN', (0, 0), (0, 7)),
114             ('SPAN', (0, 8), (0, 10)),
115             ('SPAN', (0, 11), (0, 19)),
116             ('SPAN', (1, 2), (1, 6)),
117             ('SPAN', (1, 12), (1, 13)),
118             ('SPAN', (1, 14), (1, 16)),
119             ('SPAN', (1, 17), (1, 19)),
120             ('SPAN', (2, 3), (2, 6))
121         ]
122         return data
123
124
125 class eSummaryTable(eTable):
126
127     def analysisData(self, data):
128         self._style = [
129             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
130             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
131             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
132             ('BOX', (0, 0), (-1, -1), 1, colors.black),
133             ('SPAN', (0, 0), (0, 1)),
134             ('SPAN', (1, 0), (4, 0)),
135             ('SPAN', (5, 0), (-1, 0))
136         ]
137         return data
138
139
140 class eGitInfoTable(eTable):
141
142     def analysisData(self, data):
143         self._style = [
144             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
145             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
146             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
147             ('BOX', (0, 0), (-1, -1), 1, colors.black),
148             ('SPAN', (0, 0), (0, 2)),
149             ('SPAN', (0, 3), (0, 5)),
150             ('SPAN', (0, 6), (0, 8))
151         ]
152         return data
153
154
155 class eScenarioTable(eTable):
156
157     def analysisData(self, data):
158         self._style = [
159             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
160             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
161             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
162             ('BOX', (0, 0), (-1, -1), 1, colors.black),
163             ('ALIGN', (2, 1), (-1, -1), 'LEFT'),
164             ('SPAN', (0, 1), (0, 6)),
165             ('SPAN', (0, 7), (0, 12)),
166             ('SPAN', (0, 13), (0, 16)),
167             ('SPAN', (0, 17), (0, 20))
168         ]
169         return data
170
171
172 class eOptionsTable(eTable):
173
174     def analysisData(self, data):
175         self._style = [
176             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
177             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
178             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
179             ('BOX', (0, 0), (-1, -1), 1, colors.black),
180             ('SPAN', (2, 0), (4, 0)),
181             ('SPAN', (2, 1), (4, 1)),
182             ('SPAN', (0, 0), (0, -1)),
183             ('SPAN', (1, 2), (1, 16)),
184             ('SPAN', (1, 17), (1, 19)),
185             ('SPAN', (1, 20), (1, 22)),
186             ('SPAN', (1, 23), (1, 24)),
187             ('SPAN', (2, 2), (2, 4)),
188             ('SPAN', (2, 5), (2, 12)),
189             ('SPAN', (2, 13), (2, 16)),
190             ('SPAN', (2, 17), (2, 19)),
191             ('SPAN', (2, 20), (2, 22)),
192             ('SPAN', (2, 23), (2, 24))
193         ]
194         return data
195
196
197 class eProfileTable(eTable):
198
199     def analysisData(self, data):
200         self._style = [
201             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
202             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
203             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
204             ('BOX', (0, 0), (-1, -1), 1, colors.black),
205             ('SPAN', (0, 1), (0, -1)),
206             ('SPAN', (1, 0), (2, 0)),
207         ]
208         return data
209
210
211 class eDataTable(eTable):
212
213     def analysisData(self, data):
214         result = data
215         self._style = [
216             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
217             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
218             ('LEADING', (0, 0), (-1, -1), 18),
219             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
220             ('BOX', (0, 0), (-1, -1), 1, colors.black),
221             ('LINEBEFORE', (1, 0), (1, -1), 0.8, colors.black),
222             # ('LINEBEFORE', (3, 0), (3, -1), 1, colors.black),
223             # ('LINEBEFORE', (5, 0), (5, -1), 1, colors.black),
224             ('LINEBELOW', (0, 0), (-1, 0), 0.8, colors.black),
225             # ('SPAN', (0, 0), (0, 1)),
226             # ('SPAN', (1, 0), (2, 0)),
227             # ('SPAN', (3, 0), (4, 0))
228         ]
229         if self._spin is True:
230             print "start spin"
231             result = map(list, zip(*result))
232             style = []
233             for value in self._style:
234                 value = list(value)
235                 value[1] = (value[1][1], value[1][0])
236                 value[2] = (value[2][1], value[2][0])
237                 if value[0] == 'LINEBELOW':
238                     value[0] = 'LINEAFTER'
239                 elif value[0] == 'LINEBEFORE':
240                     value[0] = 'LINEABOVE'
241                 value = tuple(value)
242                 style.append(value)
243             self._style = style
244         return result
245
246
247 class eGraphicsTable(eTable):
248
249     def analysisData(self, data):
250         self._style = [
251             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
252             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE')
253         ]
254         return data
255
256
257 class noScaleXValueAxis(XValueAxis):
258
259     def __init__(self):
260         XValueAxis.__init__(self)
261
262     def makeTickLabels(self):
263         g = Group()
264         if not self.visibleLabels:
265             return g
266
267         f = self._labelTextFormat  # perhaps someone already set it
268         if f is None:
269             f = self.labelTextFormat or (self._allIntTicks() and '%.0f' or str)
270         elif f is str and self._allIntTicks():
271             f = '%.0f'
272         elif hasattr(f, 'calcPlaces'):
273             f.calcPlaces(self._tickValues)
274         post = self.labelTextPostFormat
275         scl = self.labelTextScale
276         pos = [self._x, self._y]
277         d = self._dataIndex
278         pos[1 - d] = self._labelAxisPos()
279         labels = self.labels
280         if self.skipEndL != 'none':
281             if self.isXAxis:
282                 sk = self._x
283             else:
284                 sk = self._y
285             if self.skipEndL == 'start':
286                 sk = [sk]
287             else:
288                 sk = [sk, sk + self._length]
289                 if self.skipEndL == 'end':
290                     del sk[0]
291         else:
292             sk = []
293
294         nticks = len(self._tickValues)
295         nticks1 = nticks - 1
296         for i, tick in enumerate(self._tickValues):
297             label = i - nticks
298             if label in labels:
299                 label = labels[label]
300             else:
301                 label = labels[i]
302             if f and label.visible:
303                 v = self.scale(i)
304                 if sk:
305                     for skv in sk:
306                         if abs(skv - v) < 1e-6:
307                             v = None
308                             break
309                 if v is not None:
310                     if scl is not None:
311                         t = tick * scl
312                     else:
313                         t = tick
314                     if isinstance(f, str):
315                         txt = f % t
316                     elif isSeq(f):
317                         # it's a list, use as many items as we get
318                         if i < len(f):
319                             txt = f[i]
320                         else:
321                             txt = ''
322                     elif hasattr(f, '__call__'):
323                         if isinstance(f, TickLabeller):
324                             txt = f(self, t)
325                         else:
326                             txt = f(t)
327                     else:
328                         raise ValueError('Invalid labelTextFormat %s' % f)
329                     if post:
330                         txt = post % txt
331                     pos[d] = v
332                     label.setOrigin(*pos)
333                     label.setText(txt)
334
335                     # special property to ensure a label doesn't project beyond
336                     # the bounds of an x-axis
337                     if self.keepTickLabelsInside:
338                         if isinstance(
339                                 self, XValueAxis):  # not done yet for y axes
340                             a_x = self._x
341                             if not i:  # first one
342                                 x0, y0, x1, y1 = label.getBounds()
343                                 if x0 < a_x:
344                                     label = label.clone(dx=label.dx + a_x - x0)
345                             if i == nticks1:  # final one
346                                 a_x1 = a_x + self._length
347                                 x0, y0, x1, y1 = label.getBounds()
348                                 if x1 > a_x1:
349                                     label = label.clone(
350                                         dx=label.dx - x1 + a_x1)
351                     g.add(label)
352
353         return g
354
355     def ___calcScaleFactor(self):
356         """Calculate the axis' scale factor.
357         This should be called only *after* the axis' range is set.
358         Returns a number.
359         """
360         self._scaleFactor = self._length / (len(self._tickValues) + 1)
361         return self._scaleFactor
362
363     def scale(self, value):
364         """Converts a numeric value to a plotarea position.
365         The chart first configures the axis, then asks it to
366         """
367         assert self._configured, "Axis cannot scale numbers before it is configured"
368         if value is None:
369             value = 0
370         # this could be made more efficient by moving the definition of org and
371         # sf into the configuration
372         org = (self._x, self._y)[self._dataIndex]
373         sf = self._length / (len(self._tickValues) + 1)
374         if self.reverseDirection:
375             sf = -sf
376             org += self._length
377         return org + sf * (value + 1)
378
379
380 class noScaleLinePlot(LinePlot):
381
382     def __init__(self):
383         LinePlot.__init__(self)
384         self.xValueAxis = noScaleXValueAxis()
385
386     def calcPositions(self):
387         """Works out where they go.
388
389         Sets an attribute _positions which is a list of
390         lists of (x, y) matching the data.
391         """
392         self._seriesCount = len(self.data)
393         self._rowLength = max(map(len, self.data))
394
395         self._positions = []
396         for rowNo in range(len(self.data)):
397             line = []
398             len_row = len(self.data[rowNo])
399             for colNo in range(len_row):
400                 datum = self.data[rowNo][colNo]  # x, y value
401                 x = self.x + self.width / (len_row + 1) * (colNo + 1)
402                 self.xValueAxis.labels[colNo].x = self.x + \
403                     self.width / (len_row + 1) * (colNo + 1)
404                 y = self.yValueAxis.scale(datum[1])
405                 #               print self.width, " ", x
406                 line.append((x, y))
407             self._positions.append(line)
408
409
410 # def _innerDrawLabel(self, rowNo, colNo, x, y):
411 #        return None
412 class eLinePlot(object):
413
414     def __init__(self, data, style):
415         self._lpstyle = style
416         self._linename = data[0]
417         self._data = self.analysisData(data[1:])
418         if self._data:
419             self.create()
420
421     @property
422     def draw(self):
423         return self._draw
424
425     def analysisData(self, data):
426         columns = len(data)
427         # print data
428         data = map(list, zip(*data))
429         rows = len(data)
430
431         for i in range(rows):
432             for j in range(columns):
433                 data[i][j] = float(data[i][j])
434         self._linename = self._linename[1:]
435         """
436         delcnt = 0
437         delrows = []
438         for i in range(columns):
439             delrows.append(0.0)
440         del_line = [self._linename[0]]
441         for i in range(rows):
442            for j in range(columns):
443               data[i][j] = float(data[i][j])
444            if data[i] == delrows:
445                delcnt += 1
446                del_line.append(self._linename[i])
447         for i in range(delcnt):
448             data.remove(delrows)
449         for name in del_line:
450             self._linename.remove(name)
451
452         rows = len(data)
453         """
454         # print rows
455         # print data
456         xvalueSteps = data[0]
457         xvalueMin = data[0][0]
458         xvalueMax = data[0][0]
459         yvalueMin = data[1][0]
460         yvalueMax = data[1][0]
461         yvalueSteps = []
462         result = []
463         for j in range(columns):
464             if xvalueMin > data[0][j]:
465                 xvalueMin = data[0][j]
466             if xvalueMax < data[0][j]:
467                 xvalueMax = data[0][j]
468
469         for i in range(rows - 1):
470             lst = []
471             for j in range(columns):
472                 lst.append((data[0][j], data[i + 1][j]))
473                 if yvalueMin > data[i + 1][j]:
474                     yvalueMin = data[i + 1][j]
475                 if yvalueMax < data[i + 1][j]:
476                     yvalueMax = data[i + 1][j]
477                 yvalueSteps.append(int(data[i + 1][j] * 2.5) / 2.5)
478             result.append(tuple(lst))
479         xvalueMin = int(xvalueMin) / 100 * 100
480         xvalueMax = int(xvalueMax) / 100 * 100 + 200
481         yvalueMin = int(yvalueMin) * 1.0 - 1
482         if yvalueMin < 0:
483             yvalueMin = 0.0
484         yvalueMax = int(yvalueMax) + 2.0
485         yvalueSteps.append(yvalueMin)
486         yvalueSteps.append(yvalueMax)
487         yvalueSteps = {}.fromkeys(yvalueSteps).keys()
488
489         self._xvalue = (xvalueMin, xvalueMax, xvalueSteps)
490         self._yvalue = (yvalueMin, yvalueMax, yvalueSteps)
491         print result
492         return result
493
494     def create(self):
495         lpw = self._lpstyle.width
496         lph = self._lpstyle.height
497         draw = Drawing(lpw, lph)
498         line_cnts = len(self._linename)
499         #        lp = noScaleLinePlot()
500         lp = LinePlot()
501         lg_line = (line_cnts + 3) / 4
502         lp.x = self._lpstyle.left
503         lp.y = self._lpstyle.bottom
504
505         lp.height = lph - self._lpstyle.bottom * (lg_line + 1.5)
506         lp.width = lpw - lp.x * 2
507         lp.data = self._data
508         lp.joinedLines = 1
509         lp.strokeWidth = self._lpstyle.strokeWidth
510         line_cnts = len(self._data)
511         sytle_cnts = len(self._lpstyle.linestyle)
512         color_paris = []
513         for i in range(line_cnts):
514             styleIndex = i % sytle_cnts
515             lp.lines[i].strokeColor = self._lpstyle.linestyle[styleIndex][0]
516             lp.lines[i].symbol = makeMarker(
517                 self._lpstyle.linestyle[styleIndex][1])
518             lp.lines[i].strokeWidth = self._lpstyle.linestyle[styleIndex][2]
519             color_paris.append(
520                 (self._lpstyle.linestyle[styleIndex][0], self._linename[i]))
521         #            lp.lineLabels[i].strokeColor = self._lpstyle.linestyle[styleIndex][0]
522
523         lp.lineLabelFormat = self._lpstyle.format[0]
524
525         lp.strokeColor = self._lpstyle.strokeColor
526
527         lp.xValueAxis.valueMin, lp.xValueAxis.valueMax, lp.xValueAxis.valueSteps = self._xvalue
528         #       valueMin, valueMax, xvalueSteps = self._xvalue
529         #       lp.xValueAxis.valueStep = (lp.xValueAxis.valueMax - lp.xValueAxis.valueMin)/len(xvalueSteps)
530         #       lp.xValueAxis.valueSteps = map(lambda x: str(x), xvalueSteps)
531
532         lp.yValueAxis.valueMin, lp.yValueAxis.valueMax, lp.yValueAxis.valueSteps = self._yvalue
533
534         #       lp.xValueAxis.forceZero = 0
535         #       lp.xValueAxis.avoidBoundFrac = 1
536         #       lp.xValueAxis.tickDown = 3
537         #       lp.xValueAxis.visibleGrid = 1
538         #       lp.xValueAxis.categoryNames = '64 256 512 1400 1500 4096'.split(' ')
539
540         lp.xValueAxis.labelTextFormat = self._lpstyle.format[1]
541         lp.yValueAxis.labelTextFormat = self._lpstyle.format[2]
542
543         delsize = int(lp.xValueAxis.valueMax / 2000)
544         lp.xValueAxis.labels.fontSize = self._lpstyle.labelsfont
545         lp.xValueAxis.labels.angle = 25
546
547         lp.yValueAxis.labels.fontSize = self._lpstyle.labelsfont
548         lp.lineLabels.fontSize = self._lpstyle.labelsfont - delsize
549         draw.add(lp)
550
551         lg = Legend()
552         lg.colorNamePairs = color_paris
553         lg.fontName = 'Helvetica'
554         lg.fontSize = 7
555
556         lg.x = self._lpstyle.left * 3
557         lg.y = self._lpstyle.bottom * (1 + lg_line) + lp.height
558
559         lg.dxTextSpace = 5
560         lg.dy = 5
561         lg.dx = 20
562         lg.deltax = 60
563         lg.deltay = 0
564         lg.columnMaximum = 1
565         lg.alignment = 'right'
566         draw.add(lg)
567         self._draw = draw
568
569
570 class eHorizontalLineChart(object):
571
572     def __init__(self, data, style):
573         self._lcstyle = style
574         if len(data) < 1:
575             return
576         self._linename = data[0]
577         self._data = self.analysisData(data[1:])
578         if self._data:
579             self.create()
580
581     @property
582     def draw(self):
583         return self._draw
584
585     def analysisData(self, data):
586         columns = len(data)
587         data = map(list, zip(*data))
588         self._catNames = data[0]
589         self._linename = self._linename[1:]
590         data = data[1:]
591         rows = len(data)
592
593         yvalueMin = float(data[0][0])
594         yvalueMax = float(data[0][0])
595         yvalueSteps = []
596         result = []
597
598         for rowNo in range(rows):
599             for columnNo in range(columns):
600                 data[rowNo][columnNo] = float(data[rowNo][columnNo])
601                 if yvalueMin > data[rowNo][columnNo]:
602                     yvalueMin = data[rowNo][columnNo]
603                 if yvalueMax < data[rowNo][columnNo]:
604                     yvalueMax = data[rowNo][columnNo]
605                 yvalueSteps.append(int(data[rowNo][columnNo] * 1.0) / 1.0)
606             result.append(tuple(data[rowNo]))
607
608         yvalueMin = int(yvalueMin) * 1.0 - 1
609         if yvalueMin < 0:
610             yvalueMin = 0.0
611         yvalueMax = int(yvalueMax) + 2.0
612         yvalueSteps.append(yvalueMin)
613         yvalueSteps.append(yvalueMax)
614         yvalueSteps = {}.fromkeys(yvalueSteps).keys()
615
616         self._value = (yvalueMin, yvalueMax, yvalueSteps)
617         print result
618         return result
619
620     def create(self):
621         dw = self._lcstyle.width
622         dh = self._lcstyle.height
623         draw = Drawing(dw, dh)
624
625         lc = HorizontalLineChart()
626         line_cnts = len(self._linename)
627
628         lg_line = (line_cnts + 3) / 4
629         lc.height = dh - self._lcstyle.bottom * (lg_line + 1.5)
630         lc.width = dw - lc.x * 2
631         lc.x = self._lcstyle.left
632         lc.y = self._lcstyle.bottom
633
634         lc.data = self._data
635
636         lc.strokeColor = self._lcstyle.strokeColor
637         lc.strokeWidth = self._lcstyle.strokeWidth
638         lc.useAbsolute = 1
639         lc.groupSpacing = lc.width * 2.0 / len(self._catNames)
640         lc.joinedLines = 1
641         lc.lineLabelFormat = self._lcstyle.format[0]
642
643         lc.valueAxis.valueMin, lc.valueAxis.valueMax, lc.valueAxis.valueSteps = self._value
644         lc.valueAxis.labelTextFormat = self._lcstyle.format[1]
645         lc.valueAxis.labels.fontSize = self._lcstyle.labelsfont
646
647         lc.categoryAxis.categoryNames = self._catNames
648         lc.categoryAxis.labels.boxAnchor = 'ne'
649         lc.categoryAxis.labels.dx = lc.width / 2.0 / len(self._catNames)
650         lc.categoryAxis.labels.dy = -6
651         lc.categoryAxis.labels.angle = 10
652         lc.categoryAxis.labels.fontSize = self._lcstyle.labelsfont
653         #        lc.categoryAxis.visibleGrid = 1
654         #        lc.categoryAxis.tickUp = 100
655         #        lc.categoryAxis.tickDown = 50
656         #        lc.categoryAxis.gridEnd = dh
657         sytle_cnts = len(self._lcstyle.linestyle)
658         color_paris = []
659         for i in range(line_cnts):
660             styleIndex = i % sytle_cnts
661             lc.lines[i].strokeColor = self._lcstyle.linestyle[styleIndex][0]
662             lc.lines[i].symbol = makeMarker(
663                 self._lcstyle.linestyle[styleIndex][1])
664             lc.lines[i].strokeWidth = self._lcstyle.linestyle[styleIndex][2]
665             color_paris.append(
666                 (self._lcstyle.linestyle[styleIndex][0], self._linename[i]))
667
668         lc.lineLabels.fontSize = self._lcstyle.labelsfont - 2
669
670         draw.add(lc)
671
672         lg = Legend()
673         lg.colorNamePairs = color_paris
674         lg.fontName = 'Helvetica'
675         lg.fontSize = 7
676         #        lg.x = dw /2
677         #        lg.y = self._lcstyle.bottom *(1.5 + lg_line)
678
679         lg.x = self._lcstyle.left * 3
680         lg.y = self._lcstyle.bottom * (1 + lg_line) + lc.height
681
682         lg.dxTextSpace = 5
683         lg.dy = 5
684         lg.dx = 20
685         lg.deltax = 60
686         lg.deltay = 0
687         lg.columnMaximum = 1
688         lg.alignment = 'right'
689         draw.add(lg)
690         self._draw = draw
691
692
693 class eBarChartColumn(object):
694
695     def __init__(self, data, style):
696         self._bcstyle = style
697         if len(data) < 4:
698             return
699         self._data = self.analysisData(data)
700         if self._data:
701             self.create()
702
703     @property
704     def draw(self):
705         return self._draw
706
707     def analysisData(self, data):
708         self._ytitle = data[0]
709         self._name = data[1]
710         self._bar = data[2]
711         bar_data = data[3]
712         result = []
713         for bar in bar_data:
714             bar = map(lambda x: float(x), bar)
715             result.append(tuple(bar))
716         return result
717
718     def create(self):
719         dw = self._bcstyle.width
720         dh = self._bcstyle.height
721         draw = Drawing(dw, dh)
722
723         bc = VerticalBarChart()
724         bar_cnt = len(self._bar)
725         lg_line = (bar_cnt + 3) / 4
726
727         bc.width = dw - self._bcstyle.left - self._bcstyle.right
728         bc.height = dh - self._bcstyle.top - self._bcstyle.bottom
729         if bar_cnt > 1:
730             bc.height -= lg_line * 15
731
732         bc.x = self._bcstyle.left
733         bc.y = self._bcstyle.bottom
734         color_paris = []
735         for i in range(bar_cnt):
736             bc.bars[i].fillColor = self._bcstyle.pillarstyle[self._bar[i]][0]
737             color_paris.append(
738                 (self._bcstyle.pillarstyle[
739                     self._bar[i]][0],
740                     self._bar[i]))
741
742         bc.fillColor = self._bcstyle.background
743         bc.barLabels.fontName = 'Helvetica'
744         bc.barLabelFormat = self._bcstyle.pillarstyle[self._bar[0]][1]
745         bc.barLabels.fontSize = self._bcstyle.labelsfont
746         bc.barLabels.dy = self._bcstyle.labelsfont
747         bc.valueAxis.labels.fontName = 'Helvetica'
748         bc.valueAxis.labels.fontSize = self._bcstyle.labelsfont
749         bc.valueAxis.forceZero = 1
750         bc.valueAxis.valueMin = 0
751
752         bc.data = self._data
753         bc.barSpacing = self._bcstyle.barSpacing
754         bc.groupSpacing = self._bcstyle.groupSpacing / bar_cnt
755         bc.valueAxis.avoidBoundFrac = 1
756         bc.valueAxis.gridEnd = dw - self._bcstyle.right
757         bc.valueAxis.tickLeft = self._bcstyle.tick
758         bc.valueAxis.visibleGrid = 1
759         bc.categoryAxis.categoryNames = self._name
760         bc.categoryAxis.tickDown = self._bcstyle.tick
761         bc.categoryAxis.labels.fontName = 'Helvetica'
762         bc.categoryAxis.labels.fontSize = self._bcstyle.labelsfont
763         bc.categoryAxis.labels.dy = -27
764         bc.categoryAxis.labels.angle = -90
765         draw.add(bc)
766         lb = Label()
767         lb.fontName = 'Helvetica'
768         lb.fontSize = 7
769         lb.x = 12
770         lb.y = 80
771         lb.angle = 90
772         lb.textAnchor = 'middle'
773         lb.maxWidth = 100
774         lb.height = 20
775         lb._text = self._ytitle
776         draw.add(lb)
777         if bar_cnt > 1:
778             lg = Legend()
779             lg.colorNamePairs = color_paris
780             lg.fontName = 'Helvetica'
781             lg.fontSize = 7
782
783             lg.x = self._bcstyle.left + bc.width / (bar_cnt + 1)
784             lg.y = dh - self._bcstyle.top - lg_line * 5
785
786             lg.dxTextSpace = 5
787             lg.dy = 5
788             lg.dx = 25
789             lg.deltax = 80
790             lg.deltay = 0
791             lg.columnMaximum = 1
792             lg.alignment = 'right'
793             draw.add(lg)
794
795         self._draw = draw
796
797
798 class eParagraph(object):
799
800     def __init__(self, data, style):
801         self._pstyle = style
802         self._data = self.analysisData(data)
803         self.create()
804
805     def analysisData(self, data):
806         result = ""
807         for dstr in data:
808             if self._pstyle.name == 'ps_body':
809                 #               dstr = "<i>" + dstr + "</i><br/>"
810                 dstr = dstr + "<br/>"
811             else:
812                 dstr = dstr + "<br/>"
813             result += dstr
814         return result
815
816     def create(self):
817         self._para = Paragraph(self._data, self._pstyle)
818
819     @property
820     def para(self):
821         return self._para