def add_ytics_chipseq(self): """ Add Y ticks to the svg plot """ steps = round(self.maxh / 5, 1) if self.maxh else 1 labels = [0, steps, 2 * steps, 3 * steps, 4 * steps, 5 * steps] ytics = [ round( self.height - self.BOTTOM_MARGIN - (self.dimension_y / 5 * y), 3) for y in range(0, 6) ] spacing = (ytics[0] - ytics[1]) / 2 for tic, label in zip(ytics, labels): ticline = Rect(insert=(self.MARGIN - 2, tic), size=(5, 1), fill=LEGEND_COLOUR) if tic - spacing > self.MARGIN: ticline2 = Rect(insert=(self.MARGIN - 2, tic - spacing), size=(2, 1), fill=LEGEND_COLOUR) self.elements.append(ticline2) tic_x = self.MARGIN - SMALL_FONT * 2 tic_y = tic + 1 if len(str(label)) == 1: tic_x += 3 if len(str(label)) == 2: tic_x += 2 if len(str(label)) >= 3: tic_x -= 10 ticmarker = (Text(str(label), insert=(tic_x, tic_y), fill=LEGEND_COLOUR, font_size=SMALL_FONT)) self.elements.append(ticline) self.elements.append(ticmarker)
def add_ytics_methylation(self): """ Add Y ticks to the svg plot """ labels = [0, 0.2, 0.4, 0.6, 0.8, 1] ytics = [ round((self.MARGIN + self.dimension_y) - (y * self.dimension_y), 3) for y in labels ] spacing = (ytics[0] - ytics[1]) / 2 for tic, label in zip(ytics, labels): ticline = Rect(insert=(self.width - self.RIGHT_MARGIN, tic), size=(5, 1), fill=LEGEND_COLOUR) if tic - spacing > self.MARGIN: ticline2 = Rect(insert=(self.width - self.RIGHT_MARGIN, tic - spacing), size=(2, 1), fill=LEGEND_COLOUR) self.elements.append(ticline2) tic_x = self.width - self.RIGHT_MARGIN + SMALL_FONT tic_y = tic + 1 if len(str(label)) == 1: tic_x += 3 if len(str(label)) == 2: tic_x += 2 ticmarker = (Text(str(label), insert=(tic_x, tic_y), fill=LEGEND_COLOUR, font_size=SMALL_FONT)) self.elements.append(ticline) self.elements.append(ticmarker)
def draw_genes(self, genes): for gene in genes: for transcript in gene['transcripts']: start = self.convert_xcoord_to_pos(gene['start']) length = self.convert_xcoord_to_pos(gene['end']) - start if start < self.MARGIN: if start < 0: # first, remove anything before zero. length += start start = 0 length -= ( self.MARGIN + start ) # then remove anything before the margin begins start = self.MARGIN if start + length > (self.width - self.RIGHT_MARGIN): length = (self.width - self.RIGHT_MARGIN) - start if gene['strand'] == 1: text = gene['name'] + " ->>>" else: text = " <<<- " + gene['name'] # print "(self.width + self.RIGHT_MARGIN + self.MARGIN)", (self.width - self.RIGHT_MARGIN) # print "gene -> text:{} chrend:{} chrstart:{} start:{} length:{}" # .format(gene['name'], gene['end'], gene['start'], start, length)_ g_rect = Rect(insert=(start, self.height - self.BOTTOM_MARGIN + self.gene_offset + 4), size=(length, 2), fill="grey") g_text = (Text(text, insert=(start, self.height - self.BOTTOM_MARGIN + self.gene_offset + 9), fill=LEGEND_COLOUR, font_size=SMALL_FONT)) self.elements.append(g_rect) self.elements.append(g_text) for exon in gene["transcripts"][transcript]["exons"]: exon_info = gene["transcripts"][transcript]["exons"][exon] e_start = self.convert_xcoord_to_pos(exon_info["start"]) e_len = self.convert_xcoord_to_pos( exon_info['end']) - e_start if e_start > (self.width - self.RIGHT_MARGIN) or ( e_start + e_len) < self.MARGIN: continue if e_start < self.MARGIN: e_start = self.MARGIN if e_start + e_len > (self.width - self.RIGHT_MARGIN): e_len = (self.width - self.RIGHT_MARGIN) - e_start e_rect = Rect(insert=(e_start, self.height - self.BOTTOM_MARGIN + self.gene_offset), size=(e_len, 9), fill="grey") self.elements.append(e_rect) self.gene_offset += 12 if self.gene_offset > 250: self.gene_offset = self.GENE_OFFSET
def get_4cat_canvas(path, width, height, header=None, footer="made with 4cat - 4cat.oilab.nl", fontsize_normal=None, fontsize_small=None, fontsize_large=None): """ Get a standard SVG canvas to draw 4CAT graphs to Adds a border, footer, header, and some basic text styling :param path: The path where the SVG graph will be saved :param width: Width of the canvas :param height: Height of the canvas :param header: Header, if necessary to draw :param footer: Footer text, if necessary to draw. Defaults to shameless 4CAT advertisement. :param fontsize_normal: Font size of normal text :param fontsize_small: Font size of small text (e.g. footer) :param fontsize_large: Font size of large text (e.g. header) :return SVG: SVG canvas (via svgwrite) that can be drawn to """ from svgwrite.container import SVG from svgwrite.drawing import Drawing from svgwrite.shapes import Rect from svgwrite.text import Text if fontsize_normal is None: fontsize_normal = width / 75 if fontsize_small is None: fontsize_small = width / 100 if fontsize_large is None: fontsize_large = width / 50 # instantiate with border and white background canvas = Drawing(str(path), size=(width, height), style="font-family:monospace;font-size:%ipx" % fontsize_normal) canvas.add(Rect(insert=(0, 0), size=(width, height), stroke="#000", stroke_width=2, fill="#FFF")) # header if header: header_shape = SVG(insert=(0, 0), size=("100%", fontsize_large * 2)) header_shape.add(Rect(insert=(0, 0), size=("100%", "100%"), fill="#000")) header_shape.add( Text(insert=("50%", "50%"), text=header, dominant_baseline="middle", text_anchor="middle", fill="#FFF", style="font-size:%ipx" % fontsize_large)) canvas.add(header_shape) # footer (i.e. 4cat banner) if footer: footersize = (fontsize_small * len(footer) * 0.7, fontsize_small * 2) footer_shape = SVG(insert=(width - footersize[0], height - footersize[1]), size=footersize) footer_shape.add(Rect(insert=(0, 0), size=("100%", "100%"), fill="#000")) footer_shape.add( Text(insert=("50%", "50%"), text=footer, dominant_baseline="middle", text_anchor="middle", fill="#FFF", style="font-size:%ipx" % fontsize_small)) canvas.add(footer_shape) return canvas
def draw(self, builder): pos = builder.position(self.pos[0], builder.y + self.pos[1]) size = (builder.image_size, builder.image_size) result = [] title = self.name if self.email: title += " <{}>".format(self.email) color = builder.authors[self.email, "rgb(128, 128, 128)"] result.append(Rect(pos, size, fill=color, stroke=color, stroke_width=10)) result.append(Rect(pos, size, fill=WHITE, stroke=WHITE, stroke_width=5)) image = Image(self.image, pos, size) image.add(Title(title)) result.append(image) return result
def materialOutline(self, lines, layer=None): cfg = self.cfg if self.svg is not None: self.xOffset = 0.0 self.yOffset = cfg.dxfInput.ySize self.svg.add(Rect((0, 0), (cfg.dxfInput.xSize * self.pScale, \ cfg.dxfInput.ySize * self.pScale), \ fill='rgb(255, 255, 255)')) path = self.materialPath if path is None: self.materialPath = Path(stroke_width=.5, stroke='red', \ fill='none') path = self.materialPath for l in lines: (start, end) = l path.push('M', (self.scaleOffset(start))) path.push('L', (self.scaleOffset(end))) if self.d is not None: if layer is None: layer = self.lBorder for l in lines: (start, end) = l self.d.add(dxf.line(cfg.dxfInput.fix(start), \ cfg.dxfInput.fix(end), layer=layer))
def add_cpg(annotations, margin, height, scale_x, start, end, bottom_margin): """draw the regions on the svg graph.""" if annotations is None: return [] elements = [] color_high = 'darkseagreen' color_low = 'deepskyblue' for ((island_start, island_end), colour_type) in annotations['Islands']: if island_start < start: island_start = start if island_end > end: island_end = end x_position = margin + (island_start - start) * scale_x thickness = (island_end - island_start) * scale_x if 'IC' in colour_type: color = color_low opacity = 0.2 elif 'HC' in colour_type: color = color_high opacity = 0.2 else: color = 'white' opacity = 0 island = Rect(insert=(x_position, margin), size=(thickness, height - margin - bottom_margin), fill=color, fill_opacity=opacity) elements.append(island) return elements
def draw_rectangle_around_text(scene: Drawing, origin: tuple, width: int, height: int, fill_color: tuple, line_color: tuple, line_width: int, rounded: int, text: str, font_size: int, font_family: str): scene.add( Rect(insert=origin, size=(width, height), shape_rendering='inherit', fill=rgb(*fill_color), stroke=rgb(*line_color), stroke_width=line_width, rx=rounded, ry=rounded)) # write label in the middle under labelx = origin[0] + width // 2 labely = origin[ 1] + height // 2 + 4 # TODO: Should be drawn in the vertical center, so + 4 not needed! scene.add( Text(text, insert=(labelx, labely), fill=rgb(*line_color), font_family=font_family, font_size=font_size, text_rendering='inherit', alignment_baseline='central', text_anchor='middle') ) # TODO: alignment_baseline should be hanging or baseline! return origin[0], origin[1], width, height
def _draw_cell(self, drw: Drawing, cell, stone_size): from_grid_to_edge = stone_size / 2 + self._margin x = (from_grid_to_edge + (cell.x - 1) * stone_size) y = (from_grid_to_edge + (cell.y - 1) * stone_size) node = cell.node cell = drw.add(drw.g(id=f'cell{cell.x}-{cell.y}')) if node.stone is not None: self._put_stone(cell, x, y, node.stone, stone_size) if node.stone is None: half_size = 3 * stone_size / 8 cell.add( Rect( ((x - half_size) * self.unit, (y - half_size) * self.unit), (2 * half_size * self.unit, 2 * half_size * self.unit), fill="white")) fill = "white" if node.stone == Stone.Black else "black" if isinstance(node.marker, game.Label): self._put_label(cell, x, y, node.marker.label, fill, stone_size) elif isinstance(node.marker, game.Square): self._put_square(cell, fill, stone_size, x, y) elif isinstance(node.marker, game.Circle): self._put_circle(cell, x, y, fill, stone_size) elif isinstance(node.marker, game.Cross): self._put_cross(cell, x, y, fill, stone_size) elif isinstance(node.marker, game.Triangle): self._put_triangle(cell, x, y, fill, stone_size)
def draw(self, start=0, end=None, ext='svg', name=None): if end is None: end = os.path.getsize(self.source_path) if name is None: name = self.source_path.name name = f"{name}.{ext}" if ext == 'svg': from svgwrite import Drawing from svgwrite.shapes import Rect dwg = Drawing(name, profile='tiny') elif ext == 'dxf': from dxfwrite import DXFEngine as dxf dwg = dxf.drawing(name) with open(self.source_path, 'rb') as source_file: for i, bit in enumerate(bits(source_file, start, end)): if bit == self.invert: x = (i // self.height) * self.scale y = (-i % self.height) * self.scale params = { 'insert': (x, y), 'size': (self.scale, self.scale) } if ext == 'dxf': rect = DxfRect(**params).to_face3d() else: rect = Rect(**params) dwg.add(rect) dwg.save()
def rect(self, insert, size, stroke="black", stroke_width=0.5, fill=None): return Rect( insert=insert, size=size, stroke=stroke, stroke_width=stroke_width, fill=fill, )
def decorate_rect_with_class(rect: shapes.Rect, day_date: date, _): """ Decorator for day squares for SVG calendar view Args: rect: day_date: _: Returns: """ day_string = day_date.strftime('%Y-%m-%d') outer = Hyperlink('/byday/' + day_string, '_self') rect.update({'class_': 'dateTrigger'}) rect.update({'id': 'calday-' + day_string}) outer.add(rect) return outer
def draw_inning_stripes(self): y = ORIGIN_Y for i, inning in enumerate(self.game.innings): inning_ht = self.get_inning_height(inning) y += inning_ht if not i % 2: self.dwg.add( Rect((ORIGIN_X, y - inning_ht), (ATBAT_W, inning_ht), class_='inning-fill')) if (not (i == len(self.game.innings) - 1 and self.is_no_final_bottom())): if not i % 2: self.dwg.add( Rect((ORIGIN_X + ATBAT_W + SEPARATION, y - inning_ht), (ATBAT_W, inning_ht), class_='inning-fill'))
def get_axis(width, margin, height, bottom_margin, right_margin): """leave "margin" on either side of the image, draw the axes along the boundaries of the margin.""" margin = margin height = height x_axis = Rect(insert=(margin, height - bottom_margin), size=(width - (margin + right_margin), 1), fill=LEGEND_COLOUR) y_axis = Rect(insert=(margin, margin), size=(1, height - (margin + bottom_margin)), # viewing area is the height, minus the top margin and bottom margin. fill=LEGEND_COLOUR) y_axis2 = Rect(insert=(width - right_margin, margin), size=(1, height - (margin + bottom_margin)), # viewing area is the height, minus the top margin and bottom margin. fill=LEGEND_COLOUR) return x_axis, y_axis, y_axis2
def __init__(self): super().__init__() rect = Rect(insert=(0, 0), size=(5, 5), fill='#9e9e9e') path = Path('M 0 5 L 5 0 Z M 6 4 L 4 6 Z M -1 1 L 1 -1 Z', stroke='#888', stroke_width=1) pattern = Pattern(id=self.__class__.__name__.lower(), patternUnits='userSpaceOnUse', size=(5, 5), stroke='none') pattern.add(rect) pattern.add(path) self.add(pattern)
def draw_theme_palette(theme_configuration, start_point, size, displacement): rects = [] for k, v in theme_configuration.items(): rgb = tuple(int(v[i + 1:i + 3], 16) for i in (0, 2, 4)) rects.append( Rect(start_point, size, fill=svgwrite.utils.rgb(rgb[0], rgb[1], rgb[2]))) start_point = (start_point[0] + displacement[0], start_point[1] + displacement[1]) return rects
def get_team_box(self, id, ht): box = Group() box['id'] = id box['class'] = 'team-box' box.add(Rect((ORIGIN_X, ORIGIN_Y), (ATBAT_W, ht))) box.add( Line((ORIGIN_X + NAME_W, ORIGIN_Y), (ORIGIN_X + NAME_W, ORIGIN_Y + ht))) box.add( Line((ORIGIN_X + NAME_W + SCORE_W, ORIGIN_Y), (ORIGIN_X + NAME_W + SCORE_W, ORIGIN_Y + ht))) return box
def add_xtics(self): """ Create X tics on the plot""" scale_tics = 1 while scale_tics * 10 < self.end - self.start: scale_tics *= 10 xtics = [ i for i in range(self.start, self.end + 1) if i % scale_tics == 0 ] while len(xtics) < 4: scale_tics /= 2 xtics += [ j for j in range(self.start, self.end + 1) if j % scale_tics == 0 and j not in xtics ] xtics.sort() spacing = fabs((self.MARGIN + (xtics[1] - self.start) * self.scale_x) - (self.MARGIN + (xtics[0] - self.start) * self.scale_x)) / 4 for tic in xtics: tic_x = (self.MARGIN + (tic - self.start) * self.scale_x) tic_y = self.height - self.BOTTOM_MARGIN + SMALL_FONT * 1.5 ticmarker = (Text(str(tic), insert=(tic_x, tic_y), fill=LEGEND_COLOUR, font_size=SMALL_FONT)) ticline = Rect(insert=(tic_x, self.height - self.BOTTOM_MARGIN - 2), size=(1, 5), fill=LEGEND_COLOUR) for i in range(1, 4): if tic_x - spacing * i > self.MARGIN - 5: ticline2 = Rect(insert=(tic_x - spacing * i, self.height - self.BOTTOM_MARGIN - 2), size=(1, 2), fill=LEGEND_COLOUR) self.elements.append(ticline2) self.elements.append(ticline) self.elements.append(ticmarker)
def _draw_box(self, width, color, url, labels, y_indent=0, padding_multiplier=1, radius=10): """ Return an SVG Link element containing a Rect and one or more text labels representing a parent object or cable termination point. :param width: Box width :param color: Box fill color :param url: Hyperlink URL :param labels: Iterable of text labels :param y_indent: Vertical indent (for overlapping other boxes) (default: 0) :param padding_multiplier: Add extra vertical padding (default: 1) :param radius: Box corner radius (default: 10) """ self.cursor -= y_indent # Create a hyperlink link = Hyperlink(href=f'{self.base_url}{url}', target='_blank') # Add the box position = (OFFSET + (self.width - width) / 2, self.cursor) height = PADDING * padding_multiplier \ + LINE_HEIGHT * len(labels) \ + PADDING * padding_multiplier box = Rect(position, (width - 2, height), rx=radius, class_='parent-object', style=f'fill: #{color}') link.add(box) self.cursor += PADDING * padding_multiplier # Add text label(s) for i, label in enumerate(labels): self.cursor += LINE_HEIGHT text_coords = (self.center, self.cursor - LINE_HEIGHT / 2) text_color = f'#{foreground_color(color, dark="303030")}' text = Text(label, insert=text_coords, fill=text_color, class_='bold' if not i else []) link.add(text) self.cursor += PADDING * padding_multiplier return link
def get_grid_rects(self): rects: List[Rect] = [] for i in range(0 + self.circle_radius, self.width + self.circle_radius + self.cell_width, self.cell_width): rects.append( Rect(insert=(i, 0), size=(self.line_width, self.height + self.line_width), fill=self.line_color)) rects.append( Rect(insert=(0 + self.circle_radius, 0), size=(self.width, self.line_width * 2), fill=self.line_color)) for i in range(0 + self.cell_height, self.height + self.cell_height, self.cell_height): rects.append( Rect(insert=(self.circle_radius, i), size=(self.width + self.line_width, self.line_width), fill=self.line_color)) return rects
def add_legend(self): # legend: for idx, sample_name in enumerate(sorted(self.legend)): self.plot.add( Text(sample_name + " [" + self.legend[sample_name]['category'] + "]", insert=(self.margin_left + self.plottable_x + 10, self.margin_top + self.plottable_y / 10 + (idx * 15)), fill=self.graph_colour, font_size="15")) self.plot.add( Rect(insert=(self.margin_left + self.plottable_x, self.margin_top + self.plottable_y / 10 + (idx * 15) - 9), size=(8, 8), fill=self.legend[sample_name]['colour']))
def build(self): bin_count = len(self.data) + 1 bin_width = (self.plottable_x - (bin_count + 1) + self.gap) // bin_count # floored division if bin_width < 1: bin_width = 1 for i in range(len(self.data)): for letter in self.alphabet: size = float(self.data[letter]) * self.plottable_y self.plot.add( Text(letter, insert=(self.margin_left + self.gap + (i * (bin_width + self.gap)), self.plottable_y + self.margin_top + 20), fill="yellow", height=size)) self.plot.add( Rect(insert=(self.margin_left + self.gap + (i * (bin_width + self.gap)), (self.margin_top + self.plottable_y) - ((float(self.binned_data[i]) / self.data_max) * self.plottable_y)), size=(bin_width, ((float(self.binned_data[i]) / self.data_max) * self.plottable_y)), fill="red")) self.plot.add( Text(str((i * self.units_per_bin) + self.x_min), insert=(self.margin_left + self.gap + (i * (bin_width + self.gap)), self.plottable_y + self.margin_top + 20), fill="yellow", font_size="15")) self.plot.add( Text(self.x_label, insert=(self.plottable_x / 2, self.plottable_y + self.margin_top + (self.margin_bottom / 2) + 15), fill="yellow", font_size="15")) self.plot.add(Text(str())) self.data = None
def tool_template(name, width_in): g = Group( stroke="black", stroke_width=0.5, font_family="Arial, Helvetica", ) # Border g.add(Rect( (0, 0), (width_in * inch, width_in * inch), fill="none", )) # Lanyard punch g.add( Circle( (0.4 * inch, (width_in - 0.4) * inch), 3.5 * mm, fill="none", )) # plast-karto! g.add( Text( "https://plast-karto.readthedocs.io", ((width_in / 2) * inch, (width_in - 0.3) * inch), text_anchor="middle", font_size=2 * mm, )) g.add( Text( name, ((0.75) * inch, (width_in - 0.75) * inch), text_anchor="middle", font_size=4 * mm, )) g.add(square_rose(width_in)) return g
def add_line(self, instance_xtype): ''' Draw svg line representing DiffxElement. :param instance_xtype: XTypes.DiffxElement ''' _text = instance_xtype.name() _w, _h = render_text.Render.get_text_size(_text) _h += _h * 0.25 _svg = SVG(insert=(self.pos_x, self.pos_y), width=_w, height=_h) _text_svg = Text(_text) _text_svg['x'] = 0 _text_svg['y'] = _h - _h * 0.25 _text_svg['font-size'] = self.font_size _text_svg['font-family'] = self.font_family _text_svg['opacity'] = 1.0 _text_svg['fill'] = rgb(0, 0, 0) _rect_svg = Rect() _rect_svg['x'] = 0 _rect_svg['y'] = 0 _rect_svg['fill'] = instance_xtype.fill _rect_svg['opacity'] = instance_xtype.opacity _rect_svg['height'] = _h _rect_svg['width'] = _w _svg.add(_text_svg) _svg.add(_rect_svg) _svg.viewbox(0, 0, _w, _h) self.pos_y = self.pos_y + _h self.pos_x_max = max(self.pos_x_max, _w + self.pos_x) self.pos_y_max = max(self.pos_y_max, self.pos_y) return _svg
def set_properties(self, filename, title, start, end, width, height): """Set the properties of the canvas on which you'll want to generate your image """ self.elements = [] self.title = title self.start = start self.end = end self.width = width # default = 200.0 self.height = height # default = 60.0 self.dimension_y = self.height - self.MARGIN - self.BOTTOM_MARGIN # this is the size of the y field self.dimension_x = self.width - self.MARGIN - self.RIGHT_MARGIN self.scale_x = float(self.dimension_x) / ( self.end - self.start) # this is a scaling variable self.y_bottom = str(round(self.dimension_y + self.MARGIN, 2)) canvas_size = (str(self.width) + "px", "100%") # create drawing # Default is 100%,100% - don't override that, # as this allows the svg to fit the data and expand as necessary self.plot = Drawing(filename, size=canvas_size) background = Rect(insert=(0, 0), size=canvas_size, fill="white") self.plot.add(background)
def put_pixels(self, colour, pixels): for i in range(pixels): if self.cur_direction: self.cur_x_pos += 1 else: self.cur_x_pos -= 1 if self.cur_direction and self.cur_x_pos >= self.plottable_x: self.cur_y_pos += 1 self.cur_x_pos -= 1 self.cur_direction = not self.cur_direction if not self.cur_direction and self.cur_x_pos < 0: self.cur_y_pos += 1 self.cur_x_pos += 1 self.cur_direction = not self.cur_direction self.plot.add( Rect(insert=(self.margin_left + self.cur_x_pos, (self.margin_top + self.plottable_y) - self.cur_y_pos), size=(1, 1), fill=rgb(colour[0], colour[1], colour[2])))
def add_group_legend(self): # legend: # collapse: groups = set() for sample_detail in self.legend.values(): category = sample_detail['category'] groups.add(category) for idx, category in enumerate(sorted(groups)): colour = self.colour_helper.get_category_colour(category) self.plot.add( Text(category, insert=(self.margin_left + self.plottable_x + 10, self.margin_top + self.plottable_y / 10 + (idx * 15)), fill=self.graph_colour, font_size="15")) self.plot.add( Rect(insert=(self.margin_left + self.plottable_x, self.margin_top + self.plottable_y / 10 + (idx * 15) - 9), size=(8, 8), fill=colour))
def visualize(self, trajectory, output_file): drawing = Drawing() # Определение параметров образов состояний аппарата machine_view_length, machine_view_width = self.__machine_view_size coordinates_scaling = machine_view_length / self.__machine_length machine_diameter = \ ((machine_view_length * 2.0) ** 2.0 + machine_view_width ** 2.0) \ ** 0.5 machine_radius = machine_diameter / 2.0 # Создание последовательности записываемых состояний аппарата def generate_states_sequence(): spawn_time = 0.0 for trajectory_time, state in trajectory: if trajectory_time >= spawn_time: spawn_time += self.__time_interval yield state states_sequence = generate_states_sequence() # Запись последовательности состояний аппарата is_view_box_initialized = False view_box_minimal_x, view_box_minimal_y = 0.0, 0.0 view_box_maximal_x, view_box_maximal_y = 0.0, 0.0 for state in states_sequence: # Создание образа состояния аппарата state_view_angle = - state.coordinates[2] / math.pi * 180.0 state_view_center = \ state.coordinates[0] * coordinates_scaling, \ - state.coordinates[1] * coordinates_scaling state_view_position = \ state_view_center[0], \ state_view_center[1] - machine_view_width / 2.0 state_view = \ Rect( insert = state_view_position, size = self.__machine_view_size, fill = rgb(255, 255, 255), stroke = rgb(0, 0, 0), stroke_width = 1 ) state_view.rotate( state_view_angle, center = state_view_center ) # Добавление образа состояния аппарата к образу траектории drawing.add(state_view) if is_view_box_initialized: view_box_minimal_x, view_box_minimal_y = \ min(state_view_center[0], view_box_minimal_x), \ min(state_view_center[1], view_box_minimal_y) view_box_maximal_x, view_box_maximal_y = \ max(state_view_center[0], view_box_maximal_x), \ max(state_view_center[1], view_box_maximal_y) else: is_view_box_initialized = True view_box_minimal_x, view_box_minimal_y = \ state_view_center[0], \ state_view_center[1] view_box_maximal_x, view_box_maximal_y = \ state_view_center[0], \ state_view_center[1] # Настройка отображения образа траектории drawing.viewbox( minx = view_box_minimal_x - machine_radius, miny = view_box_minimal_y - machine_radius, width = view_box_maximal_x - view_box_minimal_x + machine_diameter, height = view_box_maximal_y - view_box_minimal_y + machine_diameter ) # Запись образа траектории в файл try: drawing.write(output_file) except: raise Exception() #!!!!! Генерировать хорошие исключения
def nest(output, files, wbin, hbin, enclosing_rectangle=False): packer = newPacker() def float2dec(x): return _float2dec(x, 4) def bbox_paths(paths): bbox = None for p in paths: p_bbox = p.bbox() if bbox is None: bbox = p_bbox else: bbox = (min(p_bbox[0], bbox[0]), max(p_bbox[1], bbox[1]), min(p_bbox[2], bbox[2]), max(p_bbox[3], bbox[3])) return tuple(float2dec(x) for x in bbox) all_paths = {} for svg\ in files: paths, attributes = svg2paths(svg) bbox = bbox_paths(paths) for i in range(files[svg]): rid = svg + str(i) all_paths[rid] = {'paths': paths, 'bbox': bbox} print(rid) packer.add_rect(bbox[1] - bbox[0], bbox[3] - bbox[2], rid=rid) print('Rectangle packing...') while True: packer.add_bin(wbin, hbin) packer.pack() rectangles = {r[5]: r for r in packer.rect_list()} if len(rectangles) == len(all_paths): break else: print('not enough space in the bin, adding ') combineds = {} print('packing into SVGs...') for rid, obj in all_paths.items(): paths = obj['paths'] bbox = obj['bbox'] group = Group() width, height = (float2dec(bbox[1] - bbox[0]), float2dec(bbox[3] - bbox[2])) bin, x, y, w, h, _ = rectangles[rid] if bin not in combineds: svg_file = output if bin != 0: splitext = os.path.splitext(svg_file) svg_file = splitext[0] + '.%s' % bin + splitext[1] dwg = Drawing(svg_file, profile='tiny', size=('%smm' % wbin, '%smm' % hbin), viewBox="0 0 %s %s" % (wbin, hbin)) combineds[bin] = dwg combined = combineds[bin] if (width > height and w > h) or \ (width < height and w < h) or \ (width == height and w == h): rotate = 0 dx = -bbox[0] dy = -bbox[2] else: rotate = 90 dx = -bbox[2] dy = -bbox[0] for p in paths: path = Path(d=p.d()) path.stroke(color='red', width='1') path.fill(opacity=0) group.add(path) group.translate(x + dx, y + dy) group.rotate(rotate) combined.add(group) for combined in combineds.values(): if enclosing_rectangle: r = Rect(size=(wbin, hbin)) r.fill(opacity=0) r.stroke(color='lightgray') combined.add(r) print('SVG saving...') combined.save(pretty=True)
def process(self): """ Render an SVG histogram/bar chart using a previous frequency analysis as input. """ self.dataset.update_status("Reading source file") header = self.parameters.get("header", self.options["header"]["default"]) max_posts = 0 # collect post numbers per month intervals = {} for post in self.iterate_csv_items(self.source_file): intervals[post["date"]] = int(post["frequency"]) max_posts = max(max_posts, int(post["frequency"])) if len(intervals) <= 1: self.dataset.update_status("Not enough data available for a histogram; need more than one time series.") self.dataset.finish(0) return self.dataset.update_status("Cleaning up data") (missing, intervals) = pad_interval(intervals) # create histogram self.dataset.update_status("Drawing histogram") # you may change the following four variables to adjust the graph dimensions width = 1024 height = 786 y_margin = 75 x_margin = 50 x_margin_left = x_margin * 2 tick_width = 5 fontsize_normal = int(height / 40) fontsize_small = int(height / 75) # better don't touch the following line_width = round(width / 512) y_margin_top = 150 if header else 50 y_height = height - (y_margin + y_margin_top) x_width = width - (x_margin + x_margin_left) canvas = Drawing(filename=str(self.dataset.get_results_path()), size=(width, height), style="font-family:monospace;font-size:%ipx" % fontsize_normal) # normalize the Y axis to a multiple of a power of 10 magnitude = pow(10, len(str(max_posts)) - 1) # ew max_neat = math.ceil(max_posts / magnitude) * magnitude self.dataset.update_status("Max (normalized): %i (%i) (magnitude: %i)" % (max_posts, max_neat, magnitude)) # draw border canvas.add(Rect( insert=(0, 0), size=(width, height), stroke="#000", stroke_width=line_width, fill="#FFF" )) # draw header on a black background if needed if header: if len(header) > 40: header = header[:37] + "..." header_rect_height = (y_margin_top / 1.5) header_fontsize = (width / len(header)) header_container = SVG(insert=(0, 0), size=(width, header_rect_height)) header_container.add(Rect( insert=(0, 0), size=(width, header_rect_height), fill="#000" )) header_container.add(Text( insert=("50%", "50%"), text=header, dominant_baseline="middle", text_anchor="middle", fill="#FFF", style="font-size:%i" % header_fontsize )) canvas.add(header_container) # horizontal grid lines for i in range(0, 10): offset = (y_height / 10) * i canvas.add(Line( start=(x_margin_left, y_margin_top + offset), end=(width - x_margin, y_margin_top + offset), stroke="#EEE", stroke_width=line_width )) # draw bars item_width = (width - (x_margin + x_margin_left)) / len(intervals) item_height = (height - y_margin - y_margin_top) bar_width = item_width * 0.9 x = x_margin_left + (item_width / 2) - (bar_width / 2) if bar_width >= 8: arc_adjust = max(8, int(item_width / 5)) / 2 else: arc_adjust = 0 for interval in intervals: posts = int(intervals[interval]) bar_height = ((posts / max_neat) * item_height) self.dataset.update_status("%s: %i posts" % (interval, posts)) bar_top = height - y_margin - bar_height bar_bottom = height - y_margin if bar_height == 0: x += item_width continue bar = Path(fill="#000") bar.push("M %f %f" % (x, bar_bottom)) bar.push("L %f %f" % (x, bar_top + (arc_adjust if bar_height > arc_adjust else 0))) if bar_height > arc_adjust > 0: control = (x, bar_top) bar.push("C %f %f %f %f %f %f" % (*control, *control, x + arc_adjust, bar_top)) bar.push("L %f %f" % (x + bar_width - arc_adjust, height - y_margin - bar_height)) if bar_height > arc_adjust > 0: control = (x + bar_width, bar_top) bar.push("C %f %f %f %f %f %f" % (*control, *control, x + bar_width, bar_top + arc_adjust)) bar.push("L %f %f" % (x + bar_width, height - y_margin)) bar.push("Z") canvas.add(bar) x += item_width # draw X and Y axis canvas.add(Line( start=(x_margin_left, height - y_margin), end=(width - x_margin, height - y_margin), stroke="#000", stroke_width=2 )) canvas.add(Line( start=(x_margin_left, y_margin_top), end=(x_margin_left, height - y_margin), stroke="#000", stroke_width=2 )) # draw ticks on Y axis for i in range(0, 10): offset = (y_height / 10) * i canvas.add(Line( start=(x_margin_left - tick_width, y_margin_top + offset), end=(x_margin_left, y_margin_top + offset), stroke="#000", stroke_width=line_width )) # draw ticks on X axis for i in range(0, len(intervals)): offset = (x_width / len(intervals)) * (i + 0.5) canvas.add(Line( start=(x_margin_left + offset, height - y_margin), end=(x_margin_left + offset, height - y_margin + tick_width), stroke="#000", stroke_width=line_width )) # prettify # y labels origin = (x_margin_left / 2) step = y_height / 10 for i in range(0, 11): label = str(int((max_neat / 10) * i)) labelsize = (len(label) * fontsize_normal * 1.25, fontsize_normal) label_x = origin - (tick_width * 2) label_y = height - y_margin - (i * step) - (labelsize[1] / 2) label_container = SVG( insert=(label_x, label_y), size=(x_margin_left / 2, x_margin_left / 5) ) label_container.add(Text( insert=("100%", "50%"), text=label, dominant_baseline="middle", text_anchor="end" )) canvas.add(label_container) # x labels label_width = max(fontsize_small * 6, item_width) label_x = x_margin_left label_y = height - y_margin + (tick_width * 2) next = 0 for interval in intervals: if len(interval) == 7: label = month_abbr[int(interval[5:7])] + "\n" + interval[0:4] elif len(interval) == 10: label = str(int(interval[8:10])) + month_abbr[int(interval[5:7])] + "\n" + interval[0:4] else: label = interval.replace("-", "\n") if label_x > next: shift = 0 for line in label.split("\n"): label_container = SVG( insert=(label_x + (item_width / 2) - (label_width / 2), label_y + (tick_width * 2)), size=(label_width, y_margin), overflow="visible") label_container.add(Text( insert=("50%", "0%"), text=line, dominant_baseline="middle", text_anchor="middle", baseline_shift=-shift )) shift += fontsize_small * 2 canvas.add(label_container) next = label_x + (label_width * 0.9) label_x += item_width # 4cat logo label = "made with 4cat - 4cat.oilab.nl" footersize = (fontsize_small * len(label) * 0.7, fontsize_small * 2) footer = SVG(insert=(width - footersize[0], height - footersize[1]), size=footersize) footer.add(Rect(insert=(0, 0), size=("100%", "100%"), fill="#000")) footer.add(Text( insert=("50%", "50%"), text=label, dominant_baseline="middle", text_anchor="middle", fill="#FFF", style="font-size:%i" % fontsize_small )) canvas.add(footer) canvas.save(pretty=True) self.dataset.update_status("Finished") self.dataset.finish(len(intervals))
# # print(all_pixels) import datetime t1 = datetime.datetime.utcnow() dwg = svgwrite.Drawing( 'asd.svg', # size=('{}px'.format(width), '{}px'.format(height)) size=('420mm', '297mm'), viewBox=('0 0 {} {}'.format(1190 * 2, 841.9 * 2))) rect = Rect( insert=(0, 0), size=('100%', '100%'), stroke='black', fill_opacity=0, ) dwg.add(rect) # g = dwg.add() g = Group() low_clip = .15 high_clip = .65 x_spacing = 10 y_spacing = 15 circle_size = .05
def test_numbers(self): rect = Rect(insert=(0,0), size=(10,20)) self.assertEqual(rect.tostring(), '<rect height="20" width="10" x="0" y="0" />')
def test_coordinates(self): rect = Rect(insert=('10cm','11cm'), size=('20cm', '30cm')) self.assertEqual(rect.tostring(), '<rect height="30cm" width="20cm" x="10cm" y="11cm" />')
def test_corners_numbers(self): rect = Rect(rx=1, ry=1) self.assertEqual(rect.tostring(), '<rect height="1" rx="1" ry="1" width="1" x="0" y="0" />')
def test_corners_length(self): rect = Rect(rx='1mm', ry='1mm') self.assertEqual(rect.tostring(), '<rect height="1" rx="1mm" ry="1mm" width="1" x="0" y="0" />')