def _draw_legend_line(self, index, series_name): end = PDFCursor(self.legend_data_start.x + 10, self.legend_data_start.y + 10) box = PDFRectangle(self.session, self.page, self.legend_data_start, end, None, self.bar_fill_colors[index], style="F", stroke="solid") box._draw() end.x_plus(10) text = PDFText(self.session, self.page, series_name, cursor=end, color=self.base_color) self.legend_data_start.y_plus(1.75 * self._legend_line_height)
def draw_tick(self, x1, y1, x2, y2): x = PDFCursor(x1, y1) y = PDFCursor(x2, y2) if self.axis: tick = PDFLine(self.session, self.page, x, y, self.base_color, "solid") tick._draw()
def _draw_legend_title(self, legend_title="Legend"): text_width = self.session.parent.document.font._string_width(legend_title) text_height = self.session.parent.document.font.font_size text_cursor = PDFCursor(self.legend_start_cursor.x + (self.legend_width - text_width) / 2.0, self.legend_start_cursor.y + 1.2 * text_height) legend_title = PDFText(self.session, self.page, "Legend", cursor=text_cursor) self.legend_data_start = PDFCursor(self.legend_start_cursor.x + 10, self.legend_start_cursor.y + 3 * text_height)
def createSmallArc(self, radius, a1, a2): a = (a2 - a1) / 2.0 x4 = radius * math.cos(a) y4 = radius * math.sin(a) x1 = x4 y1 = -y4 q1 = x1**2 + y1**2 q2 = q1 + x1*x4 + y1*y4 k2 = (4.0/3.0) * (math.sqrt(2 * q1 * q2) - q2) / (x1 * y4 - y1 * x4) x2 = x1 - k2 * y1 y2 = y1 + k2 * x1 x3 = x2 y3 = -y2 ar = a + a1 cos_ar = math.cos(ar) sin_ar = math.sin(ar) return { "p0": PDFCursor(self.center.x + (radius * math.cos(a1)), self.center.y - radius * math.sin(a1)), "p1": PDFCursor(self.center.x + (x2 * cos_ar - y2 * sin_ar), self.center.y - (x2 * sin_ar + y2 * cos_ar)), "p2": PDFCursor(self.center.x + (x3 * cos_ar - y3 * sin_ar), self.center.y - (x3 * sin_ar + y3 * cos_ar)), "p3": PDFCursor(self.center.x + (radius * math.cos(a2)), self.center.y - (radius * math.sin(a2))) }
def __init__(self, orientation="P", layout="letter", margin=None): # Additional layout sizes may be added to this dictionary. # Width then height, in pixels, in portrait orientation. self.layout_dict = {'a3': (841.89, 1190.55), 'a4': (595.28, 841.89), 'a5': (420.94, 595.28), 'letter': (612, 792), 'legal': (612, 1008), '11x17': (792, 1224) } self.set_page_size(layout) # "P" or "L" self.orientation = orientation # Each page has a cursor. self.cursor = PDFCursor() # Initialize the Page Margin. self.margin = margin self.set_orientation(orientation) self.set_margins(margin) self.orientation_change = False self.buffer = ""
def _draw_legend_line(self, index, series_name): line_height = self.session.parent.document.font.font_size end = PDFCursor(self.legend_data_start.x + 15, self.legend_data_start.y) line = PDFLine(self.session, self.page, self.legend_data_start, end, color=self.line_colors[index]) line._draw() end.x_plus(10) end.y_plus(0.25 * line_height) text = PDFText(self.session, self.page, series_name, cursor=end) self.legend_data_start.y_plus(1.75 * line_height)
def _draw_legend_line(self, index, series_name): end = PDFCursor(self.legend_data_start.x + 10, self.legend_data_start.y + 10) box = PDFRectangle(self.session, self.page, self.legend_data_start, end, None, self.fill_colors[index], style="F", stroke="solid") box._draw() end.x_plus(10) text = PDFText(self.session, self.page, series_name, cursor=end, color=self.base_color) w = end.x + 4 if w > self.max_x: self.max_x = w self.legend_data_start.y_plus(1.75 * self._legend_line_height)
def draw_axis_titles(self, x_title=None, y_title=None): if x_title is not None: label_cursor_x = PDFCursor(self.origin.x + (self.width - self.padding[0])/ 2.0, self.origin.y + 0.8 * self.padding[1]) PDFText(self.session, self.page, x_title, cursor=label_cursor_x) if y_title is not None: if self.padding[0] == 0: self.padding = (self.width * 0.12, self.padding[1]) label_cursor_y = PDFCursor(self.origin.x - 0.8 * self.padding[0], self.origin.y - (self.height / 2.0) - 0.8 * self.padding[1]) text = PDFText(self.session, self.page, None, cursor=label_cursor_y) text.text_rotate(-90) text._text(y_title)
def draw_bars(self): x_space = int(self.bar_padding * self.x_delta) i = 0 for pair in self.data: draw, fill = self._get_colors(i) cursor1 = PDFCursor(self.x_array[i][1] + x_space, self.interpolate(pair[1], self.y_array)) cursor2 = PDFCursor(self.x_array[i][1] + self.x_delta - x_space, self.origin.y) rect = PDFRectangle(self.session, self.page, cursor1, cursor2, draw, fill, self.bar_style, "solid") rect._draw() i += 1
def get_cursors(self, cursors): xlist = [i.x for i in cursors] ylist = [i.y for i in cursors] min_x = min(xlist) min_y = min(ylist) max_x = max(xlist) max_y = max(ylist) x_sum = 0 y_sum = 0 xy_sum = 0 x2_sum = 0 y2_sum = 0 N = 0 for cursor in cursors: x = cursor.x y = cursor.y x_sum += x y_sum += y xy_sum += x * y x2_sum += x**2 y2_sum += y**2 N += 1 self.cursor_slope = ((N * xy_sum) - (x_sum * y_sum)) / ((N * x2_sum) - (x_sum**2)) self.cursor_intercept = ((x2_sum * y_sum) - (x_sum * xy_sum)) / ((N * x2_sum) - (x_sum**2)) x1 = 0 y1 = 0 if self.cursor_intercept < min_y: y1 = min_y x1 = self._get_x_at_y(y1) if self.cursor_intercept >= min_y: x1 = min_x y1 = self._get_y_at_x(x1) x2 = max_x y2 = self._get_y_at_x(x2) if y2 > max_y: y2 = max_y x2 = self._get_x_at_y(y2) return PDFCursor(x1, y1), PDFCursor(x2, y2)
def draw_x_axis(self, zero=True): # Draw x axis ticks self.x_array = [(0, self.origin.x)] try: x_delta = self.width / (float(self.x_range[1] - self.x_range[0]) / float(self.frequency[0])) except ZeroDivisionError: x_delta = self.width / 2.0 self.x_delta = x_delta y_delta = 3 tick_x = self.origin.x i = self.x_range[0] k = 0 self.draw_tick(tick_x, self.origin.y, tick_x, self.origin.y + y_delta) if zero: self.draw_x_label(i, k, tick_x, self.origin.y) while i < self.x_range[1]: i += self.frequency[0] tick_x += x_delta self.x_array.append((i, tick_x)) self.draw_tick(tick_x, self.origin.y, tick_x, self.origin.y + y_delta) self.draw_x_label(i, k, tick_x, self.origin.y) k += 1 cursor2 = PDFCursor(tick_x, self.origin.y) if self.axis: xaxis = PDFLine(self.session, self.page, self.origin, cursor2, self.base_color, stroke="solid") xaxis._draw()
def __init__(self, orientation="P", layout="letter"): # Additional layout sizes may be added to this dictionary. # Width then height, in pixels, in portrait orientation. self.layoutdict = {'a3': (841.89, 1190.55), 'a4': (595.28, 841.89), 'a5': (420.94, 595.28), 'letter': (612, 792), 'legal': (612, 1008), '11x17': (792, 1224) } self._setPageSize(layout) # "P" or "L" self.orientation = orientation # Each page has a cursor. self.cursor = PDFCursor() # Initialize the Page Margin. self.margin = None self.setOrientation(orientation) self.setMargins() self.orientation_change = False self.buffer = ""
def _draw_title(self): if self.title is not None: save_font = self.font self.session.parent.document.set_font(save_font.family, "b", save_font.font_size * 1.2) title_cursor = PDFCursor(self.origin.x + (self.width - self.session.parent.document.font._string_width(self.title))/ 2.0, self.origin.y - self.height - (self.padding[1] * 0.4)) title = PDFText(self.session, self.page, self.title, cursor=title_cursor, color=self.base_color) self.session.parent.document.set_font(font=save_font)
def draw_y_axis(self, zero=True): # Draw y axis ticks self.y_array = [(self.y_range[0], self.origin.y)] try: y_delta = self.height / (float(self.y_range[1] - self.y_range[0]) / float(self.frequency[1])) except ZeroDivisionError: y_delta = self.height / 2.0 x_delta = 3 tick_y = self.origin.y j = self.y_range[0] k = 0 self.draw_tick(self.origin.x, tick_y, self.origin.x - x_delta, tick_y) if zero: self.draw_y_label(j, k, self.origin.x - x_delta, tick_y) while j < self.y_range[1]: j += self.frequency[1] tick_y -= y_delta self.y_array.append((j, tick_y)) self.draw_tick(self.origin.x, tick_y, self.origin.x - x_delta, tick_y) self.draw_y_label(j, k, self.origin.x - x_delta, tick_y) k += 1 # Draw axis lines cursor1 = PDFCursor(self.origin.x, tick_y) if self.axis: yaxis = PDFLine(self.session, self.page, cursor1, self.origin, self.base_color, stroke="solid") yaxis._draw()
def _draw_dots(self, cursors): if self.dots is not None: for cursor in cursors: dot = PDFEllipse(self.session, self.page, cursor, PDFCursor(self.dots, self.dots), style="F") dot._draw()
def _draw_legend_box(self): end_cursor = PDFCursor( self.legend_start_cursor.x + self.legend_width, self.legend_data_start.y + 1.2 * self.session.parent.document.font.font_size) legend_box = PDFRectangle(self.session, self.page, self.legend_start_cursor, end_cursor, self.base_color) legend_box._draw()
def draw_y_label(self, i, k, x1, y1): if self.axis_labels is None: return elif self.axis_labels is "Auto": text = i else: text = self.axis_labels["y"][k] cursor = PDFCursor(x1 - self.font._string_width(text) - 1, y1 + 2) label = PDFText(self.session, self.page, '%s' % text, cursor=cursor)
def draw_bars(self): x_space = int(self.bar_padding * self.x_delta) sub_array = [] for x in self.x_array: sub_array.append((x[0], x[1] + x_space)) self.new_x_array = [sub_array] new_x_delta = self.x_delta / float(len(self.data)) for series in range(1, len(self.data)): sub_array = [] for pair in self.x_array: sub_array.append((pair[0], pair[1] + new_x_delta)) self.new_x_array.append(sub_array) if self.legend is not None: self._legend_line_height = self.session.parent.document.font.font_size self.legend_start_cursor.x_plus(-self.padding[0] * 0.5) self.legend_width += self.padding[0] * 0.55 self._draw_legend_title() j = 0 for series in self.data: values_list = series.values()[0] draw, fill = self._get_colors(j) if self.legend is not None: self._draw_legend_line(j, series.keys()[0]) i = 0 for pair in values_list: cursor1 = PDFCursor(self.new_x_array[j][i][1], self.interpolate(pair[1], self.y_array)) cursor2 = PDFCursor( self.new_x_array[j][i][1] + new_x_delta - x_space, self.origin.y) rect = PDFRectangle(self.session, self.page, cursor1, cursor2, draw, fill, self.bar_style, "solid") rect._draw() i += 1 j += 1 if self.legend is not None: self._draw_legend_box()
def _draw_background(self, width, height): if self.background.exists: cursor_end = PDFCursor(self.origin.x + width, self.origin.y + height) rectangle = PDFRectangle(self.session, self.page, self.origin, cursor_end, self.background.border_color, self.background.fill_color, self.background.style, self.background.stroke, self.background.size) rectangle._draw()
def _pad(self, width, height): self.origin.x_plus(self.padding[0]) self.origin.y_plus(-self.padding[1] + height) if self.legend == "right": self.width = (0.8 * width) - (2 * self.padding[0]) self.legend_width = 0.2 * width - (self.padding[0] * 0.2) self.height = height - 2 * self.padding[1] self.legend_height = self.height self.legend_start_cursor = PDFCursor(self.origin.x + self.width + self.padding[0], self.origin.y - self.height) else: self.width = width - 2 * self.padding[0] self.height = height - 2 * self.padding[1]
def draw_data(self): if self.legend is not None: self._draw_legend_title() i = 0 for series in self.data: if self.legend is not None: self._draw_legend_line(i, series.keys()[0]) series = series.values()[0] self._set_color(i) self.line = LinearRegressionLine() i += 1 cursors = [] for value in series: cursor = self.get_coord(value) cursors.append(cursor) self.line.add_data(value) self._draw_dots(cursors) if self.linear_regression: self.line.calculate_line() cursor1, cursor2 = self.line.get_cursors(cursors) trend = PDFLine(self.session, self.page, cursor1, cursor2) trend._draw() if self.linear_regression_equation: text = self.line.get_equation() text_width = self.session.parent.document.font._string_width( text) text_height = self.session.parent.document.font.font_size * 1.2 x = cursor2.x + (-text_width) y = self.line._get_y_at_x(x) + text_height PDFText(self.session, self.page, text, cursor=PDFCursor(x, y)) if self.legend is not None: self._draw_legend_box()
def draw_base_circle(self): circle = PDFEllipse(self.session, self.page, self.center_cursor, PDFCursor(self.radius, self.radius), self.base_color, None, style="S", stroke="solid", size=1) circle._draw()
def _set_center(self): self.center_cursor = PDFCursor(self.origin.x + self.width / 2.0, self.origin.y - self.height / 2.0) self.radius = min(self.width, self.height) / 2.0
def get_coord(self, tuple): x = self.interpolate(tuple[0], self.x_array) y = self.interpolate(tuple[1], self.y_array) return PDFCursor(x, y)
def draw_x_label(self, i, k, x1, y1): text = self.data[k][0] cursor = PDFCursor( x1 - (self.x_delta + self.font._string_width(text)) / 2.0, y1 + 9) label = PDFText(self.session, self.page, '%s' % text, cursor=cursor)
class PDFPage(object): """ Defines the structure of an individual page. Margins are set by default. If you want to change them, it should be done through the Document object, or before any content is written to the page. """ def __init__(self, orientation="P", layout="letter"): # Additional layout sizes may be added to this dictionary. # Width then height, in pixels, in portrait orientation. self.layoutdict = {'a3': (841.89, 1190.55), 'a4': (595.28, 841.89), 'a5': (420.94, 595.28), 'letter': (612, 792), 'legal': (612, 1008), '11x17': (792, 1224) } self._setPageSize(layout) # "P" or "L" self.orientation = orientation # Each page has a cursor. self.cursor = PDFCursor() # Initialize the Page Margin. self.margin = None self.setOrientation(orientation) self.setMargins() self.orientation_change = False self.buffer = "" def _compress(self): """ Uses zlib to compress page buffers. Compression option is enabled through PDFLite object's setCompression method. """ self.buffer = compress(self.buffer) def _setIndex(self, value): self.index = value def _setPageSize(self, layout): self.layout = layout.lower() if self.layout in self.layoutdict: self.pagesize = self.layoutdict[self.layout] else: raise Exception('Unknown page layout: ', self.layout) def _setDimensions(self): self.width = self.size[0] self.height = self.size[1] def setOrientation(self, orientation="P"): self.orientation = orientation.lower() if(self.orientation == 'p' or self.orientation == 'portrait'): self.size = self.pagesize elif(self.orientation == 'l' or self.orientation == 'landscape'): self.size = (self.pagesize[1], self.pagesize[0]) else: raise Exception('Incorrect orientation: ', self.orientation) self._setDimensions() self._setBounds() def changeOrientation(self): if self.orientation_change is False: self.size = (self.size[1], self.size[0]) self.orientation_change = True self._setDimensions() self._setBounds() else: pass def setMargins(self, margin=None): if margin is None: self.margin = PDFMargin() elif isinstance(margin, PDFMargin): self.margin = margin else: raise Exception("Invalid Margin object") self._setDimensions() self._setBounds() def _setBounds(self): if self.margin is None: xmin = 0 xmax = self.size[0] ymin = self.size[1] ymax = 0 else: xmin = 0 + self.margin.l xmax = self.size[0] - self.margin.r ymin = self.size[1] - self.margin.t ymax = 0 + self.margin.b self.cursor.setBounds(xmin, ymin, xmax, ymax) def addNewline(self, font, number=1): self.cursor.yPlus((font.linesize*number)) self.cursor.xReset() def addIndent(self, font, number=4): self.cursor.xPlus(number * font.stringWidth(' '))
class PDFPage(object): """ Defines the structure of an individual page. Margins are set by default. If you want to change them, it should be done through the Document object, or before any content is written to the page. """ def __init__(self, orientation="P", layout="letter", margin=None): # Additional layout sizes may be added to this dictionary. # Width then height, in pixels, in portrait orientation. self.layout_dict = {'a3': (841.89, 1190.55), 'a4': (595.28, 841.89), 'a5': (420.94, 595.28), 'letter': (612, 792), 'legal': (612, 1008), '11x17': (792, 1224) } self.set_page_size(layout) # "P" or "L" self.orientation = orientation # Each page has a cursor. self.cursor = PDFCursor() # Initialize the Page Margin. self.margin = margin self.set_orientation(orientation) self.set_margins(margin) self.orientation_change = False self.buffer = "" # Page may be retrieved and manipulated using these: def set_orientation(self, orientation="P"): self.orientation = orientation.lower() if self.orientation == 'p' or self.orientation == 'portrait': self.size = self.page_size elif self.orientation == 'l' or self.orientation == 'landscape': self.size = (self.page_size[1], self.page_size[0]) else: raise Exception('Incorrect orientation: ', self.orientation) self._set_dimensions() self._set_bounds() def set_page_size(self, layout): """ Valid choices: 'a3, 'a4', 'a5', 'letter', 'legal', '11x17'. """ self.layout = layout.lower() if self.layout in self.layout_dict: self.page_size = self.layout_dict[self.layout] else: dimensions = self.layout.split('x') if len(dimensions) == 2: self.page_size = (float(dimensions[0]) * 72, float(dimensions[1]) * 72) else: raise IndexError("Page is two dimensions, given: %s" % len(dimensions)) def set_margins(self, margin=None): if margin is None: self.margin = PDFMargin() elif isinstance(margin, PDFMargin): self.margin = margin else: raise Exception("Invalid Margin object") self._set_dimensions() self._set_bounds() def get_margins(self): return self.margin # Private methods for building pages def _compress(self): """ Uses zlib to compress page buffers. Compression option is enabled through PDFLite object's setCompression method. """ self.buffer = compress(self.buffer) def _set_index(self, value): self.index = value def _set_dimensions(self): self.width = self.size[0] self.height = self.size[1] def _change_orientation(self): if self.orientation_change is False: self.orientation_change = True else: self.orientation_change = False self.size = (self.size[1], self.size[0]) self._set_dimensions() self._set_bounds() def _set_cursor(self, cursor): self.cursor = cursor self._set_bounds() def _set_bounds(self): if self.margin is None: xmin = 0 xmax = self.size[0] ymin = 0 ymax = self.size[1] else: xmin = 0 + self.margin.left xmax = self.size[0] - self.margin.right ymin = 0 + self.margin.top ymax = self.size[1] - self.margin.bottom self.cursor.set_bounds(xmin, ymin, xmax, ymax, self.size[1]) def _add_newline(self, font, number=1, double_spacing=None): if double_spacing is not None: self.cursor.y_plus((font.line_size * number * double_spacing)) self.cursor.y_plus((font.line_size * number)) self.cursor.x_reset() def _add_indent(self, font, number=4): self.cursor.x_plus(number * font._string_width(' '))