Esempio n. 1
1
class Gauge(object):
    config = {
        'id'                    : None,
        'title'                 : 'Title',
        'titleFontColor'        : '#999999',
        'value'                 : 0,
        'valueFontColor'        : '#010101',
        'min'                   : 0,
        'max'                   : 100,
        'showMinMax'            : True,
        'gaugeWidthScale'       : 1.0,
        'gaugeColor'            : '#edebeb',
        'label'                 : "",
        'showInnerShadow'       : True,
        'shadowOpacity'         : 0.2,
        'shadowSize'            : 5,
        'shadowVerticalOffset'  : 3,
        'levelColors'           : ["#a9d70b", "#f9c802", "#ff0000"],
        'levelColorsGradient'   : True,
        'labelFontColor'        : "#b3b3b3",
        'showNeedle'            : False,
        'needleColor'           : "#b3b3b3",
        'canvasWidth'           : 400,
        'canvasHeight'          : 300,
    }

    def __init__(self, *args, **kwargs):
        for param_name, param_value in kwargs.items():
            if self.config.has_key(param_name):
                self.config[param_name] = param_value

        # Overflow values
        if self.config['value'] > self.config['max']:
            self.config['value'] = self.config['max']
        if self.config['value'] < self.config['min']:
            self.config['value'] = self.config['min']
        self.originalValue = self.config['value']

        self.canvas = Drawing(size=(self.config['canvasWidth'],
                                    self.config['canvasHeight']))

        canvasW = self.config['canvasWidth']
        canvasH = self.config['canvasHeight']

        self.canvas.add(self.canvas.rect(insert=(0, 0),
                                         size=(canvasW, canvasH),
                                         stroke="none",
                                         fill="#ffffff"))

        # widget dimensions
        widgetW, widgetH = None, None
        if ((canvasW / canvasH) > 1.25):
            widgetW = 1.25 * canvasH
            widgetH = canvasH
        else:
            widgetW = canvasW
            widgetH = canvasW / 1.25

        # delta 
        dx = (canvasW - widgetW)/2
        dy = (canvasH - widgetH)/2

        # title 
        titleFontSize = ((widgetH / 8) > 10) and (widgetH / 10) or 10
        titleX = dx + widgetW / 2
        titleY = dy + widgetH / 6.5

        # value 
        valueFontSize = ((widgetH / 6.4) > 16) and (widgetH / 6.4) or 16
        valueX = dx + widgetW / 2
        valueY = dy + widgetH / 1.4

        # label 
        labelFontSize = ((widgetH / 16) > 10) and (widgetH / 16) or 10
        labelX = dx + widgetW / 2
        labelY = valueY + valueFontSize / 2 + 6

        # min 
        minFontSize = ((widgetH / 16) > 10) and (widgetH / 16) or 10
        minX = dx + (widgetW / 10) + (widgetW / 6.666666666666667 * self.config['gaugeWidthScale']) / 2
        minY = dy + widgetH / 1.126760563380282

        # max
        maxFontSize = ((widgetH / 16) > 10) and (widgetH / 16) or 10
        maxX = dx + widgetW - (widgetW / 10) - (widgetW / 6.666666666666667 * self.config['gaugeWidthScale']) / 2
        maxY = dy + widgetH / 1.126760563380282

        # parameters
        self.params = {
            'canvasW'         : canvasW,
            'canvasH'         : canvasH,
            'widgetW'         : widgetW,
            'widgetH'         : widgetH,
            'dx'              : dx,
            'dy'              : dy,
            'titleFontSize'   : titleFontSize,
            'titleX'          : titleX,
            'titleY'          : titleY,
            'valueFontSize'   : valueFontSize,
            'valueX'          : valueX,
            'valueY'          : valueY,
            'labelFontSize'   : labelFontSize,
            'labelX'          : labelX,
            'labelY'          : labelY,
            'minFontSize'     : minFontSize,
            'minX'            : minX,
            'minY'            : minY,
            'maxFontSize'     : maxFontSize,
            'maxX'            : maxX,
            'maxY'            : maxY
        }

        # gauge
        self.gauge = self.gauge_path(self.config['max'], self.config['min'], self.config['max'],
                                     self.params['widgetW'], self.params['widgetH'], self.params['dx'],
                                     self.params['dy'], self.config['gaugeWidthScale'],
                                     stroke='none',
                                     fill=self.config['gaugeColor'])

        self.canvas.add(self.gauge)

        # level
        percent_value = (self.config['value'] - self.config['min']) / (self.config['max'] - self.config['min'])
        self.level = self.gauge_path(self.config['value'], self.config['min'], self.config['max'],
                                     self.params['widgetW'], self.params['widgetH'], self.params['dx'],
                                     self.params['dy'], self.config['gaugeWidthScale'],
                                     stroke='none',
                                     fill=self.get_color_for_value(percent_value,
                                                                   self.config['levelColors'],
                                                                   self.config['levelColorsGradient']))
        self.canvas.add(self.level)

        # needle
        if self.config['showNeedle']:
            self.needle = self.needle_path(self.config['value'], self.config['min'], self.config['max'],
                                           self.params['widgetW'], self.params['widgetH'], self.params['dx'],
                                           self.params['dy'], self.config['gaugeWidthScale'],
                                           stroke='none',
                                           fill=self.config['needleColor'])
            self.canvas.add(self.needle)

        # Value
        else:
            text_config = {
                "font-size"     : "%d" % self.params['valueFontSize'],
                "font-weight"   : "bold",
                "font-family"   : "Arial",
                "fill"          : self.config['valueFontColor'],
                "fill-opacity"  : "1",
                "text-anchor"  : 'middle'
            }
            value_text = self.canvas.text('',
                                          insert=('%d' % self.params['valueX'],
                                                  '%d' % self.params['valueY']),
                                          **text_config)
            value_tspan = self.canvas.tspan(self.originalValue,
                                            dy=[8])
            value_text.add(value_tspan)
            self.canvas.add(value_text)

        # Add min & max value
        self.show_minmax()


    def save(self, path):
        svg = self.canvas.tostring()
        svg2png = getattr(cairosvg, 'svg2png')
        png_byte = svg2png(bytestring=svg)
        f = open(path,'w')
        f.write(png_byte)
        f.close()


    def gauge_path(self, value, val_min, val_max, w, h, dx, dy, gws, **extra):
        alpha = (1 - (value - val_min) / (val_max - val_min)) * math.pi
        Ro = w / 2 - w / 10
        Ri = Ro - w / 6.666666666666667 * gws
        Cx = w / 2 + dx
        Cy = h / 1.25 + dy

        Xo = w / 2 + dx + Ro * math.cos(alpha)
        Yo = h - (h - Cy) + dy - Ro * math.sin(alpha)
        Xi = w / 2 + dx + Ri * math.cos(alpha)
        Yi = h - (h - Cy) + dy - Ri * math.sin(alpha)

        path = []
        path.append(u"M%d,%d " % ((Cx - Ri), Cy))
        path.append(u"L%d,%d " % ((Cx - Ro), Cy))
        path.append(u"A%d,%d 0 0,1 %d,%d " % (Ro, Ro, Xo, Yo))
        path.append(u"L%d,%d " % (Xi, Yi))
        path.append(u"A%d,%d 0 0,0 %d,%d " % (Ri, Ri, (Cx - Ri), Cy))
        path.append(u"z ")

        return Path(d=path, **extra)

    def needle_path(self, value, val_min, val_max, w, h, dx, dy, gws, **extra):
        xO = w / 2 + dx
        yO = h / 1.25 + dy

        Rext = w / 2 - w / 10
        Rint = Rext - w / 6.666666666666667 * gws

        x_offset = xO
        y_offset = h - (h - yO) + dy

        val = (value - val_min) / (val_max - val_min)

        angle_b = val<0.5 and val*math.pi or (math.pi - val*math.pi) # Angle de la pointe
        angle_a = math.pi/2 - angle_b
        angle_c = math.pi/2 - angle_b

        rayon_base = 7
        rayon_b = Rint + (Rext-Rint)*10/100

        xA = x_offset + -1 * rayon_base * math.cos(angle_a)
        yA = y_offset - (val<0.5 and -1 or 1) * rayon_base * math.sin(angle_a)

        xC = x_offset + 1 * rayon_base * math.cos(angle_c)
        yC = y_offset - (val<0.5 and 1 or -1) * rayon_base * math.sin(angle_c)

        xB = x_offset + (val<0.5 and -1 or 1) * rayon_b * math.cos(angle_b)
        yB = y_offset - rayon_b * math.sin(angle_b)

        path = []
        path.append(u"M%d,%d " % (xA, yA))
        path.append(u"L%d,%d " % (xB, yB))
        path.append(u"L%d,%d " % (xC, yC))
        path.append(u"A%d,%d 0 1,1 %d,%d " % (rayon_base, rayon_base, xA, yA))
        path.append(u"z ")

        return Path(d=path, **extra)

    def get_color_for_value(self, pct, color, grad):
        no = len(color);
        if no == 1: return color[0]

        HEX = r'[a-fA-F\d]{2}'
        HEX_COLOR = r'#(?P<red>%(hex)s)(?P<green>%(hex)s)(?P<blue>%(hex)s)' % {'hex': HEX}
        inc = grad and (1 / (no - 1)) or (1 / no)
        colors = []
        i = 0
        while i < no:
            percentage = (grad) and (inc * i) or (inc * (i + 1))
            parts = re.match(HEX_COLOR,color[i]).groupdict()

            rval = int(parts['red'], 16)
            gval = int(parts['green'], 16)
            bval = int(parts['blue'], 16)
            colors.append({
                'pct': percentage,
                'color': {
                    'r': rval,
                    'g': gval,
                    'b': bval
                 }
            })
            i+=1

        if pct == 0:
            return 'rgb(%d,%d,%d)' % (colors[0]['color']['r'],
                                      colors[0]['color']['g'],
                                      colors[0]['color']['b'])

        i = 0
        while i < len(colors):
            if pct <= colors[i]['pct']:
                if (grad == True):
                    lower = colors[i-1]
                    upper = colors[i]
                    _range = upper['pct'] - lower['pct']
                    rangePct = (pct - lower['pct']) / _range
                    pctLower = 1 - rangePct
                    pctUpper = rangePct
                    color = {
                      'r': math.floor(lower['color']['r'] * pctLower + upper['color']['r'] * pctUpper),
                      'g': math.floor(lower['color']['g'] * pctLower + upper['color']['g'] * pctUpper),
                      'b': math.floor(lower['color']['b'] * pctLower + upper['color']['b'] * pctUpper)
                    }
                    return 'rgb(%d,%d,%d)' % (color['r'], color['g'], color['b'])
                else:
                    return 'rgb(%d,%d,%d)' % (colors[i]['color']['r'],
                                              colors[i]['color']['g'],
                                              colors[i]['color']['b']) 
            i+=1

    def show_minmax(self):
        # min
        txtMin_config = {
            "font-size"    : '%d' % self.params['minFontSize'],
            "font-weight"  : "normal",
            "font-family"  : "Arial",
            "fill"         : self.config['labelFontColor'],
            "fill-opacity" : self.config['showMinMax'] and "1" or "0",
            "text-anchor"  : 'middle'
        }
        txtMin = self.canvas.text(self.config['min'],
                                  insert=(self.params['minX'],
                                          self.params['minY']),
                                  **txtMin_config)

        self.canvas.add(txtMin)

        # max
        txtMax_config = {
            "font-size"    : '%d' % self.params['maxFontSize'],
            "font-weight"  :"normal",
            "font-family"  :"Arial",
            "fill"         : self.config['labelFontColor'],   
            "fill-opacity" : self.config['showMinMax'] and "1" or "0",
            "text-anchor"  : 'middle'
        }
        txtMax = self.canvas.text(self.config['max'],
                                  insert=(self.params['maxX'],
                                          self.params['maxY']),
                                  **txtMax_config)
        self.canvas.add(txtMax)
def generate_frame(i, j, k):
    filename = str(i)+str(j)+str(k)+".svg"
    dwg = Drawing(filename, size=(300, 300))
    dwg.add(dwg.text('i = %d, j = %d, k %d' % (i, j, k), insert=(0.5, 20),
                     fill='red'))
    dwg.add(dwg.line((0, 0), (10, 0), stroke=rgb(10, 10, 16, '%')))
    dwg.save()
    pixel_width = 300
    return convert(pixel_width, filename)
Esempio n. 3
0
def create_empty_chart(full_file_name):
    """Creates a chart of the proper dimensions with a white background."""
    num_days_in_week = 7
    num_weeks = math.ceil(NUM_DAYS_TO_SHOW / 7.0)
    if date.today().weekday() + 1 < NUM_DAYS_TO_SHOW % 7:
        # We need to draw NUM_DAYS_TO_SHOW % 7 extra days, but on the last week
        # we have only space for date.today().weekday() + 1 days.
        num_weeks += 1

    width = 2 * MARGIN + num_weeks * DAY_BOX_SIZE + \
        (num_weeks - 1) * DAY_BOX_SEPARATION
    height = 2 * MARGIN + num_days_in_week * DAY_BOX_SIZE + \
        (num_days_in_week - 1) * DAY_BOX_SEPARATION

    chart = Drawing(full_file_name, size=(width, height))
    chart.add(chart.rect(insert=(0, 0), size=(width, height), fill='white'))
    return chart
Esempio n. 4
0
def export_svg_svgwrite(fn, paths, w, h, line_width=0.1):

  from svgwrite import Drawing
  w_str = "{}pt".format(w)
  h_str = "{}pt".format(h)

  dwg = Drawing(filename = fn,
                size = (w_str, h_str),
                viewBox=("0 0 {} {}".format(w,h)))

  for path in paths:
    if(len(path) > 1):
      str_list = []
      str_list.append("M {},{}".format(path[0,0],path[0,1]))
      for e in path[1:]:
        str_list.append(" L {},{}".format(e[0],e[1]))
      s = ''.join(str_list)
      dwg.add(dwg.path(s).stroke(color="rgb(0%,0%,0%)",width=line_width).fill("none"))

  dwg.save()
Esempio n. 5
0
class Builder(object):
    
    def __init__(self, name, commits, configuration, deltax=50.0, width=700.0, y=40.0, sep=20.0, image_size=40.0):
        self.commits = commits
        self.authors = AuthorList()
        self.initial_last_dates(configuration)
        self.position_function()
        height = y + sep + (self.max_elements + 1) * (image_size + sep)
        self.dwg = Drawing(name, size=(width + 2 * deltax, height))
        
        self.deltax = deltax
        self.width = width
        self.y = y
        self.sep = sep
        self.image_size = image_size
        
    def initial_last_dates(self, configuration):
        self.initial = self.commits[0]["date"]
        self.last = self.commits[-1]["date"]
        self.max_elements = 0

        for date_tuple, elements in configuration.items():
            date = datetime(*date_tuple).replace(tzinfo=timezone.utc)
            self.last = max(self.last, date)
            self.initial = min(self.initial, date)
            self.max_elements = max(self.max_elements, len(elements))
            
    def position_function(self):
        size = self.last.timestamp() - self.initial.timestamp()
        def position(date, y, deltax=0, deltay=0):
            return (self.deltax + (date.timestamp() - self.initial.timestamp()) / size * self.width + deltax, y + deltay)
        self.position = position
        
    def add(self, element):
        for xml in element.draw(self):
            self.dwg.add(xml)
            
    def save(self):
        self.dwg.save()
Esempio n. 6
0
    def draw_path_clip(self):
        path_filename = "{}/path_clip_{}.svg".format(
            self.output_folder,
            basename(self.filename).replace(".svg", ""))
        dwg = Drawing(path_filename)
        image_bbox = calc_overall_bbox(self.tile_paths)

        dx = self.pent_x - min(image_bbox[0], image_bbox[1])
        dy = self.pent_y - min(image_bbox[2], image_bbox[3])
        dwg.add(
            dwg.path(
                **{
                    "d": self.new_pentagon().d(),
                    "fill": "none",
                    'stroke-width': 4,
                    'stroke': rgb(0, 0, 0)
                }))
        neg_transform = "translate({}, {})".format(-dx, -dy)
        transform = "translate({}, {})".format(dx, dy)
        clip_path = dwg.defs.add(
            dwg.clipPath(id="pent_path", transform=neg_transform))
        clip_path.add(dwg.path(d=self.new_pentagon().d()))
        group = dwg.add(
            dwg.g(clip_path="url(#pent_path)",
                  transform=transform,
                  id="clippedpath"))
        for i, path in enumerate(self.tile_paths):
            group.add(
                dwg.path(d=path.d(),
                         style=self.tile_attributes[i].get('style'),
                         id=self.tile_attributes[i]['id']))
        dwg.add(dwg.use("#clippedpath", transform="transform(100, 100)"))

        dwg.viewbox(self.pent_x, self.pent_y, self.pent_width,
                    self.pent_height)
        dwg.save()
        xml = xml.dom.minidom.parse(path_filename)
        open(path_filename, "w").write(xml.toprettyxml())
Esempio n. 7
0
def save_pie_chart(filename, root_list, step_size):
    
    #  create the drawing surface
    svg_drawing = Drawing(
        filename=filename,
        size=(SVG_SIZE, SVG_SIZE),
        debug=True)
    
    start_x = SVG_SIZE//2
    start_y = SVG_SIZE//2
    radius = SVG_SIZE//2

    all_angles = []
    for node in root_list:
        all_angles += node.pie_angle
    all_angles = sorted(all_angles)
    
    radians0 = all_angles[-1]
    for i in range(len(all_angles)):
        radians1 = all_angles[i]
        dx0 = radius*(math.sin(radians0))
        dy0 = radius*(math.cos(radians0))
        dx1 = radius*(math.sin(radians1))
        dy1 = radius*(math.cos(radians1))
    
        m0 = dy0 
        n0 = -dx0 
        m1 = -dy0 + dy1 
        n1 = dx0 - dx1 
    
        w = svg_drawing.path(d="M {0},{1} l {2},{3} a {4},{4} 0 0,0 {5},{6} z".format(start_x, start_y, m0, n0, radius, m1, n1),
                 fill = colors[i], 
                 stroke="none",
                )
        svg_drawing.add(w)
        radians0 = radians1
    
    svg_drawing.save()
Esempio n. 8
0
 def draw(self, dr: svgwrite.Drawing, size: XY, offset: XY):
     """Draw the heatmap based on tracks."""
     normal_lines = []
     special_lines = []
     bbox = self._determine_bbox()
     for tr in self.poster.tracks:
         for line in utils.project(bbox, size, offset, tr.polylines):
             if tr.special:
                 special_lines.append(line)
             else:
                 normal_lines.append(line)
     for lines, color in [(normal_lines, self.poster.colors['track']),
                          (special_lines, self.poster.colors['special'])]:
         for opacity, width in [(0.1, 5.0), (0.2, 2.0), (1.0, 0.3)]:
             for line in lines:
                 dr.add(
                     dr.polyline(points=line,
                                 stroke=color,
                                 stroke_opacity=opacity,
                                 fill='none',
                                 stroke_width=width,
                                 stroke_linejoin='round',
                                 stroke_linecap='round'))
Esempio n. 9
0
    def test_draw_template(self):
        # def draw_template(self, canvas, template, target_width, height, labels=None, colors=None):
        d = DiagramSettings()
        canvas = Drawing(size=(1000, 50))
        t = genomic.Template('1',
                             1,
                             100000,
                             bands=[
                                 BioInterval(None, 1, 8000, 'p1'),
                                 BioInterval(None, 10000, 15000, 'p2')
                             ])
        g = draw_template(d, canvas, t, 1000)
        canvas.add(g)
        canvas.attribs['height'] = g.height
        canvas = Drawing(size=(1000, 50))

        g = draw_template(d, canvas, TEMPLATE_METADATA['1'], 1000)
        self.assertEqual(
            d.breakpoint_top_margin + d.breakpoint_bottom_margin +
            d.template_track_height, g.height)
        canvas.add(g)
        canvas.attribs['height'] = g.height
        self.assertEqual(2, len(canvas.elements))
Esempio n. 10
0
def create_svg_document(elements,
                        size,
                        viewbox=None,
                        background_color="white",
                        background_opacity=1.0):
    """Create the full SVG document.

    :param viewbox: (minx, miny, width, height)
    """
    dwg = Drawing("ase.svg", profile="tiny", size=size)
    root = Group(id="root")
    dwg.add(root)
    # if Color(background_color).web != "white":
    # apparently the best way, see: https://stackoverflow.com/a/11293812/5033292
    root.add(
        shapes.Rect(size=size,
                    fill=background_color,
                    fill_opacity=background_opacity))
    for element in elements:
        root.add(element)
    if viewbox:
        dwg.viewbox(*viewbox)
    return dwg
Esempio n. 11
0
def save_radial_tree_plot(filename, root_list, step_size):

    #  define some params
    white = "rgb(255, 255, 255)"
    black = "rgb(0, 0, 0)"

    #  create the drawing surface
    svg_drawing = Drawing(filename=filename,
                          size=(SVG_SIZE, SVG_SIZE),
                          debug=True)

    #  create defs, in this case, just a single gradient
    rad_grad = svg_drawing.radialGradient(("50%", "50%"),
                                          "100%", ("50%", "50%"),
                                          id="rad_grad")
    rad_grad.add_stop_color("0%", black, 255)
    rad_grad.add_stop_color("100%", white, 255)
    svg_drawing.defs.add(rad_grad)

    tree_plot = svg_drawing.mask(
        id='treeplot',
        style=
        'stroke: black; stroke-width: 3; fill: none; stroke-linecap: round; stroke-opacity: 0.5;'
    )

    tree_plot.add(svg_drawing.rect((0, 0), (SVG_SIZE, SVG_SIZE)).fill(white))

    for root in root_list:
        draw_radial_tree_node(svg_drawing, tree_plot, root, rad_grad,
                              step_size)

    base_rect = svg_drawing.rect((0, 0), (SVG_SIZE, SVG_SIZE),
                                 mask="url(#treeplot)").fill(black)
    svg_drawing.add(base_rect)
    svg_drawing.add(tree_plot)

    svg_drawing.save()
Esempio n. 12
0
def draw():
	drawing = Drawing(drawing_file_name, drawing_size)
	
	
	first_circle_view = \
		Circle(
			center       = first_circle_center,
			r            = first_circle_radius,
			fill_opacity = 0,
			stroke       = rgb(0, 0, 0),
			stroke_width = 1
		)
		
	first_circle_center_view = \
		Circle(
			center       = first_circle_center,
			r            = 3,
			fill         = rgb(0, 0, 0),
			stroke_width = 0
		)
		
	drawing.add(first_circle_view)
	drawing.add(first_circle_center_view)
	
	
	second_circle_view = \
		Circle(
			center       = second_circle_center,
			r            = second_circle_radius,
			fill_opacity = 0,
			stroke       = rgb(0, 0, 0),
			stroke_width = 1
		)
		
	second_circle_center_view = \
		Circle(
			center       = second_circle_center,
			r            = 3,
			fill         = rgb(0, 0, 0),
			stroke_width = 0
		)
		
	drawing.add(second_circle_view)
	drawing.add(second_circle_center_view)
	
	
	drawing.save()
Esempio n. 13
0
    def add(self, svg: Drawing) -> None:
        point: np.array = to_grid(self.point)
        radius: float = 7.5
        a1 = self.angle + math.pi / 9.0
        a2 = self.angle - math.pi / 9.0
        n1 = np.array((math.cos(a1), math.sin(a1)))
        n2 = np.array((math.cos(a2), math.sin(a2)))
        p1 = point + n1 * radius
        p2 = point + n1 * 20
        p3 = point + n2 * 20
        p4 = point + n2 * radius
        svg.add(
            svg.path(d=["M", p1, "C", p2, p3, p4],
                     fill="none",
                     stroke="black",
                     stroke_width=0.5))

        n = (p4 - p3) / np.linalg.norm(p4 - p3)
        svg.add(
            svg.path(d=create_v(p4, n,
                                np.dot(rotation_matrix(-math.pi / 2.0), n)),
                     stroke_width=0.5,
                     fill="none",
                     stroke="black"))
Esempio n. 14
0
    def _draw_year(self, d: svgwrite.Drawing, size: XY, offset: XY, year: int):
        min_size = min(size.x, size.y)
        outer_radius = 0.5 * min_size - 6
        radius_range = ValueRange.from_pair(outer_radius / 4, outer_radius)
        center = offset + 0.5 * size

        if self._rings:
            self._draw_rings(d, center, radius_range)

        year_style = 'dominant-baseline: central; font-size:{}px; font-family:Arial;'.format(min_size * 4.0 / 80.0)
        month_style = 'font-size:{}px; font-family:Arial;'.format(min_size * 3.0 / 80.0)

        d.add(d.text('{}'.format(year), insert=center.tuple(), fill=self.poster.colors['text'], text_anchor="middle",
                     alignment_baseline="middle", style=year_style))
        df = 360.0 / (366 if calendar.isleap(year) else 365)
        day = 0
        date = datetime.date(year, 1, 1)
        while date.year == year:
            text_date = date.strftime("%Y-%m-%d")
            a1 = math.radians(day * df)
            a2 = math.radians((day + 1) * df)
            if date.day == 1:
                (_, last_day) = calendar.monthrange(date.year, date.month)
                a3 = math.radians((day + last_day - 1) * df)
                sin_a1, cos_a1 = math.sin(a1), math.cos(a1)
                sin_a3, cos_a3 = math.sin(a3), math.cos(a3)
                r1 = outer_radius + 1
                r2 = outer_radius + 6
                r3 = outer_radius + 2
                d.add(d.line(
                    start=(center + r1 * XY(sin_a1, -cos_a1)).tuple(),
                    end=(center + r2 * XY(sin_a1, -cos_a1)).tuple(),
                    stroke=self.poster.colors['text'],
                    stroke_width=0.3))
                path = d.path(d=('M', center.x + r3 * sin_a1, center.y - r3 * cos_a1), fill='none', stroke='none')
                path.push('a{},{} 0 0,1 {},{}'.format(r3, r3, r3 * (sin_a3 - sin_a1), r3 * (cos_a1 - cos_a3)))
                d.add(path)
                tpath = svgwrite.text.TextPath(path, date.strftime("%B"), startOffset=(0.5 * r3 * (a3 - a1)))
                text = d.text("", fill=self.poster.colors['text'], text_anchor="middle", style=month_style)
                text.add(tpath)
                d.add(text)
            if text_date in self.poster.tracks_by_date:
                self._draw_circle_segment(d, self.poster.tracks_by_date[text_date], a1, a2, radius_range, center)

            day += 1
            date += datetime.timedelta(1)
Esempio n. 15
0
def _draw_classical_double_line(drawing: Drawing,
                                x1_coord, y1_coord,
                                x2_coord, y2_coord) -> None:
    """Draw a double line between (x1_coord,y1_coord) and (x2_coord,y2_coord).

    Raises:
        NotImplementedError: when x1_coord!=x2_coord and y1_coord!=y2_coord (i.e. when the
                         line is neither horizontal nor vertical).
    """
    x_increment, y_increment = 0, 0
    if x1_coord == x2_coord:
        x_increment = _constants.DOUBLE_LINES_SEPARATION
    elif y1_coord == y2_coord:
        y_increment = _constants.DOUBLE_LINES_SEPARATION
    else:
        raise NotImplementedError("The drawed line should be either horizontal or vertical.")
    drawing.add(drawing.line(start=(x1_coord - x_increment, y1_coord - y_increment),
                             end=(x2_coord - x_increment, y2_coord - y_increment),
                             stroke=_constants.GATE_BORDER_COLOR,
                             stroke_width=_constants.STROKE_THICKNESS))
    drawing.add(drawing.line(start=(x1_coord + x_increment, y1_coord + y_increment),
                             end=(x2_coord + x_increment, y2_coord + y_increment),
                             stroke=_constants.GATE_BORDER_COLOR,
                             stroke_width=_constants.STROKE_THICKNESS))
Esempio n. 16
0
    def draw(self,
             svg: svgwrite.Drawing,
             point: np.array,
             color: Color,
             opacity=1.0,
             tags: Dict[str, Any] = None,
             outline: bool = False):
        """
        Draw icon shape into SVG file.

        :param svg: output SVG file
        :param point: icon position
        :param color: fill color
        :param opacity: icon opacity
        :param tags: tags to be displayed as hint
        :param outline: draw outline for the icon
        """
        point = np.array(list(map(int, point)))

        path: svgwrite.path.Path = self.get_path(svg, point)
        path.update({"fill": color.hex})
        if outline:
            opacity: float = 0.5

            path.update({
                "fill": color.hex,
                "stroke": color.hex,
                "stroke-width": 2.2,
                "stroke-linejoin": "round"
            })
        if opacity != 1.0:
            path.update({"opacity": opacity})
        if tags:
            title: str = "\n".join(map(lambda x: x + ": " + tags[x], tags))
            path.set_desc(title=title)
        svg.add(path)
Esempio n. 17
0
def save_radial_tree_plot(filename, root_list):
    svg_drawing = Drawing(filename=filename,
                          size=(SVG_SIZE, SVG_SIZE),
                          debug=True)

    tree_plot = svg_drawing.add(
        svg_drawing.
        g(id='treeplot',
          style=
          'stroke: black; stroke-width: 1; fill: none; stroke-linecap: round;')
    )

    for root in root_list:
        draw_radial_tree_node(svg_drawing, tree_plot, root)

    svg_drawing.save()
Esempio n. 18
0
    def generate_tiling(self):
        dwg = Drawing("{}/tiling2.svg".format(self.output_folder),
                      profile="tiny")

        current_color = 0
        row_spacing = self.pent_height * 2 + self.bottom_length

        for y in range(self.num_down):
            transform = "translate({}, {})".format(0, self.rep_spacing * y)
            dgroup = dwg.add(dwg.g(transform=transform))
            for x in range(self.num_across):
                # if x is odd, point 1 of pent 1 needs to be attached to point 3 of pent 2
                if x % 2 == 1:
                    dx = int(
                        x / 2
                    ) * self.rep_spacing + self.pent_width * 2 + self.column_offset.real
                    transform = "translate({}, {})".format(
                        dx, self.column_offset.imag)
                else:
                    transform = "translate({}, {})".format(
                        int(x / 2) * self.rep_spacing, 0)
                group = dgroup.add(dwg.g(transform=transform))
                for pent in self.cairo_group:
                    group.add(
                        dwg.path(
                            **{
                                'd':
                                pent.d(),
                                'fill':
                                self._colors[current_color %
                                             len(self._colors)],
                                'stroke-width':
                                4,
                                'stroke':
                                rgb(0, 0, 0)
                            }))
                    current_color += 1

        dwg.viewbox(*self.pattern_viewbox)
        dwg.save(pretty=True)
Esempio n. 19
0
def create_svg_image(styles, board_size, hexagons):
    """
    Creates SVG drawing.

    The drawing contains all given css styles, a board (background rectangle)
    of given size and all given hexagons. The board can be styled using '.board'.
    All hexagonal fields can be styled using '.hex-field'. Fields can be also
    styled using 'hex-field-X', where X is the type of the field.
    :param styles iterable of css styles (strings)
    :param board_size tuple representing board size (width, height)
    :param hexagons iterable of hexagons (tuples in a form of (vertices, type) )
    :returns SVG Drawing object
    """
    svg_image = Drawing()
    for style in styles:
        svg_image.add(svg_image.style(style))
    svg_image.add(svg_image.rect(size=board_size, class_="board"))
    for hexagon in hexagons:
        svg_image.add(svg_image.polygon(hexagon.vertices, class_="hex-field hex-field-%d" % hexagon.type))
    return svg_image
Esempio n. 20
0
    def draw(self, dr: svgwrite.Drawing, size: XY, offset: XY):
        if self.poster.tracks is None:
            raise PosterError("No tracks to draw")
        year_size = 200 * 4.0 / 80.0
        year_style = f"font-size:{year_size}px; font-family:Arial;"
        year_length_style = f"font-size:{110 * 3.0 / 80.0}px; font-family:Arial;"
        month_names_style = f"font-size:2.5px; font-family:Arial"
        total_length_year_dict = self.poster.total_length_year_dict
        for year in range(self.poster.years.from_year,
                          self.poster.years.to_year + 1):
            start_date_weekday, _ = calendar.monthrange(year, 1)
            github_rect_first_day = datetime.date(year, 1, 1)
            # Github profile the first day start from the last Monday of the last year or the first Monday of this year
            # It depands on if the first day of this year is Monday or not.
            github_rect_day = github_rect_first_day + datetime.timedelta(
                -start_date_weekday)
            year_length = total_length_year_dict.get(year, 0)
            year_length = format_float(self.poster.m2u(year_length))
            try:
                month_names = [
                    locale.nl_langinfo(day)[:3]  # Get only first three letters
                    for day in [
                        locale.MON_1,
                        locale.MON_2,
                        locale.MON_3,
                        locale.MON_4,
                        locale.MON_5,
                        locale.MON_6,
                        locale.MON_7,
                        locale.MON_8,
                        locale.MON_9,
                        locale.MON_10,
                        locale.MON_11,
                        locale.MON_12,
                    ]
                ]
                # support windows or others doesn't support locale Name, by Hard code
            except Exception as e:
                print(str(e))
                month_names = [
                    "Jan",
                    "Feb",
                    "Mar",
                    "Apr",
                    "May",
                    "Jun",
                    "Jul",
                    "Aug",
                    "Sep",
                    "Oct",
                    "Nov",
                    "Dec",
                ]
            km_or_mi = "mi"
            if self.poster.units == "metric":
                km_or_mi = "km"
            dr.add(
                dr.text(
                    f"{year}",
                    insert=offset.tuple(),
                    fill=self.poster.colors["text"],
                    alignment_baseline="hanging",
                    style=year_style,
                ))

            dr.add(
                dr.text(
                    f"{year_length} {km_or_mi}",
                    insert=(offset.tuple()[0] + 165, offset.tuple()[1] + 2),
                    fill=self.poster.colors["text"],
                    alignment_baseline="hanging",
                    style=year_length_style,
                ))
            # add month name up to the poster one by one because of svg text auto trim the spaces.
            for num, name in enumerate(month_names):
                dr.add(
                    dr.text(
                        f"{name}",
                        insert=(offset.tuple()[0] + 15.5 * num,
                                offset.tuple()[1] + 14),
                        fill=self.poster.colors["text"],
                        style=month_names_style,
                    ))

            rect_x = 10.0
            dom = (2.6, 2.6)
            # add every day of this year for 53 weeks and per week has 7 days
            for i in range(54):
                rect_y = offset.y + year_size + 2
                for j in range(7):
                    if int(github_rect_day.year) > year:
                        break
                    rect_y += 3.5
                    color = "#444444"
                    date_title = str(github_rect_day)
                    if date_title in self.poster.tracks_by_date:
                        tracks = self.poster.tracks_by_date[date_title]
                        length = sum([t.length for t in tracks])
                        distance1 = self.poster.special_distance[
                            "special_distance"]
                        distance2 = self.poster.special_distance[
                            "special_distance2"]
                        has_special = distance1 < length / 1000 < distance2
                        color = self.color(self.poster.length_range_by_date,
                                           length, has_special)
                        if length / 1000 >= distance2:
                            color = self.poster.colors.get(
                                "special2") or self.poster.colors.get(
                                    "special")
                        str_length = format_float(self.poster.m2u(length))
                        date_title = f"{date_title} {str_length} {km_or_mi}"

                    rect = dr.rect((rect_x, rect_y), dom, fill=color)
                    rect.set_desc(title=date_title)
                    dr.add(rect)
                    github_rect_day += datetime.timedelta(1)
                rect_x += 3.5
            offset.y += 3.5 * 9 + year_size + 1.5
Esempio n. 21
0
    def _draw_footer(self, d: svgwrite.Drawing) -> None:
        g = d.g(id="footer")
        d.add(g)

        text_color = self.colors["text"]
        header_style = "font-size:4px; font-family:Arial"
        value_style = "font-size:9px; font-family:Arial"
        small_value_style = "font-size:3px; font-family:Arial"

        (
            total_length,
            average_length,
            length_range,
            weeks,
        ) = self._compute_track_statistics()

        g.add(
            d.text(
                self.translate("ATHLETE"),
                insert=(10, self.height - 20),
                fill=text_color,
                style=header_style,
            )
        )
        g.add(
            d.text(
                self._athlete,
                insert=(10, self.height - 10),
                fill=text_color,
                style=value_style,
            )
        )
        g.add(
            d.text(
                self.translate("STATISTICS"),
                insert=(120, self.height - 20),
                fill=text_color,
                style=header_style,
            )
        )
        g.add(
            d.text(
                self.translate("Number") + f": {len(self.tracks)}",
                insert=(120, self.height - 15),
                fill=text_color,
                style=small_value_style,
            )
        )
        g.add(
            d.text(
                self.translate("Weekly") + ": " + format_float(len(self.tracks) / weeks),
                insert=(120, self.height - 10),
                fill=text_color,
                style=small_value_style,
            )
        )
        g.add(
            d.text(
                self.translate("Total") + ": " + self.format_distance(total_length),
                insert=(141, self.height - 15),
                fill=text_color,
                style=small_value_style,
            )
        )
        g.add(
            d.text(
                self.translate("Avg") + ": " + self.format_distance(average_length),
                insert=(141, self.height - 10),
                fill=text_color,
                style=small_value_style,
            )
        )
        if length_range.is_valid():
            min_length = length_range.lower()
            max_length = length_range.upper()
            assert min_length is not None
            assert max_length is not None
        else:
            min_length = 0.0
            max_length = 0.0
        g.add(
            d.text(
                self.translate("Min") + ": " + self.format_distance(min_length),
                insert=(167, self.height - 15),
                fill=text_color,
                style=small_value_style,
            )
        )
        g.add(
            d.text(
                self.translate("Max") + ": " + self.format_distance(max_length),
                insert=(167, self.height - 10),
                fill=text_color,
                style=small_value_style,
            )
        )
Esempio n. 22
0
def disvg(paths=None,
          colors=None,
          filename=None,
          stroke_widths=None,
          nodes=None,
          node_colors=None,
          node_radii=None,
          openinbrowser=True,
          timestamp=None,
          margin_size=0.1,
          mindim=600,
          dimensions=None,
          viewbox=None,
          text=None,
          text_path=None,
          font_size=None,
          attributes=None,
          svg_attributes=None,
          svgwrite_debug=False,
          paths2Drawing=False,
          baseunit='px'):
    """Creates (and optionally displays) an SVG file.

    REQUIRED INPUTS:
        :param paths - a list of paths

    OPTIONAL INPUT:
        :param colors - specifies the path stroke color.  By default all paths
        will be black (#000000).  This paramater can be input in a few ways
        1) a list of strings that will be input into the path elements stroke
            attribute (so anything that is understood by the svg viewer).
        2) a string of single character colors -- e.g. setting colors='rrr' is
            equivalent to setting colors=['red', 'red', 'red'] (see the
            'color_dict' dictionary above for a list of possibilities).
        3) a list of rgb 3-tuples -- e.g. colors = [(255, 0, 0), ...].

        :param filename - the desired location/filename of the SVG file
        created (by default the SVG will be named 'disvg_output.svg' or
        'disvg_output_<timestamp>.svg' and stored in the temporary
        directory returned by `tempfile.gettempdir()`.  See `timestamp`
        for information on the timestamp.

        :param stroke_widths - a list of stroke_widths to use for paths
        (default is 0.5% of the SVG's width or length)

        :param nodes - a list of points to draw as filled-in circles

        :param node_colors - a list of colors to use for the nodes (by default
        nodes will be red)

        :param node_radii - a list of radii to use for the nodes (by default
        nodes will be radius will be 1 percent of the svg's width/length)

        :param text - string or list of strings to be displayed

        :param text_path - if text is a list, then this should be a list of
        path (or path segments of the same length.  Note: the path must be
        long enough to display the text or the text will be cropped by the svg
        viewer.

        :param font_size - a single float of list of floats.

        :param openinbrowser -  Set to True to automatically open the created
        SVG in the user's default web browser.

        :param timestamp - if true, then the a timestamp will be
        appended to the output SVG's filename.  This is meant as a
        workaround for issues related to rapidly opening multiple
        SVGs in your browser using `disvg`. This defaults to true if
        `filename is None` and false otherwise.

        :param margin_size - The min margin (empty area framing the collection
        of paths) size used for creating the canvas and background of the SVG.

        :param mindim - The minimum dimension (height or width) of the output
        SVG (default is 600).

        :param dimensions - The (x,y) display dimensions of the output SVG.
        I.e. this specifies the `width` and `height` SVG attributes. Note that 
        these also can be used to specify units other than pixels. Using this 
        will override the `mindim` parameter.

        :param viewbox - This specifies the coordinated system used in the svg.
        The SVG `viewBox` attribute works together with the the `height` and 
        `width` attrinutes.  Using these three attributes allows for shifting 
        and scaling of the SVG canvas without changing the any values other 
        than those in `viewBox`, `height`, and `width`.  `viewbox` should be 
        input as a 4-tuple, (min_x, min_y, width, height), or a string 
        "min_x min_y width height".  Using this will override the `mindim` 
        parameter.

        :param attributes - a list of dictionaries of attributes for the input
        paths.  Note: This will override any other conflicting settings.

        :param svg_attributes - a dictionary of attributes for output svg.
        
        :param svgwrite_debug - This parameter turns on/off `svgwrite`'s 
        debugging mode.  By default svgwrite_debug=False.  This increases 
        speed and also prevents `svgwrite` from raising of an error when not 
        all `svg_attributes` key-value pairs are understood.
        
        :param paths2Drawing - If true, an `svgwrite.Drawing` object is 
        returned and no file is written.  This `Drawing` can later be saved 
        using the `svgwrite.Drawing.save()` method.

    NOTES:
        * The `svg_attributes` parameter will override any other conflicting 
        settings.

        * Any `extra` parameters that `svgwrite.Drawing()` accepts can be 
        controlled by passing them in through `svg_attributes`.

        * The unit of length here is assumed to be pixels in all variables.

        * If this function is used multiple times in quick succession to
        display multiple SVGs (all using the default filename), the
        svgviewer/browser will likely fail to load some of the SVGs in time.
        To fix this, use the timestamp attribute, or give the files unique
        names, or use a pause command (e.g. time.sleep(1)) between uses.

    SEE ALSO:
        * document.py
    """

    _default_relative_node_radius = 5e-3
    _default_relative_stroke_width = 1e-3
    _default_path_color = '#000000'  # black
    _default_node_color = '#ff0000'  # red
    _default_font_size = 12

    if filename is None:
        timestamp = True if timestamp is None else timestamp
        filename = os_path.join(gettempdir(), 'disvg_output.svg')

    dirname = os_path.abspath(os_path.dirname(filename))
    if not os_path.exists(dirname):
        makedirs(dirname)

    # append time stamp to filename
    if timestamp:
        fbname, fext = os_path.splitext(filename)
        tstamp = str(time()).replace('.', '')
        stfilename = os_path.split(fbname)[1] + '_' + tstamp + fext
        filename = os_path.join(dirname, stfilename)

    # check paths and colors are set
    if isinstance(paths, Path) or is_path_segment(paths):
        paths = [paths]
    if paths:
        if not colors:
            colors = [_default_path_color] * len(paths)
        else:
            assert len(colors) == len(paths)
            if isinstance(colors, str):
                colors = str2colorlist(colors,
                                       default_color=_default_path_color)
            elif isinstance(colors, list):
                for idx, c in enumerate(colors):
                    if is3tuple(c):
                        colors[idx] = "rgb" + str(c)

    # check nodes and nodes_colors are set (node_radii are set later)
    if nodes:
        if not node_colors:
            node_colors = [_default_node_color] * len(nodes)
        else:
            assert len(node_colors) == len(nodes)
            if isinstance(node_colors, str):
                node_colors = str2colorlist(node_colors,
                                            default_color=_default_node_color)
            elif isinstance(node_colors, list):
                for idx, c in enumerate(node_colors):
                    if is3tuple(c):
                        node_colors[idx] = "rgb" + str(c)

    # set up the viewBox and display dimensions of the output SVG
    # along the way, set stroke_widths and node_radii if not provided
    assert paths or nodes
    stuff2bound = []
    if viewbox:
        if not isinstance(viewbox, str):
            viewbox = '%s %s %s %s' % viewbox
        if dimensions is None:
            dimensions = viewbox.split(' ')[2:4]
    elif dimensions:
        dimensions = tuple(map(str, dimensions))

        def strip_units(s):
            return re.search(r'\d*\.?\d*', s.strip()).group()

        viewbox = '0 0 %s %s' % tuple(map(strip_units, dimensions))
    else:
        if paths:
            stuff2bound += paths
        if nodes:
            stuff2bound += nodes
        if text_path:
            stuff2bound += text_path
        xmin, xmax, ymin, ymax = big_bounding_box(stuff2bound)
        dx = xmax - xmin
        dy = ymax - ymin

        if dx == 0:
            dx = 1
        if dy == 0:
            dy = 1

        # determine stroke_widths to use (if not provided) and max_stroke_width
        if paths:
            if not stroke_widths:
                sw = max(dx, dy) * _default_relative_stroke_width
                stroke_widths = [sw] * len(paths)
                max_stroke_width = sw
            else:
                assert len(paths) == len(stroke_widths)
                max_stroke_width = max(stroke_widths)
        else:
            max_stroke_width = 0

        # determine node_radii to use (if not provided) and max_node_diameter
        if nodes:
            if not node_radii:
                r = max(dx, dy) * _default_relative_node_radius
                node_radii = [r] * len(nodes)
                max_node_diameter = 2 * r
            else:
                assert len(nodes) == len(node_radii)
                max_node_diameter = 2 * max(node_radii)
        else:
            max_node_diameter = 0

        extra_space_for_style = max(max_stroke_width, max_node_diameter)
        xmin -= margin_size * dx + extra_space_for_style / 2
        ymin -= margin_size * dy + extra_space_for_style / 2
        dx += 2 * margin_size * dx + extra_space_for_style
        dy += 2 * margin_size * dy + extra_space_for_style
        viewbox = "%s %s %s %s" % (xmin, ymin, dx, dy)

        if mindim is None:
            szx = "{}{}".format(dx, baseunit)
            szy = "{}{}".format(dy, baseunit)
        else:
            if dx > dy:
                szx = str(mindim) + baseunit
                szy = str(int(ceil(mindim * dy / dx))) + baseunit
            else:
                szx = str(int(ceil(mindim * dx / dy))) + baseunit
                szy = str(mindim) + baseunit
        dimensions = szx, szy

    # Create an SVG file
    if svg_attributes is not None:
        dimensions = (svg_attributes.get("width", dimensions[0]),
                      svg_attributes.get("height", dimensions[1]))
        debug = svg_attributes.get("debug", svgwrite_debug)
        dwg = Drawing(filename=filename,
                      size=dimensions,
                      debug=debug,
                      **svg_attributes)
    else:
        dwg = Drawing(filename=filename,
                      size=dimensions,
                      debug=svgwrite_debug,
                      viewBox=viewbox)

    # add paths
    if paths:
        for i, p in enumerate(paths):
            if isinstance(p, Path):
                ps = p.d()
            elif is_path_segment(p):
                ps = Path(p).d()
            else:  # assume this path, p, was input as a Path d-string
                ps = p

            if attributes:
                good_attribs = {'d': ps}
                for key in attributes[i]:
                    val = attributes[i][key]
                    if key != 'd':
                        try:
                            dwg.path(ps, **{key: val})
                            good_attribs.update({key: val})
                        except Exception as e:
                            warn(str(e))

                dwg.add(dwg.path(**good_attribs))
            else:
                dwg.add(
                    dwg.path(ps,
                             stroke=colors[i],
                             stroke_width=str(stroke_widths[i]),
                             fill='none'))

    # add nodes (filled in circles)
    if nodes:
        for i_pt, pt in enumerate([(z.real, z.imag) for z in nodes]):
            dwg.add(dwg.circle(pt, node_radii[i_pt], fill=node_colors[i_pt]))

    # add texts
    if text:
        assert isinstance(text, str) or (isinstance(text, list) and isinstance(
            text_path, list) and len(text_path) == len(text))
        if isinstance(text, str):
            text = [text]
            if not font_size:
                font_size = [_default_font_size]
            if not text_path:
                pos = complex(xmin + margin_size * dx, ymin + margin_size * dy)
                text_path = [Line(pos, pos + 1).d()]
        else:
            if font_size:
                if isinstance(font_size, list):
                    assert len(font_size) == len(text)
                else:
                    font_size = [font_size] * len(text)
            else:
                font_size = [_default_font_size] * len(text)
        for idx, s in enumerate(text):
            p = text_path[idx]
            if isinstance(p, Path):
                ps = p.d()
            elif is_path_segment(p):
                ps = Path(p).d()
            else:  # assume this path, p, was input as a Path d-string
                ps = p

            # paragraph = dwg.add(dwg.g(font_size=font_size[idx]))
            # paragraph.add(dwg.textPath(ps, s))
            pathid = 'tp' + str(idx)
            dwg.defs.add(dwg.path(d=ps, id=pathid))
            txter = dwg.add(dwg.text('', font_size=font_size[idx]))
            txter.add(txt.TextPath('#' + pathid, s))

    if paths2Drawing:
        return dwg

    dwg.save()

    # re-open the svg, make the xml pretty, and save it again
    xmlstring = md_xml_parse(filename).toprettyxml()
    with open(filename, 'w') as f:
        f.write(xmlstring)

    # try to open in web browser
    if openinbrowser:
        try:
            open_in_browser(filename)
        except:
            print("Failed to open output SVG in browser.  SVG saved to:")
            print(filename)
Esempio n. 23
0
def export_node(node, store, size=None):
    """Construct a SVG description for a workflow node.

    Args:
        node (NodeDef)
        store (dict of uid, def): elements definitions
        size (int, int): size of drawing in pixels

    Returns:
        (str) - SVG description of workflow node
    """
    pfs = port_font_size

    # node size
    pr = port_radius
    pspace = pr * 9
    nw = compute_node_width(node, node['name'], pspace)
    nh = label_font_size + 2 * pr + 2 * pfs + 2 + (2 * node_padding)

    # draw
    if size is None:
        size = (600, 600)

    paper = Drawing("workflow_node.svg", size, id="repr")

    lg = paper.linearGradient((0.5, 0), (0.5, 1.), id="in_port")
    lg.add_stop_color(0, color='#3333ff')
    lg.add_stop_color(1, color='#2222ff')
    paper.defs.add(lg)

    lg = paper.linearGradient((0.5, 0), (0.5, 1.), id="out_port")
    lg.add_stop_color(0, color='#ffff33')
    lg.add_stop_color(1, color='#9a9a00')
    paper.defs.add(lg)

    # body
    g = paper.add(paper.g())

    # background
    lg = paper.linearGradient((0.5, 0), (0.5, 1.))
    lg.add_stop_color(0, color='#8c8cff')
    lg.add_stop_color(1, color='#c8c8c8')
    paper.defs.add(lg)

    bg = paper.rect((-nw / 2, -nh / 2), (nw, nh),
                    rx=node_padding, ry=node_padding,
                    stroke_width=1)
    bg.stroke('#808080')
    bg.fill(lg)
    g.add(bg)

    # label
    style = ('font-size: %dpx; font-family: %s; '
             'text-anchor: middle' % (label_font_size, label_font))
    frag = paper.tspan(node['name'], dy=[label_font_size // 3])
    label = paper.text("", style=style, fill='#000000')
    label.add(frag)
    g.add(label)

    # ports
    port_style = ('font-size: %dpx; ' % pfs +
                  'font-family: %s; ' % label_font)
    onstyle = port_style + 'text-anchor: end'
    instyle = port_style + 'text-anchor: start'
    istyle = port_style + 'text-anchor: middle'
    nb = len(node['inputs'])
    py = -nh / 2
    for i, pdef in enumerate(node['inputs']):
        px = i * pspace - pspace * (nb - 1) / 2
        pg = g.add(paper.g())
        pg.translate(px, py)
        idef = store.get(pdef['interface'], None)
        if idef is not None and 'url' in idef:
            link = pg.add(paper.a(href=idef['url'], target='_top'))
        else:
            link = pg

        port = paper.circle((0, 0), pr, stroke='#000000', stroke_width=1)
        port.fill("url(#in_port)")
        link.add(port)
        # port name
        frag = paper.tspan(pdef['name'], dy=[-2 * pr])
        label = paper.text("", style=instyle, fill='#000000')
        label.rotate(-45)
        label.add(frag)
        pg.add(label)
        # port interface
        if idef is None:
            itxt = pdef['interface']
        else:
            itxt = idef['name']
        if len(itxt) > 10:
            itxt = itxt[:7] + "..."
        frag = paper.tspan(itxt, dy=[pr + pfs])
        label = paper.text("", style=istyle, fill='#000000')
        label.add(frag)
        link.add(label)

    nb = len(node['outputs'])
    py = nh / 2
    for i, pdef in enumerate(node['outputs']):
        px = i * pspace - pspace * (nb - 1) / 2
        pg = g.add(paper.g())
        pg.translate(px, py)
        idef = store.get(pdef['interface'], None)
        if idef is not None and 'url' in idef:
            link = pg.add(paper.a(href=idef['url'], target='_top'))
        else:
            link = pg

        port = paper.circle((0, 0), pr, stroke='#000000', stroke_width=1)
        port.fill("url(#out_port)")
        link.add(port)
        # port name
        frag = paper.tspan(pdef['name'], dy=[2 * pr + pfs // 2])
        label = paper.text("", style=onstyle, fill='#000000')
        label.rotate(-45)
        label.add(frag)
        pg.add(label)
        # port interface
        if idef is None:
            itxt = pdef['interface']
        else:
            itxt = idef['name']
        if len(itxt) > 10:
            itxt = itxt[:7] + "..."
        frag = paper.tspan(itxt, dy=[- pr - 2])
        label = paper.text("", style=istyle, fill='#000000')
        label.add(frag)
        link.add(label)

    # reformat whole drawing to fit screen
    xmin = - nw / 2 - draw_padding / 10.
    xmax = + nw / 2 + draw_padding / 10.
    if len(node['inputs']) == 0:
        inames_extend = 0
    else:
        inames = [(len(pdef['name']), pdef['name']) for pdef in node['inputs']]
        inames_extend = string_size(sorted(inames)[-1][1], pfs) * 0.7 + pfs
    ymin = - nh / 2 - pr - inames_extend - draw_padding / 10.
    if len(node['outputs']) == 0:
        onames_extend = 0
    else:
        onames = [(len(pdef['name']), pdef['name']) for pdef in node['outputs']]
        onames_extend = string_size(sorted(onames)[-1][1], pfs) * 0.7 + pfs
    ymax = + nh / 2 + pr + onames_extend + draw_padding / 10.

    w = float(size[0])
    h = float(size[1])
    ratio = max((xmax - xmin) / w, (ymax - ymin) / h)
    xsize = ratio * w
    ysize = ratio * h

    bb = (xmin * xsize / (xmax - xmin),
          ymin * ysize / (ymax - ymin),
          xsize,
          ysize)

    paper.viewbox(*bb)
    return paper.tostring(), bb
Esempio n. 24
0
class TestDraw(unittest.TestCase):
    def setUp(self):
        self.canvas = Drawing(height=100, width=1000)

    def test_generate_interval_mapping_outside_range_error(self):
        temp = [
            Interval(48556470, 48556646),
            Interval(48573290, 48573665),
            Interval(48575056, 48575078),
        ]
        mapping = generate_interval_mapping(
            input_intervals=temp,
            target_width=431.39453125,
            ratio=20,
            min_width=14,
            buffer_length=None,
            end=None,
            start=None,
            min_inter_width=10,
        )
        st = min([x.start for x in temp])
        end = min([x.end for x in temp])
        Interval.convert_pos(mapping, st)
        Interval.convert_pos(mapping, end)

    def test_generate_gene_mapping_err(self):
        #  _generate_interval_mapping [genomic.IntergenicRegion(11:77361962_77361962+)] 1181.39453125 5 30 None 77356962 77366962)
        ir = genomic.IntergenicRegion('11', 5000, 5000, STRAND.POS)
        tgt_width = 1000
        d = DiagramSettings()
        d.gene_min_buffer = 10
        # (self, canvas, gene, width, height, fill, label='', reference_genome=None)
        draw_genes(d, self.canvas, [ir], tgt_width, [])

        # _generate_interval_mapping ['Interval(29684391, 29684391)', 'Interval(29663998, 29696515)'] 1181.39453125 5 60 None 29662998 29697515
        # def generate_interval_mapping(cls, input_intervals, target_width, ratio, min_width, buffer_length=None, start=None, end=None, min_inter_width=None)
        itvls = [Interval(29684391, 29684391), Interval(29663998, 29696515)]
        generate_interval_mapping(itvls, 1181.39, 5, 60, None, 29662998,
                                  29697515)

    def test_split_intervals_into_tracks(self):
        # ----======---------
        # ------======--------
        # -----===============
        t = split_intervals_into_tracks([(1, 3), (3, 7), (2, 2), (4, 5),
                                         (3, 10)])
        self.assertEqual(3, len(t))
        self.assertEqual([(1, 3), (4, 5)], t[0])
        self.assertEqual([(2, 2), (3, 7)], t[1])
        self.assertEqual([(3, 10)], t[2])

    def test_draw_genes(self):

        x = genomic.Gene('1', 1000, 2000, strand=STRAND.POS)
        y = genomic.Gene('1', 5000, 7000, strand=STRAND.NEG)
        z = genomic.Gene('1', 1500, 2500, strand=STRAND.POS)

        d = DiagramSettings()
        breakpoints = [Breakpoint('1', 1100, 1200, orient=ORIENT.RIGHT)]
        g = draw_genes(
            d,
            self.canvas,
            [x, y, z],
            500,
            breakpoints,
            {
                x: d.gene1_color,
                y: d.gene2_color_selected,
                z: d.gene2_color
            },
        )

        # test the class structure
        self.assertEqual(6, len(g.elements))
        self.assertEqual('scaffold', g.elements[0].attribs.get('class', ''))
        for i in range(1, 4):
            self.assertEqual('gene', g.elements[i].attribs.get('class', ''))
        self.assertEqual('mask', g.elements[4].attribs.get('class', ''))
        self.assertEqual('breakpoint', g.elements[5].attribs.get('class', ''))
        self.assertEqual(
            d.track_height * 2 + d.padding + d.breakpoint_bottom_margin +
            d.breakpoint_top_margin,
            g.height,
        )
        self.canvas.add(g)
        self.assertEqual(len(g.labels), 4)
        self.assertEqual(x, g.labels['G1'])
        self.assertEqual(z, g.labels['G2'])
        self.assertEqual(y, g.labels['G3'])
        self.assertEqual(breakpoints[0], g.labels['B1'])

    def test_draw_ustranscript(self):
        d = DiagramSettings()
        # domains = [protein.Domain()]
        d1 = protein.Domain('first', [(55, 61), (71, 73)])
        d2 = protein.Domain('second', [(10, 20), (30, 34)])

        t = build_transcript(
            gene=None,
            cds_start=50,
            cds_end=249,
            exons=[(1, 99), (200, 299), (400, 499)],
            strand=STRAND.NEG,
            domains=[d2, d1],
        )
        b = Breakpoint('1', 350, 410, orient=ORIENT.LEFT)
        g = draw_ustranscript(d,
                              self.canvas,
                              t,
                              500,
                              colors={t.exons[1]: '#FFFF00'},
                              breakpoints=[b])
        self.canvas.add(g)
        # self.canvas.saveas('test_draw_ustranscript.svg')
        self.assertEqual(2, len(self.canvas.elements))
        self.assertEqual(3, len(g.elements))
        for el, cls in zip(g.elements[0].elements,
                           ['splicing', 'exon_track', 'protein']):
            self.assertEqual(cls, el.attribs.get('class', ''))

        for el, cls in zip(g.elements[0].elements[1].elements,
                           ['scaffold', 'exon', 'exon', 'exon']):
            self.assertEqual(cls, el.attribs.get('class', ''))

        for el, cls in zip(g.elements[0].elements[2].elements,
                           ['translation', 'domain', 'domain']):
            self.assertEqual(cls, el.attribs.get('class', ''))

        self.assertEqual(
            sum([
                d.track_height,
                d.splice_height,
                2 * d.padding,
                d.domain_track_height * 2,
                d.translation_track_height,
                d.padding,
                d.breakpoint_top_margin,
                d.breakpoint_bottom_margin,
            ]),
            g.height,
        )
        self.assertEqual(d1.name, g.labels['D1'])
        self.assertEqual(d2.name, g.labels['D2'])

    def test_draw_consec_exons(self):
        d = DiagramSettings()
        # domains = [protein.Domain()]
        t = build_transcript(
            gene=None,
            cds_start=50,
            cds_end=249,
            exons=[(1, 99), (200, 299), (300, 350), (400, 499)],
            strand=STRAND.POS,
            domains=[],
        )
        b = Breakpoint('1', 350, 410, orient=ORIENT.LEFT)
        g = draw_ustranscript(d,
                              self.canvas,
                              t,
                              500,
                              colors={t.exons[1]: '#FFFF00'},
                              breakpoints=[b])
        self.canvas.add(g)
        if OUTPUT_SVG:
            self.canvas.saveas('test_draw_consec_exons.svg')

        # self.canvas.saveas('test_draw_ustranscript.svg')
        self.assertEqual(2, len(self.canvas.elements))
        self.assertEqual(3, len(g.elements))
        # check that only 2 splicing marks were created
        self.assertEqual(2, len(g.elements[0].elements[0].elements))
        # get the second exon
        ex2 = g.elements[0].elements[1].elements[2].elements[0]
        print(ex2)
        self.assertAlmostEqual(120.7783426339, ex2.attribs.get('width'))
        # get the third exon
        ex3 = g.elements[0].elements[1].elements[3].elements[0]
        print(ex3)
        self.assertAlmostEqual(96.52494419642852, ex3.attribs.get('width'))

    def test_dynamic_label_color(self):
        self.assertEqual(HEX_WHITE, dynamic_label_color(HEX_BLACK))
        self.assertEqual(HEX_BLACK, dynamic_label_color(HEX_WHITE))

    def test_draw_legend(self):
        d = DiagramSettings()
        swatches = [
            ('#000000', 'black'),
            ('#FF0000', 'red'),
            ('#0000FF', 'blue'),
            ('#00FF00', 'green'),
            ('#FFFF00', 'yellow'),
        ]
        g = draw_legend(d, self.canvas, swatches)
        self.canvas.add(g)

        self.assertEqual('legend', g.attribs.get('class', ''))
        self.assertEqual(
            d.legend_swatch_size * len(swatches) + d.padding *
            (len(swatches) - 1 + 2), g.height)
        self.assertEqual(6, len(g.elements))
        self.assertEqual(
            6 * d.legend_font_size * d.font_width_height_ratio +
            d.padding * 3 + d.legend_swatch_size,
            g.width,
        )

    def test_draw_layout_single_transcript(self):
        d = DiagramSettings()
        d1 = protein.Domain('first', [(55, 61), (71, 73)])
        d2 = protein.Domain('second', [(10, 20), (30, 34)])
        g1 = genomic.Gene('1', 150, 1000, strand=STRAND.POS)
        t = build_transcript(g1, [(200, 299), (400, 499), (700, 899)], 50, 249,
                             [d2, d1])
        b1 = Breakpoint('1', 350, orient=ORIENT.RIGHT)
        b2 = Breakpoint('1', 600, orient=ORIENT.LEFT)
        bpp = BreakpointPair(b1,
                             b2,
                             opposing_strands=False,
                             untemplated_seq='')
        ann = variant.Annotation(bpp,
                                 transcript1=t,
                                 transcript2=t,
                                 event_type=SVTYPE.DUP,
                                 protocol=PROTOCOL.GENOME)
        ann.add_gene(genomic.Gene('1', 1500, 1950, strand=STRAND.POS))

        reference_genome = {'1': MockObject(seq=MockString('A'))}
        ft = variant.FusionTranscript.build(ann, reference_genome)
        ann.fusion = ft
        canvas, legend = draw_sv_summary_diagram(d, ann)
        self.assertEqual(4, len(canvas.elements))  # defs counts as element
        expected_height = (d.top_margin + d.bottom_margin + d.track_height +
                           d.breakpoint_bottom_margin +
                           d.breakpoint_top_margin + d.inner_margin +
                           d.track_height + d.splice_height + d.padding +
                           d.translation_track_height + d.padding * 2 +
                           d.domain_track_height * 2 + d.inner_margin +
                           d.track_height + d.breakpoint_bottom_margin +
                           d.breakpoint_top_margin + d.splice_height)
        if OUTPUT_SVG:
            canvas.saveas('test_draw_layout_single_transcript.svg')
        self.assertEqual(expected_height, canvas.attribs['height'])

    def test_draw_layout_single_genomic(self):
        d = DiagramSettings()
        d1 = protein.Domain('first', [(55, 61), (71, 73)])
        d2 = protein.Domain('second', [(10, 20), (30, 34)])
        g1 = genomic.Gene('1', 150, 1000, strand=STRAND.POS)
        g2 = genomic.Gene('1', 5000, 7500, strand=STRAND.POS)
        t1 = build_transcript(
            gene=g1,
            cds_start=50,
            cds_end=249,
            exons=[(200, 299), (400, 499), (700, 899)],
            domains=[d2, d1],
        )
        t2 = build_transcript(
            gene=g2,
            cds_start=20,
            cds_end=500,
            exons=[(5100, 5299), (5800, 6199), (6500, 6549), (6700, 6799)],
            domains=[],
        )
        b1 = Breakpoint('1', 350, orient=ORIENT.LEFT)
        b2 = Breakpoint('1', 6500, orient=ORIENT.RIGHT)
        bpp = BreakpointPair(b1,
                             b2,
                             opposing_strands=False,
                             untemplated_seq='')
        ann = variant.Annotation(bpp,
                                 transcript1=t1,
                                 transcript2=t2,
                                 event_type=SVTYPE.DEL,
                                 protocol=PROTOCOL.GENOME)
        ann.add_gene(genomic.Gene('1', 1500, 1950, strand=STRAND.POS))
        ann.add_gene(genomic.Gene('1', 3000, 3980, strand=STRAND.POS))
        ann.add_gene(genomic.Gene('1', 3700, 4400, strand=STRAND.NEG))

        reference_genome = {'1': MockObject(seq=MockString('A'))}

        ft = variant.FusionTranscript.build(ann, reference_genome)
        ann.fusion = ft
        self.assertEqual(t1.exons[0], ft.exon_mapping[ft.exons[0].position])
        self.assertEqual(t2.exons[2], ft.exon_mapping[ft.exons[1].position])
        self.assertEqual(t2.exons[3], ft.exon_mapping[ft.exons[2].position])

        canvas, legend = draw_sv_summary_diagram(d, ann)
        self.assertEqual(5, len(canvas.elements))  # defs counts as element

        expected_height = (d.top_margin + d.bottom_margin + d.track_height +
                           d.breakpoint_bottom_margin +
                           d.breakpoint_top_margin + d.inner_margin +
                           d.track_height + d.splice_height +
                           d.breakpoint_bottom_margin +
                           d.breakpoint_top_margin + d.padding +
                           d.translation_track_height + d.padding * 2 +
                           d.domain_track_height * 2 + d.inner_margin +
                           d.track_height + d.splice_height)
        self.assertEqual(expected_height, canvas.attribs['height'])
        if OUTPUT_SVG:
            canvas.saveas('test_draw_layout_single_genomic.svg')

    def test_draw_layout_translocation(self):
        d = DiagramSettings()
        d1 = protein.Domain('first', [(55, 61), (71, 73)])
        d2 = protein.Domain('second', [(10, 20), (30, 34)])
        g1 = genomic.Gene('1', 150, 1000, strand=STRAND.POS)
        g2 = genomic.Gene('2', 5000, 7500, strand=STRAND.NEG)
        t1 = build_transcript(
            gene=g1,
            cds_start=50,
            cds_end=249,
            exons=[(200, 299), (400, 499), (700, 899)],
            domains=[d2, d1],
        )
        t2 = build_transcript(
            gene=g2,
            cds_start=120,
            cds_end=700,
            exons=[(5100, 5299), (5800, 6199), (6500, 6549), (6700, 6799)],
            domains=[],
        )
        b1 = Breakpoint('1', 350, orient=ORIENT.LEFT)
        b2 = Breakpoint('2', 6520, orient=ORIENT.LEFT)
        bpp = BreakpointPair(b1, b2, opposing_strands=True, untemplated_seq='')
        ann = variant.Annotation(bpp,
                                 transcript1=t1,
                                 transcript2=t2,
                                 event_type=SVTYPE.ITRANS,
                                 protocol=PROTOCOL.GENOME)
        # genes 1
        ann.add_gene(genomic.Gene('1', 1500, 1950, strand=STRAND.POS))
        ann.add_gene(genomic.Gene('1', 3000, 3980, strand=STRAND.POS))
        ann.add_gene(genomic.Gene('1', 3700, 4400, strand=STRAND.NEG))
        # genes 2
        ann.add_gene(genomic.Gene('2', 1500, 1950, strand=STRAND.NEG))
        ann.add_gene(genomic.Gene('2', 5500, 9000, strand=STRAND.POS))
        ann.add_gene(genomic.Gene('2', 3700, 4400, strand=STRAND.NEG))

        reference_genome = {
            '1': MockObject(seq=MockString('A')),
            '2': MockObject(seq=MockString('A')),
        }

        ft = variant.FusionTranscript.build(ann, reference_genome)
        ann.fusion = ft
        canvas, legend = draw_sv_summary_diagram(d, ann)
        self.assertEqual(6, len(canvas.elements))  # defs counts as element
        expected_height = (
            d.top_margin + d.bottom_margin + d.track_height * 2 + d.padding +
            d.breakpoint_bottom_margin + d.breakpoint_top_margin +
            d.inner_margin + d.track_height + d.splice_height +
            d.breakpoint_bottom_margin + d.breakpoint_top_margin + d.padding +
            d.translation_track_height + d.padding * 2 +
            d.domain_track_height * 2 + d.inner_margin + d.track_height +
            d.splice_height)
        self.assertEqual(expected_height, canvas.attribs['height'])

    def test_draw_template(self):
        # def draw_template(self, canvas, template, target_width, height, labels=None, colors=None):
        d = DiagramSettings()
        canvas = Drawing(size=(1000, 50))
        t = genomic.Template(
            '1',
            1,
            100000,
            bands=[
                BioInterval(None, 1, 8000, 'p1'),
                BioInterval(None, 10000, 15000, 'p2')
            ],
        )
        g = draw_template(d, canvas, t, 1000)
        canvas.add(g)
        canvas.attribs['height'] = g.height
        canvas = Drawing(size=(1000, 50))

        g = draw_template(d, canvas, TEMPLATE_METADATA['1'], 1000)
        self.assertEqual(
            d.breakpoint_top_margin + d.breakpoint_bottom_margin +
            d.template_track_height, g.height)
        canvas.add(g)
        canvas.attribs['height'] = g.height
        self.assertEqual(2, len(canvas.elements))

    def test_draw_translocation_with_template(self):
        d = DiagramSettings()
        d1 = protein.Domain('PF0001', [(55, 61), (71, 73)])
        d2 = protein.Domain('PF0002', [(10, 20), (30, 34)])
        g1 = genomic.Gene(TEMPLATE_METADATA['1'],
                          150,
                          1000,
                          strand=STRAND.POS,
                          aliases=['HUGO2'])
        g2 = genomic.Gene(TEMPLATE_METADATA['X'],
                          5000,
                          7500,
                          strand=STRAND.NEG,
                          aliases=['HUGO3'])
        t1 = build_transcript(
            gene=g1,
            name='transcript1',
            cds_start=50,
            cds_end=249,
            exons=[(200, 299), (400, 499), (700, 899)],
            domains=[d2, d1],
        )
        t2 = build_transcript(
            gene=g2,
            name='transcript2',
            cds_start=120,
            cds_end=700,
            exons=[(5100, 5299), (5800, 6199), (6500, 6549), (6700, 6799)],
            domains=[],
        )
        b1 = Breakpoint('1', 350, orient=ORIENT.LEFT)
        b2 = Breakpoint('2', 6520, orient=ORIENT.LEFT)
        bpp = BreakpointPair(b1, b2, opposing_strands=True, untemplated_seq='')
        ann = variant.Annotation(bpp,
                                 transcript1=t1,
                                 transcript2=t2,
                                 event_type=SVTYPE.ITRANS,
                                 protocol=PROTOCOL.GENOME)
        # genes 1
        ann.add_gene(
            genomic.Gene('1', 1500, 1950, strand=STRAND.POS,
                         aliases=['HUGO5']))
        ann.add_gene(genomic.Gene('1', 3000, 3980, strand=STRAND.POS))
        ann.add_gene(genomic.Gene('1', 3700, 4400, strand=STRAND.NEG))
        # genes 2
        ann.add_gene(genomic.Gene('2', 1500, 1950, strand=STRAND.NEG))
        ann.add_gene(genomic.Gene('2', 5500, 9000, strand=STRAND.POS))
        ann.add_gene(genomic.Gene('2', 3700, 4400, strand=STRAND.NEG))

        reference_genome = {
            '1': MockObject(seq=MockString('A')),
            '2': MockObject(seq=MockString('A')),
        }

        ft = variant.FusionTranscript.build(ann, reference_genome)
        ann.fusion = ft
        canvas, legend = draw_sv_summary_diagram(d,
                                                 ann,
                                                 draw_reference_templates=True,
                                                 templates=TEMPLATE_METADATA)
        if OUTPUT_SVG:
            canvas.saveas('test_draw_translocation_with_template.svg')
        self.assertEqual(8, len(canvas.elements))  # defs counts as element
        expected_height = (
            d.top_margin + d.bottom_margin + d.track_height * 2 + d.padding +
            d.breakpoint_bottom_margin + d.breakpoint_top_margin +
            d.inner_margin + d.track_height + d.splice_height +
            d.breakpoint_bottom_margin + d.breakpoint_top_margin + d.padding +
            d.translation_track_height + d.padding * 2 +
            d.domain_track_height * 2 + d.inner_margin * 2 + d.track_height +
            d.breakpoint_bottom_margin + d.breakpoint_top_margin +
            d.splice_height + d.template_track_height)
        self.assertAlmostEqual(expected_height, canvas.attribs['height'])

    def test_draw_overlay(self):
        gene = genomic.Gene('12',
                            25357723,
                            25403870,
                            strand=STRAND.NEG,
                            name='KRAS')
        marker = BioInterval('12', 25403865, name='splice site mutation')
        t = build_transcript(
            cds_start=193,
            cds_end=759,
            exons=[
                (25403685, 25403865),
                (25398208, 25398329),
                (25380168, 25380346),
                (25378548, 25378707),
                (25357723, 25362845),
            ],
            gene=gene,
            domains=[],
        )
        build_transcript(
            cds_start=198,
            cds_end=425,
            exons=[(25403685, 25403870), (25398208, 25398329),
                   (25362102, 25362845)],
            gene=gene,
            domains=[],
        )
        build_transcript(
            cds_start=65,
            cds_end=634,
            exons=[
                (25403685, 25403737),
                (25398208, 25398329),
                (25380168, 25380346),
                (25378548, 25378707),
                (25368371, 25368494),
                (25362365, 25362845),
            ],
            gene=gene,
            domains=[
                protein.Domain('domain1', [(1, 10)]),
                protein.Domain('domain1', [(4, 10)])
            ],
            is_best_transcript=True,
        )
        build_transcript(
            cds_start=65,
            cds_end=634,
            exons=[(25403698, 25403863), (25398208, 25398329),
                   (25386753, 25388160)],
            gene=gene,
            domains=[],
        )
        d = DiagramSettings()
        for i, t in enumerate(gene.transcripts):
            t.name = 'transcript {}'.format(i + 1)
        scatterx = [x + 100 for x in range(gene.start, gene.end + 1, 400)]
        scattery = [random.uniform(-0.2, 0.2) for x in scatterx]
        s = ScatterPlot(list(zip(scatterx, scattery)),
                        'cna',
                        ymin=-1,
                        ymax=1,
                        yticks=[-1, 0, 1])

        d.gene_min_buffer = 0
        canvas = draw_multi_transcript_overlay(d,
                                               gene,
                                               vmarkers=[marker],
                                               plots=[s, s])
        self.assertEqual(2, len(canvas.elements))  # defs counts as element
        if OUTPUT_SVG:
            canvas.saveas('test_draw_overlay.svg')

    def test_single_bp_ins_exon(self):
        transcript = fusion.FusionTranscript()
        transcript.position = Interval(401258, 408265)
        transcript.exons = [
            genomic.Exon(401258, 401461, transcript=transcript),
            genomic.Exon(404799,
                         405254,
                         intact_end_splice=False,
                         transcript=transcript),
            genomic.Exon(
                405255,
                405255,
                intact_start_splice=False,
                intact_end_splice=False,
                transcript=transcript,
            ),
            genomic.Exon(405256,
                         408265,
                         intact_start_splice=False,
                         transcript=transcript),
        ]

        cfg = DiagramSettings(width=1500)
        canvas = Drawing(size=(cfg.width, 1000))
        drawing_width = cfg.width - cfg.label_left_margin - cfg.left_margin - cfg.right_margin
        canvas.add(
            draw_ustranscript(cfg,
                              canvas,
                              transcript,
                              target_width=drawing_width))
        if OUTPUT_SVG:
            canvas.saveas('test_single_bp_ins_exon.svg')

    def test_single_bp_dup(self):
        transcript = fusion.FusionTranscript()
        transcript.position = Interval(1, 500)
        transcript.exons = [
            genomic.Exon(1, 7, transcript=transcript, intact_end_splice=False),
            genomic.Exon(8,
                         8,
                         transcript=transcript,
                         intact_start_splice=False,
                         intact_end_splice=False),
            genomic.Exon(9,
                         100,
                         transcript=transcript,
                         intact_start_splice=False),
            genomic.Exon(200, 500, transcript=transcript),
        ]
        cfg = DiagramSettings(width=1500)
        canvas = Drawing(size=(cfg.width, 1000))
        drawing_width = cfg.width - cfg.label_left_margin - cfg.left_margin - cfg.right_margin
        canvas.add(
            draw_ustranscript(cfg,
                              canvas,
                              transcript,
                              target_width=drawing_width))
        if OUTPUT_SVG:
            canvas.saveas('test_single_bp_dup.svg')

    def test_two_exon_transcript(self):
        transcript = fusion.FusionTranscript()
        transcript.position = Interval(1, 555)
        transcript.exons = [
            genomic.Exon(55820038, 55820969, transcript=transcript),
            genomic.Exon(55820971, 55820976, transcript=transcript),
        ]
        transcript.exon_mapping[Interval(55820971, 55820976)] = MockObject(
            transcript=MockObject(exon_number=lambda *x: 2))
        cfg = DiagramSettings(width=1500)
        canvas = Drawing(size=(cfg.width, 1000))
        drawing_width = cfg.width - cfg.label_left_margin - cfg.left_margin - cfg.right_margin
        canvas.add(
            draw_ustranscript(cfg,
                              canvas,
                              transcript,
                              target_width=drawing_width))
        if OUTPUT_SVG:
            canvas.saveas('test_two_exon_transcript.svg')
Esempio n. 25
0
r = corner_ruler(scale=scale,
                 length=100,
                 major_interval=10,
                 minor_per_major=10)
translate_inch(r, tool_size - diag_shift, diag_shift)
utm_tool.add(r)

# Small map ruler
scale = 8000
diag_shift = 0.85
r = corner_ruler(scale=scale, length=200, major_interval=50, minor_per_major=5)
translate_inch(r, tool_size - diag_shift, diag_shift)
utm_tool.add(r)

#-------------------------------------------------------------------------------
# Repliacte onto printout
#-------------------------------------------------------------------------------
dwg = Drawing(size=(8.5 * inch, 11 * inch))

defs = Defs()
defs.add(utm_tool)
dwg.add(defs)

for xi in range(3):
    for yi in range(4):
        dwg.add(UseInch(
            utm_tool,
            (0.5 + xi * 2.5, 0.5 + yi * 2.5),
        ))
write_to_pdf(dwg, "UTM-roamer-ruler-VT.pdf")
Esempio n. 26
0
        # filter out the reverse path
        paths_to_add = [p for p in paths_to_add if p[0] != path_to_add[0]]
        start_location = paths[path_to_add[0]].start if path_to_add[0] else paths[
            path_to_add[1]].end
'''

if __name__ == "__main__":
    # make a graph of the next available grid
    num_grid = 8
    spacing = 30

    dwg = Drawing(join(OUTPUT_DIRECTORY, "next_available_grid.svg"),
                  (num_grid * spacing, num_grid * spacing))
    for x in range(num_grid):
        dwg.add(
            dwg.line(start=(0, x * spacing),
                     end=(num_grid * spacing, x * spacing),
                     stroke=rgb(10, 10, 16, '%')))
        dwg.add(
            dwg.line(start=(x * spacing, 0),
                     end=(x * spacing, num_grid * spacing),
                     stroke=rgb(10, 10, 16, '%')))
    start_point = [4, 4]

    dwg.add(
        dwg.rect(insert=(start_point[0] * spacing, start_point[1] * spacing),
                 size=(spacing, spacing),
                 fill=rgb(100, 100, 16, '%')))
    count = 0
    last_point = start_point
    for next_available in NextAvailableGrid(*start_point):
        dwg.add(
Esempio n. 27
0
Figure built manually in SVG.

Note, these require the svgwrite package (and optionally, the svglib package to convert to pdf).
"""
import subprocess

from svgwrite import Drawing

filename = 'scaling_compute_totals_gmres.svg'
color_phys = '#85C1E9'
color_scaled = '#EC7063'
main_font_size = 20

dwg = Drawing(filename, (2500, 2000), debug=True)

top_text = dwg.add(dwg.g(font_size=main_font_size,
                         style="font-family: arial;"))

locs = [
    'NL Inputs', 'NL Outputs', 'NL Residuals', 'LN Inputs', 'LN Outputs',
    'LN Residuals', 'Jacobian'
]

x = 650
y = 50
delta_x = 180
vertical_locs = []
for loc in locs:
    top_text.add(dwg.text(loc, (x - len(loc) * 4, y)))
    vertical_locs.append(x)
    x += delta_x
def flatten_scene(pScene):
    lNode = pScene.GetRootNode()

    if not lNode:
        return

    for i in range(lNode.GetChildCount()):

        lChildNode = lNode.GetChild(i)
        if lChildNode.GetNodeAttribute() is None:
            continue
        lAttributeType = (lChildNode.GetNodeAttribute().GetAttributeType())
        if lAttributeType != FbxNodeAttribute.eMesh:
            continue
        lMesh = lChildNode.GetNodeAttribute()
        projected_points = {}
        control_points = lMesh.GetControlPoints()
        start_point = 0
        poly_paths = []
        for polygon_num in range(lMesh.GetPolygonCount()):
            corners = []
            for corner in range(3):
                corners.append(lMesh.GetPolygonVertex(polygon_num, corner))
            # first, check if any of the control points are already projected
            flattened = []
            for j, corner in enumerate(corners):
                if corner in projected_points:
                    flattened.append(projected_points[corner])
                    continue
                target_corner = corners[j - 1]
                current_vec = control_points[corner]
                target_vec = control_points[target_corner]
                angle = acos(
                    current_vec.DotProduct(target_vec) /
                    (current_vec.Length() * target_vec.Length()))
                length = current_vec.Distance(target_vec)
                # find where the last point was. If it doesn't exist, use the start point
                start_corner = projected_points[target_corner] \
                    if target_corner in projected_points else start_point
                flattened_corner = start_corner + length * (cos(angle) +
                                                            1j * sin(angle))
                projected_points[corner] = flattened_corner
                start_point = flattened_corner
                flattened.append(flattened_corner)
            poly_paths.append(
                Path(*[
                    Line(start=flattened[j], end=flattened[j - 1])
                    for j in range(3)
                ]))

        dwg = Drawing("mesh{}.svg".format(i), profile='tiny')
        for poly_path in poly_paths:
            dwg.add(
                dwg.path(
                    **{
                        'd': poly_path.d(),
                        'fill': "none",
                        'stroke-width': 4,
                        'stroke': rgb(0, 0, 0)
                    }))
        bbox = calc_overall_bbox(poly_paths)
        width, height = abs(bbox[1] - bbox[0]), abs(bbox[3] - bbox[2])
        dwg.viewbox(min(bbox[0], bbox[1]), min(bbox[2], bbox[3]), width,
                    height)
        dwg.save()
Esempio n. 29
0
	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() #!!!!! Генерировать хорошие исключения
Esempio n. 30
0
Note, these require the svgwrite package (and optionally, the svglib package to convert to pdf).
"""
from __future__ import print_function
import subprocess

from svgwrite import Drawing

filename = 'scaling_run_model.svg'
color_phys = '#85C1E9'
color_scaled = '#EC7063'
main_font_size = 24

dwg = Drawing(filename, (2500, 2000), debug=True)

top_text = dwg.add(dwg.g(font_size=main_font_size, style="font-family: arial;"))

locs = ['NL Inputs',
        'NL Outputs',
        'NL Residuals']

x = 900
y = 50
delta_x = 400
vertical_locs = []
for loc in locs:
    top_text.add(dwg.text(loc, (x - len(loc)*4, y)))
    vertical_locs.append(x)
    x += delta_x

legend_text = dwg.add(dwg.g(font_size=main_font_size, style="font-family: arial;"))
Esempio n. 31
0
def disvg(paths=None, colors=None,
          filename=os_path.join(getcwd(), 'disvg_output.svg'),
          stroke_widths=None, nodes=None, node_colors=None, node_radii=None,
          openinbrowser=True, timestamp=False,
          margin_size=0.1, mindim=600, dimensions=None,
          viewbox=None, text=None, text_path=None, font_size=None,
          attributes=None, svg_attributes=None, svgwrite_debug=False, paths2Drawing=False):
    """Takes in a list of paths and creates an SVG file containing said paths.
    REQUIRED INPUTS:
        :param paths - a list of paths

    OPTIONAL INPUT:
        :param colors - specifies the path stroke color.  By default all paths
        will be black (#000000).  This paramater can be input in a few ways
        1) a list of strings that will be input into the path elements stroke
            attribute (so anything that is understood by the svg viewer).
        2) a string of single character colors -- e.g. setting colors='rrr' is
            equivalent to setting colors=['red', 'red', 'red'] (see the
            'color_dict' dictionary above for a list of possibilities).
        3) a list of rgb 3-tuples -- e.g. colors = [(255, 0, 0), ...].

        :param filename - the desired location/filename of the SVG file
        created (by default the SVG will be stored in the current working
        directory and named 'disvg_output.svg').

        :param stroke_widths - a list of stroke_widths to use for paths
        (default is 0.5% of the SVG's width or length)

        :param nodes - a list of points to draw as filled-in circles

        :param node_colors - a list of colors to use for the nodes (by default
        nodes will be red)

        :param node_radii - a list of radii to use for the nodes (by default
        nodes will be radius will be 1 percent of the svg's width/length)

        :param text - string or list of strings to be displayed

        :param text_path - if text is a list, then this should be a list of
        path (or path segments of the same length.  Note: the path must be
        long enough to display the text or the text will be cropped by the svg
        viewer.

        :param font_size - a single float of list of floats.

        :param openinbrowser -  Set to True to automatically open the created
        SVG in the user's default web browser.

        :param timestamp - if True, then the a timestamp will be appended to
        the output SVG's filename.  This will fix issues with rapidly opening
        multiple SVGs in your browser.

        :param margin_size - The min margin (empty area framing the collection
        of paths) size used for creating the canvas and background of the SVG.

        :param mindim - The minimum dimension (height or width) of the output
        SVG (default is 600).

        :param dimensions - The (x,y) display dimensions of the output SVG.
        I.e. this specifies the `width` and `height` SVG attributes. Note that 
        these also can be used to specify units other than pixels. Using this 
        will override the `mindim` parameter.

        :param viewbox - This specifies the coordinated system used in the svg.
        The SVG `viewBox` attribute works together with the the `height` and 
        `width` attrinutes.  Using these three attributes allows for shifting 
        and scaling of the SVG canvas without changing the any values other 
        than those in `viewBox`, `height`, and `width`.  `viewbox` should be 
        input as a 4-tuple, (min_x, min_y, width, height), or a string 
        "min_x min_y width height".  Using this will override the `mindim` 
        parameter.

        :param attributes - a list of dictionaries of attributes for the input
        paths.  Note: This will override any other conflicting settings.

        :param svg_attributes - a dictionary of attributes for output svg.
        
        :param svgwrite_debug - This parameter turns on/off `svgwrite`'s 
        debugging mode.  By default svgwrite_debug=False.  This increases 
        speed and also prevents `svgwrite` from raising of an error when not 
        all `svg_attributes` key-value pairs are understood.
        
        :param paths2Drawing - If true, an `svgwrite.Drawing` object is 
        returned and no file is written.  This `Drawing` can later be saved 
        using the `svgwrite.Drawing.save()` method.

    NOTES:
        * The `svg_attributes` parameter will override any other conflicting 
        settings.

        * Any `extra` parameters that `svgwrite.Drawing()` accepts can be 
        controlled by passing them in through `svg_attributes`.

        * The unit of length here is assumed to be pixels in all variables.

        * If this function is used multiple times in quick succession to
        display multiple SVGs (all using the default filename), the
        svgviewer/browser will likely fail to load some of the SVGs in time.
        To fix this, use the timestamp attribute, or give the files unique
        names, or use a pause command (e.g. time.sleep(1)) between uses.
    """


    _default_relative_node_radius = 5e-3
    _default_relative_stroke_width = 1e-3
    _default_path_color = '#000000'  # black
    _default_node_color = '#ff0000'  # red
    _default_font_size = 12


    # append directory to filename (if not included)
    if os_path.dirname(filename) == '':
        filename = os_path.join(getcwd(), filename)

    # append time stamp to filename
    if timestamp:
        fbname, fext = os_path.splitext(filename)
        dirname = os_path.dirname(filename)
        tstamp = str(time()).replace('.', '')
        stfilename = os_path.split(fbname)[1] + '_' + tstamp + fext
        filename = os_path.join(dirname, stfilename)

    # check paths and colors are set
    if isinstance(paths, Path) or is_path_segment(paths):
        paths = [paths]
    if paths:
        if not colors:
            colors = [_default_path_color] * len(paths)
        else:
            assert len(colors) == len(paths)
            if isinstance(colors, str):
                colors = str2colorlist(colors,
                                       default_color=_default_path_color)
            elif isinstance(colors, list):
                for idx, c in enumerate(colors):
                    if is3tuple(c):
                        colors[idx] = "rgb" + str(c)

    # check nodes and nodes_colors are set (node_radii are set later)
    if nodes:
        if not node_colors:
            node_colors = [_default_node_color] * len(nodes)
        else:
            assert len(node_colors) == len(nodes)
            if isinstance(node_colors, str):
                node_colors = str2colorlist(node_colors,
                                            default_color=_default_node_color)
            elif isinstance(node_colors, list):
                for idx, c in enumerate(node_colors):
                    if is3tuple(c):
                        node_colors[idx] = "rgb" + str(c)

    # set up the viewBox and display dimensions of the output SVG
    # along the way, set stroke_widths and node_radii if not provided
    assert paths or nodes
    stuff2bound = []
    if viewbox:
        if not isinstance(viewbox, str):
            viewbox = '%s %s %s %s' % viewbox
        if dimensions is None:
            dimensions = viewbox.split(' ')[2:4]
    elif dimensions:
        dimensions = tuple(map(str, dimensions))
        def strip_units(s):
            return re.search(r'\d*\.?\d*', s.strip()).group()
        viewbox = '0 0 %s %s' % tuple(map(strip_units, dimensions))
    else:
        if paths:
            stuff2bound += paths
        if nodes:
            stuff2bound += nodes
        if text_path:
            stuff2bound += text_path
        xmin, xmax, ymin, ymax = big_bounding_box(stuff2bound)
        dx = xmax - xmin
        dy = ymax - ymin

        if dx == 0:
            dx = 1
        if dy == 0:
            dy = 1

        # determine stroke_widths to use (if not provided) and max_stroke_width
        if paths:
            if not stroke_widths:
                sw = max(dx, dy) * _default_relative_stroke_width
                stroke_widths = [sw]*len(paths)
                max_stroke_width = sw
            else:
                assert len(paths) == len(stroke_widths)
                max_stroke_width = max(stroke_widths)
        else:
            max_stroke_width = 0

        # determine node_radii to use (if not provided) and max_node_diameter
        if nodes:
            if not node_radii:
                r = max(dx, dy) * _default_relative_node_radius
                node_radii = [r]*len(nodes)
                max_node_diameter = 2*r
            else:
                assert len(nodes) == len(node_radii)
                max_node_diameter = 2*max(node_radii)
        else:
            max_node_diameter = 0

        extra_space_for_style = max(max_stroke_width, max_node_diameter)
        xmin -= margin_size*dx + extra_space_for_style/2
        ymin -= margin_size*dy + extra_space_for_style/2
        dx += 2*margin_size*dx + extra_space_for_style
        dy += 2*margin_size*dy + extra_space_for_style
        viewbox = "%s %s %s %s" % (xmin, ymin, dx, dy)

        if dx > dy:
            szx = str(mindim) + 'px'
            szy = str(int(ceil(mindim * dy / dx))) + 'px'
        else:
            szx = str(int(ceil(mindim * dx / dy))) + 'px'
            szy = str(mindim) + 'px'
        dimensions = szx, szy

    # Create an SVG file
    if svg_attributes is not None:
        dimensions = (svg_attributes.get("width", dimensions[0]),
                      svg_attributes.get("height", dimensions[1]))
        debug = svg_attributes.get("debug", svgwrite_debug)
        dwg = Drawing(filename=filename, size=dimensions, debug=debug,
                      **svg_attributes)
    else:
        dwg = Drawing(filename=filename, size=dimensions, debug=svgwrite_debug,
                      viewBox=viewbox)

    # add paths
    if paths:
        for i, p in enumerate(paths):
            if isinstance(p, Path):
                ps = p.d()
            elif is_path_segment(p):
                ps = Path(p).d()
            else:  # assume this path, p, was input as a Path d-string
                ps = p

            if attributes:
                good_attribs = {'d': ps}
                for key in attributes[i]:
                    val = attributes[i][key]
                    if key != 'd':
                        try:
                            dwg.path(ps, **{key: val})
                            good_attribs.update({key: val})
                        except Exception as e:
                            warn(str(e))

                dwg.add(dwg.path(**good_attribs))
            else:
                dwg.add(dwg.path(ps, stroke=colors[i],
                                 stroke_width=str(stroke_widths[i]),
                                 fill='none'))

    # add nodes (filled in circles)
    if nodes:
        for i_pt, pt in enumerate([(z.real, z.imag) for z in nodes]):
            dwg.add(dwg.circle(pt, node_radii[i_pt], fill=node_colors[i_pt]))

    # add texts
    if text:
        assert isinstance(text, str) or (isinstance(text, list) and
                                         isinstance(text_path, list) and
                                         len(text_path) == len(text))
        if isinstance(text, str):
            text = [text]
            if not font_size:
                font_size = [_default_font_size]
            if not text_path:
                pos = complex(xmin + margin_size*dx, ymin + margin_size*dy)
                text_path = [Line(pos, pos + 1).d()]
        else:
            if font_size:
                if isinstance(font_size, list):
                    assert len(font_size) == len(text)
                else:
                    font_size = [font_size] * len(text)
            else:
                font_size = [_default_font_size] * len(text)
        for idx, s in enumerate(text):
            p = text_path[idx]
            if isinstance(p, Path):
                ps = p.d()
            elif is_path_segment(p):
                ps = Path(p).d()
            else:  # assume this path, p, was input as a Path d-string
                ps = p

            # paragraph = dwg.add(dwg.g(font_size=font_size[idx]))
            # paragraph.add(dwg.textPath(ps, s))
            pathid = 'tp' + str(idx)
            dwg.defs.add(dwg.path(d=ps, id=pathid))
            txter = dwg.add(dwg.text('', font_size=font_size[idx]))
            txter.add(txt.TextPath('#'+pathid, s))

    if paths2Drawing:
        return dwg
      
    # save svg
    if not os_path.exists(os_path.dirname(filename)):
        makedirs(os_path.dirname(filename))
    dwg.save()

    # re-open the svg, make the xml pretty, and save it again
    xmlstring = md_xml_parse(filename).toprettyxml()
    with open(filename, 'w') as f:
        f.write(xmlstring)

    # try to open in web browser
    if openinbrowser:
        try:
            open_in_browser(filename)
        except:
            print("Failed to open output SVG in browser.  SVG saved to:")
            print(filename)
Esempio n. 32
0
def create_svg(file, surface, controls_sequence = None, sn = None):
	min_x, max_x = None, None
	min_y, max_y = None, None
	
	for polygon in surface.polygons:
		for vertex in polygon.vertices:
			if min_x is None:
				min_x, max_x = vertex[0], vertex[0]
				min_y, max_y = vertex[1], vertex[1]
			else:
				min_x, max_x = min(vertex[0], min_x), max(vertex[0], max_x)
				min_y, max_y = min(vertex[1], min_y), max(vertex[1], max_y)
				
				
	a = (min_x, max_x, min_y, max_y)
	b = (max_x - min_x, max_y - min_y, 10.0)


	surface_view = Drawing(size = (max_x - min_x, max_y - min_y))
	
	
	def correct_vertex(vertex, surface_bounds, canvas_bounds):
		x_coordinate, y_coordinate                       = vertex
		left_bound, right_bound, bottom_bound, top_bound = surface_bounds
		canvas_width, canvas_height, canvas_padding      = canvas_bounds
		
		
		x_coordinate_scaling = \
			(canvas_width - 2.0 * canvas_padding) \
				/ (right_bound - left_bound)
				
		y_coordinate_scaling = \
			(canvas_height - 2.0 * canvas_padding) \
				/ (top_bound - bottom_bound)
				
				
		x_coordinate = \
			x_coordinate_scaling * (x_coordinate - left_bound) \
				+ canvas_padding
				
		y_coordinate = \
			y_coordinate_scaling * (y_coordinate - bottom_bound) \
				+ canvas_padding
				
		y_coordinate = canvas_height - y_coordinate
		
		
		return x_coordinate, y_coordinate
		
		
	for polygon in surface.polygons:
		vertices = \
			[correct_vertex((x_coordinate, y_coordinate), a, b) \
				for x_coordinate, y_coordinate, z_coordinate \
				in  polygon.vertices]
				
				
		if surface.maximal_impossibility - surface.minimal_impossibility > 0.0:
			relative_impossibility = \
				(polygon.impossibility - surface.minimal_impossibility) \
					/ (surface.maximal_impossibility - surface.minimal_impossibility)
		else:
			relative_impossibility = 0.0
			
		fill_color_red_component   = round(255.0 * relative_impossibility)
		fill_color_green_component = round(255.0 - 255.0 * relative_impossibility)
		fill_color_blue_component  = 0
		fill_color                 = \
			rgb(
				fill_color_red_component,
				fill_color_green_component,
				fill_color_blue_component
			)
			
		polygon_view = \
			Polygon(
				vertices,
				stroke_width = 1,
				stroke       = rgb(0, 0, 0),
				fill         = fill_color
			)
			
		surface_view.add(polygon_view)
		
		
	if sn is not None:
		for polygon_index, polygon in enumerate(surface.polygons):
			polygon_index_view = \
				Text(
					str(polygon_index),
					insert = \
						correct_vertex(
							(polygon.center[0], polygon.center[1]),
							a, b
						)
				)
				
			surface_view.add(polygon_index_view)
			
			
	# if sn is not None:
	# 	from svgwrite.text import Text
	# 	for state in sn:
	# 		polygon = state.polygon
	# 		polygon_number = sn[state]
			
	# 		polygon_center      = polygon.center[0], polygon.center[1]
	# 		q,w = correct_vertex(polygon_center, a, b)
	# 		polygon_center_view = \
	# 			Text(
	# 				str(polygon_number),
	# 				insert = (q+2,w+2),
	# 				style = "font-size: 50%; font-color: #808080"
	# 			)
				
	# 		surface_view.add(polygon_center_view)
			
			
	if controls_sequence is not None:
		last_state          = None
		last_polygon_center = None
		smoother            = Smoother(surface = surface, smoothing_depth = 1)
		
		
		for state in controls_sequence:
			polygon = state.polygons_sequence[-1]
			
			polygon_center      = polygon.center[0], polygon.center[1]
			polygon_center_view = \
				Circle(
					correct_vertex(polygon_center, a, b),
					2,
					stroke_width = 0,
					fill         = rgb(0, 0, 0),
				)
				
			surface_view.add(polygon_center_view)
			
			
			if last_state is not None:
				smoother.push_transfer(
					last_state.get_transfer(state)
				)
				
				first_transfer_point, second_transfer_point = \
					smoother.transfers_points_sequence[0]
					
					
				first_trek_view = \
					Line(
						correct_vertex(last_polygon_center, a, b),
						correct_vertex(
							(first_transfer_point.coordinates[0],
								first_transfer_point.coordinates[1]),
							a,
							b
						),
						stroke_width = 1,
						stroke       = rgb(0, 0, 0),
					)
					
				first_trek_end_view = \
					Circle(
						correct_vertex(
							(first_transfer_point.coordinates[0],
								first_transfer_point.coordinates[1]),
							a,
							b
						),
						2,
						stroke_width = 0,
						fill         = rgb(0, 0, 0),
					)
					
				second_trek_view = \
					Line(
						correct_vertex(
							(second_transfer_point.coordinates[0],
								second_transfer_point.coordinates[1]),
							a,
							b
						),
						correct_vertex(polygon_center, a, b),
						stroke_width = 1,
						stroke       = rgb(0, 0, 0),
					)
					
				second_trek_start_view = \
					Circle(
						correct_vertex(
							(second_transfer_point.coordinates[0],
								second_transfer_point.coordinates[1]),
							a,
							b
						),
						2,
						stroke_width = 0,
						fill         = rgb(0, 0, 0),
					)
					
					
				surface_view.add(first_trek_view)
				surface_view.add(first_trek_end_view)
				surface_view.add(second_trek_view)
				surface_view.add(second_trek_start_view)
				
				
			last_state          = state
			last_polygon_center = polygon_center
			
			
	surface_view.write(file)
	
Esempio n. 33
0
 def export(self):
     dwg = Drawing(self.name, width=W, height=H)
     for r in self.rects:
         dwg.add(dwg.rect(insert=(r.x, r.y), size=(r.w, r.h), fill='black'))
     dwg.save()
Esempio n. 34
0
Image.fromarray(np.asarray(skeletonized, dtype='uint8') *
                255).save("skeletonized.png")

g = im_to_graph(skeletonized)
lines = list(partition_forest(g))
assert len(lines) == 1
line = lines.pop()
smoothed = gaussian_filter1d(np.asarray(line, dtype=float),
                             sigma=DEFAULT_SIGMA,
                             axis=0)

length = np.linalg.norm(np.diff(smoothed, axis=0), axis=1).sum()

dwg = Drawing("line.svg")
dwg.add(dwg.rect(size=drawn_arr.shape[::-1], fill="black"))
dwg.add(
    dwg.polyline([tuple(pair[::-1]) for pair in smoothed],
                 stroke="white",
                 stroke_width=4,
                 fill="none"))

dwg.save(pretty=True, indent=2)


def pad_dim(vals, pad, integer=True):
    vmin = vals.min()
    vmax = vals.max()
    vpad = (vmax - vmin) * pad
    if integer:
        vpad = int(np.ceil(vpad))
Esempio n. 35
0
    def _draw(self, d: svgwrite.Drawing, size: XY, offset: XY, year: int):
        min_size = min(size.x, size.y)
        year_size = min_size * 4.0 / 80.0
        year_style = 'font-size:{}px; font-family:Arial;'.format(year_size)
        month_style = 'font-size:{}px; font-family:Arial;'.format(min_size *
                                                                  3.0 / 80.0)
        day_style = 'dominant-baseline: central; font-size:{}px; font-family:Arial;'.format(
            min_size * 1.0 / 80.0)
        day_length_style = 'font-size:{}px; font-family:Arial;'.format(
            min_size * 1.0 / 80.0)

        d.add(
            d.text('{}'.format(year),
                   insert=offset.tuple(),
                   fill=self.poster.colors['text'],
                   alignment_baseline="hanging",
                   style=year_style))
        offset.y += year_size
        size.y -= year_size
        count_x = 31
        for month in range(1, 13):
            date = datetime.date(year, month, 1)
            (_, last_day) = calendar.monthrange(year, month)
            count_x = max(count_x, date.weekday() + last_day)

        cell_size = min(size.x / count_x, size.y / 36)
        spacing = XY((size.x - cell_size * count_x) / (count_x - 1),
                     (size.y - cell_size * 3 * 12) / 11)

        dow = ["M", "T", "W", "T", "F", "S", "S"]
        for month in range(1, 13):
            date = datetime.date(year, month, 1)
            y = month - 1
            y_pos = offset.y + (y * 3 + 1) * cell_size + y * spacing.y
            d.add(
                d.text(date.strftime("%B"),
                       insert=(offset.x, y_pos - 2),
                       fill=self.poster.colors['text'],
                       alignment_baseline="hanging",
                       style=month_style))

            day_offset = date.weekday()
            while date.month == month:
                x = date.day - 1
                x_pos = offset.x + (day_offset + x) * cell_size + x * spacing.x
                pos = (x_pos + 0.05 * cell_size, y_pos + 0.05 * cell_size)
                dim = (cell_size * 0.9, cell_size * 0.9)
                text_date = date.strftime("%Y-%m-%d")
                if text_date in self.poster.tracks_by_date:
                    tracks = self.poster.tracks_by_date[text_date]
                    length = sum([t.length for t in tracks])
                    color = self.color(self.poster.length_range_by_date,
                                       length,
                                       [t for t in tracks if t.special])
                    d.add(d.rect(pos, dim, fill=color))
                    d.add(
                        d.text("{:.1f}".format(self.poster.m2u(length)),
                               insert=(x_pos + cell_size / 2,
                                       y_pos + cell_size + cell_size / 2),
                               text_anchor="middle",
                               style=day_length_style,
                               fill=self.poster.colors['text']))
                else:
                    d.add(d.rect(pos, dim, fill='#444444'))

                d.add(
                    d.text(dow[date.weekday()],
                           insert=(offset.x + (day_offset + x) * cell_size +
                                   cell_size / 2, y_pos + cell_size / 2),
                           text_anchor="middle",
                           alignment_baseline="middle",
                           style=day_style))
                date += datetime.timedelta(1)
Esempio n. 36
0
    def process(self):
        graphs = {}
        intervals = []

        smooth = self.parameters.get("smooth",
                                     self.options["smooth"]["default"])
        normalise_values = self.parameters.get(
            "normalise", self.options["normalise"]["default"])
        completeness = convert_to_int(
            self.parameters.get("complete",
                                self.options["complete"]["default"]), 0)
        graph_label = self.parameters.get("label",
                                          self.options["label"]["default"])
        top = convert_to_int(
            self.parameters.get("top", self.options["top"]["default"]), 10)

        # first gather graph data: each distinct item gets its own graph and
        # for each graph we have a sequence of intervals, each interval with
        # its own value
        first_date = "9999-99-99"
        last_date = "0000-00-00"

        with self.source_file.open() as input:
            reader = csv.DictReader(input)

            item_key = "text" if "text" in reader.fieldnames else "item"
            date_key = "time" if "time" in reader.fieldnames else "date"
            value_key = "value" if "value" in reader.fieldnames else "frequency"

        for row in self.iterate_csv_items(self.source_file):
            if row[item_key] not in graphs:
                graphs[row[item_key]] = {}

            # make sure the months and days are zero-padded
            interval = row.get(date_key, "")
            interval = "-".join([
                str(bit).zfill(2 if len(bit) != 4 else 4)
                for bit in interval.split("-")
            ])
            first_date = min(first_date, interval)
            last_date = max(last_date, interval)

            if interval not in intervals:
                intervals.append(interval)

            if interval not in graphs[row[item_key]]:
                graphs[row[item_key]][interval] = 0

            graphs[row[item_key]][interval] += float(row.get(value_key, 0))

        # first make sure we actually have something to render
        intervals = sorted(intervals)
        if len(intervals) <= 1:
            self.dataset.update_status(
                "Not enough data for a side-by-side over-time visualisation.")
            self.dataset.finish(0)
            return

        # only retain most-occurring series - sort by sum of all frequencies
        if len(graphs) > top:
            selected_graphs = {
                graph: graphs[graph]
                for graph in sorted(
                    graphs,
                    key=lambda x: sum(
                        [graphs[x][interval] for interval in graphs[x]]),
                    reverse=True)[0:top]
            }
            graphs = selected_graphs

        # there may be items that do not have values for all intervals
        # this will distort the graph, so the next step is to make sure all
        # graphs consist of the same continuous interval list
        missing = {graph: 0 for graph in graphs}
        for graph in graphs:
            missing[graph], graphs[graph] = pad_interval(
                graphs[graph],
                first_interval=first_date,
                last_interval=last_date)

        # now that's done, make sure the graph datapoints are in order
        intervals = sorted(list(graphs[list(graphs)[0]].keys()))

        # delete graphs that do not have the required amount of intervals
        # this is useful to get rid of outliers and items that only occur
        # very few times over the full interval
        if completeness > 0:
            intervals_required = len(intervals) * (completeness / 100)
            disqualified = []
            for graph in graphs:
                if len(intervals) - missing[graph] < intervals_required:
                    disqualified.append(graph)

            graphs = {
                graph: graphs[graph]
                for graph in graphs if graph not in disqualified
            }

        # determine max value per item, so we can normalize them later
        limits = {}
        max_limit = 0
        for graph in graphs:
            for interval in graphs[graph]:
                limits[graph] = max(limits.get(graph, 0),
                                    abs(graphs[graph][interval]))
                max_limit = max(max_limit, abs(graphs[graph][interval]))

        # order graphs by highest (or lowest) value)
        limits = {
            limit: limits[limit]
            for limit in sorted(limits, key=lambda l: limits[l])
        }
        graphs = {graph: graphs[graph] for graph in limits}

        if not graphs:
            # maybe nothing is actually there to be graphed
            self.dataset.update_status(
                "No items match the selection criteria - nothing to visualise."
            )
            self.dataset.finish(0)
            return None

        # how many vertical grid lines (and labels) are to be included at most
        # 12 is a sensible default because it allows one label per month for a full
        # year's data
        max_gridlines = 12

        # If True, label is put at the lower left bottom of the graph rather than
        # outside it. Automatically set to True if one of the labels is long, as
        # else the label would fall off the screen
        label_in_graph = max([len(item) for item in graphs]) > 30

        # determine how wide each interval should be
        # the graph has a minimum width - but the graph's width will be
        # extended if at this minimum width each item does not have the
        # minimum per-item width
        min_full_width = 600
        min_item_width = 1
        item_width = max(min_item_width, min_full_width / len(intervals))

        # determine how much space each graph should get
        # same trade-off as for the interval width
        min_full_height = 300
        min_item_height = 100
        item_height = max(min_item_height, min_full_height / len(graphs))

        # margin - this should be enough for the text labels to fit in
        margin = 75

        # this determines the "flatness" of the isometric projection and an be
        # tweaked for different looks - basically corresponds to how far the
        # camera is above the horizon
        plane_angle = 120

        # don't change these
        plane_obverse = radians((180 - plane_angle) / 2)
        plane_angle = radians(plane_angle)

        # okay, now determine the full graphic size with these dimensions projected
        # semi-isometrically. We can also use these values later for drawing for
        # drawing grid lines, et cetera. The axis widths and heights here are the
        # dimensions of the bounding box wrapping the isometrically projected axes.
        x_axis_length = (item_width * (len(intervals) - 1))
        y_axis_length = (item_height * len(graphs))

        x_axis_width = (sin(plane_angle / 2) * x_axis_length)
        y_axis_width = (sin(plane_angle / 2) * y_axis_length)
        canvas_width = x_axis_width + y_axis_width

        x_axis_height = (cos(plane_angle / 2) * x_axis_length)
        y_axis_height = (cos(plane_angle / 2) * y_axis_length)
        canvas_height = x_axis_height + y_axis_height

        # now we have the dimensions, the canvas can be instantiated
        canvas = Drawing(str(self.dataset.get_results_path()),
                         size=(canvas_width + margin,
                               canvas_height + (2 * margin)),
                         style="font-family:monospace")

        # draw gridlines - vertical
        gridline_x = y_axis_width
        gridline_y = margin + canvas_height

        step_x_horizontal = sin(plane_angle / 2) * item_width
        step_y_horizontal = cos(plane_angle / 2) * item_width
        step_x_vertical = sin(plane_angle / 2) * item_height
        step_y_vertical = cos(plane_angle / 2) * item_height

        # labels for x axis
        skip = max(1, int(len(intervals) / max_gridlines))
        for i in range(0, len(intervals)):
            if i % skip == 0:
                canvas.add(
                    Line(start=(gridline_x, gridline_y),
                         end=(gridline_x - y_axis_width,
                              gridline_y - y_axis_height),
                         stroke="grey",
                         stroke_width=0.25))

                # to properly position the rotated and skewed text a container
                # element is needed
                label1 = str(intervals[i])[0:4]
                center = (gridline_x, gridline_y)
                container = SVG(x=center[0] - 25,
                                y=center[1],
                                width="50",
                                height="1.5em",
                                overflow="visible")
                container.add(
                    Text(insert=("25%", "100%"),
                         text=label1,
                         transform="rotate(%f) skewX(%f)" %
                         (-degrees(plane_obverse), degrees(plane_obverse)),
                         text_anchor="middle",
                         baseline_shift="-0.75em",
                         style="font-weight:bold;"))

                if re.match(r"^[0-9]{4}-[0-9]{2}", intervals[i]):
                    label2 = month_abbr[int(str(intervals[i])[5:7])]
                    if re.match(r"^[0-9]{4}-[0-9]{2}-[0-9]{2}", intervals[i]):
                        label2 += " %i" % int(intervals[i][8:10])

                    container.add(
                        Text(insert=("25%", "100%"),
                             text=label2,
                             transform="rotate(%f) skewX(%f)" %
                             (-degrees(plane_obverse), degrees(plane_obverse)),
                             text_anchor="middle",
                             baseline_shift="-1.75em"))

                canvas.add(container)

            gridline_x += step_x_horizontal
            gridline_y -= step_y_horizontal

        # draw graphs as filled beziers
        top = step_y_vertical * 1.5
        graph_start_x = y_axis_width
        graph_start_y = margin + canvas_height

        # draw graphs in reverse order, so the bottom one is most in the
        # foreground (in case of overlap)
        for graph in reversed(list(graphs)):
            self.dataset.update_status("Rendering graph for '%s'" % graph)

            # path starting at lower left corner of graph
            area_graph = Path(fill=self.colours[self.colour_index])
            area_graph.push("M %f %f" % (graph_start_x, graph_start_y))
            previous_value = None

            graph_x = graph_start_x
            graph_y = graph_start_y
            for interval in graphs[graph]:
                # normalise value
                value = graphs[graph][interval]
                try:
                    limit = limits[graph] if normalise_values else max_limit
                    value = top * copysign(abs(value) / limit, value)
                except ZeroDivisionError:
                    value = 0

                if previous_value is None:
                    # vertical line upwards to starting value of graph
                    area_graph.push("L %f %f" %
                                    (graph_start_x, graph_start_y - value))
                elif not smooth:
                    area_graph.push("L %f %f" % (graph_x, graph_y - value))
                else:
                    # quadratic bezier from previous value to current value
                    control_left = (graph_x - (step_x_horizontal / 2),
                                    graph_y + step_y_horizontal -
                                    previous_value - (step_y_horizontal / 2))
                    control_right = (graph_x - (step_x_horizontal / 2),
                                     graph_y - value + (step_y_horizontal / 2))
                    area_graph.push("C %f %f %f %f %f %f" %
                                    (*control_left, *control_right, graph_x,
                                     graph_y - value))

                previous_value = value
                graph_x += step_x_horizontal
                graph_y -= step_y_horizontal

            # line to the bottom of the graph at the current Y position
            area_graph.push(
                "L %f %f" %
                (graph_x - step_x_horizontal, graph_y + step_y_horizontal))
            area_graph.push("Z")  # then close the Path
            canvas.add(area_graph)

            # add text labels - skewing is a bit complicated and we need a
            # "center" to translate the origins properly.
            if label_in_graph:
                insert = (graph_start_x + 5, graph_start_y - 10)
            else:
                insert = (graph_x - (step_x_horizontal) + 5,
                          graph_y + step_y_horizontal - 10)

            # we need to take the skewing into account for the translation
            offset_y = tan(plane_obverse) * insert[0]
            canvas.add(
                Text(insert=(0, 0),
                     text=graph,
                     transform="skewY(%f) translate(%f %f)" %
                     (-degrees(plane_obverse), insert[0],
                      insert[1] + offset_y)))

            # cycle colours, back to the beginning if all have been used
            self.colour_index += 1
            if self.colour_index >= len(self.colours):
                self.colour_index = 0

            graph_start_x -= step_x_vertical
            graph_start_y -= step_y_vertical

        # draw gridlines - horizontal
        gridline_x = 0
        gridline_y = margin + canvas_height - y_axis_height
        for graph in graphs:
            gridline_x += step_x_vertical
            gridline_y += step_y_vertical
            canvas.add(
                Line(start=(gridline_x, gridline_y),
                     end=(gridline_x + x_axis_width,
                          gridline_y - x_axis_height),
                     stroke="black",
                     stroke_width=1))

        # x axis
        canvas.add(
            Line(start=(y_axis_width, margin + canvas_height),
                 end=(canvas_width, margin + canvas_height - x_axis_height),
                 stroke="black",
                 stroke_width=2))

        if graph_label:
            canvas.add(
                Text(insert=((margin / 10), (margin / 2)),
                     text=graph_label,
                     style="font-size:2em;",
                     alignment_baseline="hanging"))

        # and finally save the SVG
        canvas.save(pretty=True)
        self.dataset.finish(len(graphs))
Esempio n. 37
0
def export_node(node, store, size=None):
    """Construct a SVG description for a workflow node.

    Args:
        node (NodeDef)
        store (dict of uid, def): elements definitions
        size (int, int): size of drawing in pixels

    Returns:
        (str) - SVG description of workflow node
    """
    pfs = port_font_size

    # node size
    pr = port_radius
    pspace = pr * 9
    nw = compute_node_width(node, node['name'], pspace)
    nh = label_font_size + 2 * pr + 2 * pfs + 2 + (2 * node_padding)

    # draw
    if size is None:
        size = (600, 600)

    paper = Drawing("workflow_node.svg", size, id="repr")

    lg = paper.linearGradient((0.5, 0), (0.5, 1.), id="in_port")
    lg.add_stop_color(0, color='#3333ff')
    lg.add_stop_color(1, color='#2222ff')
    paper.defs.add(lg)

    lg = paper.linearGradient((0.5, 0), (0.5, 1.), id="out_port")
    lg.add_stop_color(0, color='#ffff33')
    lg.add_stop_color(1, color='#9a9a00')
    paper.defs.add(lg)

    # body
    g = paper.add(paper.g())

    # background
    lg = paper.linearGradient((0.5, 0), (0.5, 1.))
    lg.add_stop_color(0, color='#8c8cff')
    lg.add_stop_color(1, color='#c8c8c8')
    paper.defs.add(lg)

    bg = paper.rect((-nw / 2, -nh / 2), (nw, nh),
                    rx=node_padding,
                    ry=node_padding,
                    stroke_width=1)
    bg.stroke('#808080')
    bg.fill(lg)
    g.add(bg)

    # label
    style = ('font-size: %dpx; font-family: %s; '
             'text-anchor: middle' % (label_font_size, label_font))
    frag = paper.tspan(node['name'], dy=[label_font_size // 3])
    label = paper.text("", style=style, fill='#000000')
    label.add(frag)
    g.add(label)

    # ports
    port_style = ('font-size: %dpx; ' % pfs + 'font-family: %s; ' % label_font)
    onstyle = port_style + 'text-anchor: end'
    instyle = port_style + 'text-anchor: start'
    istyle = port_style + 'text-anchor: middle'
    nb = len(node['inputs'])
    py = -nh / 2
    for i, pdef in enumerate(node['inputs']):
        px = i * pspace - pspace * (nb - 1) / 2
        pg = g.add(paper.g())
        pg.translate(px, py)
        idef = store.get(pdef['interface'], None)
        if idef is not None and 'url' in idef:
            link = pg.add(paper.a(href=idef['url'], target='_top'))
        else:
            link = pg

        port = paper.circle((0, 0), pr, stroke='#000000', stroke_width=1)
        port.fill("url(#in_port)")
        link.add(port)
        # port name
        frag = paper.tspan(pdef['name'], dy=[-2 * pr])
        label = paper.text("", style=instyle, fill='#000000')
        label.rotate(-45)
        label.add(frag)
        pg.add(label)
        # port interface
        if idef is None:
            itxt = pdef['interface']
        else:
            itxt = idef['name']
        if len(itxt) > 10:
            itxt = itxt[:7] + "..."
        frag = paper.tspan(itxt, dy=[pr + pfs])
        label = paper.text("", style=istyle, fill='#000000')
        label.add(frag)
        link.add(label)

    nb = len(node['outputs'])
    py = nh / 2
    for i, pdef in enumerate(node['outputs']):
        px = i * pspace - pspace * (nb - 1) / 2
        pg = g.add(paper.g())
        pg.translate(px, py)
        idef = store.get(pdef['interface'], None)
        if idef is not None and 'url' in idef:
            link = pg.add(paper.a(href=idef['url'], target='_top'))
        else:
            link = pg

        port = paper.circle((0, 0), pr, stroke='#000000', stroke_width=1)
        port.fill("url(#out_port)")
        link.add(port)
        # port name
        frag = paper.tspan(pdef['name'], dy=[2 * pr + pfs // 2])
        label = paper.text("", style=onstyle, fill='#000000')
        label.rotate(-45)
        label.add(frag)
        pg.add(label)
        # port interface
        if idef is None:
            itxt = pdef['interface']
        else:
            itxt = idef['name']
        if len(itxt) > 10:
            itxt = itxt[:7] + "..."
        frag = paper.tspan(itxt, dy=[-pr - 2])
        label = paper.text("", style=istyle, fill='#000000')
        label.add(frag)
        link.add(label)

    # reformat whole drawing to fit screen
    xmin = -nw / 2 - draw_padding / 10.
    xmax = +nw / 2 + draw_padding / 10.
    if len(node['inputs']) == 0:
        inames_extend = 0
    else:
        inames = [(len(pdef['name']), pdef['name']) for pdef in node['inputs']]
        inames_extend = string_size(sorted(inames)[-1][1], pfs) * 0.7 + pfs
    ymin = -nh / 2 - pr - inames_extend - draw_padding / 10.
    if len(node['outputs']) == 0:
        onames_extend = 0
    else:
        onames = [(len(pdef['name']), pdef['name'])
                  for pdef in node['outputs']]
        onames_extend = string_size(sorted(onames)[-1][1], pfs) * 0.7 + pfs
    ymax = +nh / 2 + pr + onames_extend + draw_padding / 10.

    w = float(size[0])
    h = float(size[1])
    ratio = max((xmax - xmin) / w, (ymax - ymin) / h)
    xsize = ratio * w
    ysize = ratio * h

    bb = (xmin * xsize / (xmax - xmin), ymin * ysize / (ymax - ymin), xsize,
          ysize)

    paper.viewbox(*bb)
    return paper.tostring(), bb
def diode_svg_frame(illuminated, num_across=9, num_down=8, frame=0, single_route=-1):
    filename = "diode{:03d}.svg".format(frame)
    led_symbol = "resources/Symbol_LED.svg"
    image_width = 600
    image_height = 400
    right_margin = 30
    bottom_margin = 30
    dwg = Drawing(filename,
                  size=(image_width+right_margin, image_height+bottom_margin),
                  style="background-color:white")
    # create a white background rectangle
    dwg.add(dwg.rect(size=(image_width+right_margin, image_height+bottom_margin),
                     insert=(0, 0), fill="white"))

    LED_dimensions = [106.0, 71.0]
    LED_points = [[35, 68], [35, 31], [66, 50]]
    LED_entries = [[4, 50], [103, 50]]
    aspect_ratio = LED_dimensions[1]/LED_dimensions[0]
    new_width = image_width/num_across
    new_height = new_width*aspect_ratio
    LED_scale = 0.75
    LED_offsets = [new_width*LED_scale/2, new_height*LED_scale]
    junction_radius = 0.8
    elements = []
    for i in range(0, num_across):
        x_pos = new_width*(num_across-i-1)
        if illuminated[1] >= illuminated[0]:
            incoming_wire = illuminated[1] + 1
        else:
            incoming_wire = illuminated[1]
        if i == incoming_wire:
            connection = "+"
            text_fill = "red"
        elif i == illuminated[0]:
            connection = "-"
            text_fill = "black"
        else:
            connection = "NC"
            text_fill = "gray"
        wire_label = "{} {}".format(i+1, connection)
        # the input wire title
        dwg.add(dwg.text(wire_label, insert=(x_pos+new_width-10, 10),
                             fill=text_fill))
        for j in range(0, num_down):
            y_pos = (image_height/num_down)*j
            position = [x_pos+LED_offsets[0], y_pos+LED_offsets[1]]
            scale = [LED_scale*new_width/LED_dimensions[0],
                     LED_scale*new_height/LED_dimensions[1]]
            # the led svg
            dwg.add(dwg.image(led_symbol, insert=position,
                              size=(new_width*LED_scale, new_height*LED_scale)))
            if i == illuminated[0] and j == illuminated[1] and single_route == -1:
                points = []
                for point in LED_points:
                    points.append(transform_point(point, scale, position))
                # the illuminated svg box
                dwg.add(dwg.polygon(points=points, fill="yellow"))
                line_fill = "green"
                stroke_width = 1
                insert_pos = -1
            else:
                line_fill = "black"
                insert_pos = 0
                stroke_width = 0.5
            # for each LED, we want to generate a line going from the input
            # to its output
            entry_point = transform_point(LED_entries[0], scale, position)
            if i > j:
                incoming_line_points = [[new_width*(num_across-j)-LED_offsets[0], 0],
                                    [new_width*(num_across-j)-LED_offsets[0], y_pos+20],
                                    [entry_point[0], y_pos+20], entry_point]
            elif j > i:
                incoming_line_points = [
                    [new_width * (num_across - j - 1) - LED_offsets[0], 0],
                    [new_width * (num_across - j - 1) - LED_offsets[0],
                     entry_point[1] + LED_offsets[1]],
                    [entry_point[0], entry_point[1]+LED_offsets[1]], entry_point]
            elif i == j:
                incoming_line_points = [
                    [new_width * (num_across - j - 1) - LED_offsets[0], 0],
                    [new_width * (num_across - j - 1) - LED_offsets[0], entry_point[1]], entry_point]
            else:
                incoming_line_points = []
            elements.insert(insert_pos,
                            make_junction_line(dwg, incoming_line_points,
                                               junction_radius, line_fill,
                                               stroke_width))
            # outgoing line
            exit_point = transform_point(LED_entries[1], scale, position)
            outgoing_line_points = [exit_point,
                                    [x_pos+new_width-LED_offsets[0],
                                     exit_point[1]],
                                    [x_pos+new_width-LED_offsets[0], 0]]
            elements.insert(insert_pos,
                            make_junction_line(dwg, outgoing_line_points,
                                               junction_radius, line_fill,
                                               stroke_width))
            route_points = [[new_width * (num_across - j - 1) - LED_offsets[0],
                             0]]
            for point in range(0, single_route+1):
                if point < i:
                    route_points.append([new_width * (num_across - j - 1) - LED_offsets[0], 0])

            # now create the network
            nodes = []
            for i in range(0, num_across):
                for j in range(0, num_down):
                    nodes.append(entry_point)
                    nodes.append(exit_point)
    # flatten the elements structure
    elements = sum(elements, [])
    print(elements)
    # the lines should be drawn last so that they are layered on top of all
    # other elements
    #for element in elements:
    #    dwg.add(element)
    dwg.save()
    return convert(image_width, filename)
Esempio n. 39
0
    def process(self):
        """
		This takes a 4CAT results file as input, and outputs a plain text file
		containing all post bodies as one continuous string, sanitized.
		"""

        link_regex = re.compile(r"https?://[^\s]+")
        delete_regex = re.compile(r"[^a-zA-Z)(.,\n -]")

        # settings
        strip_urls = self.parameters.get("strip-urls",
                                         self.options["strip-urls"]["default"])
        strip_symbols = self.parameters.get(
            "strip-symbols", self.options["strip-symbols"]["default"])
        sides = self.parameters.get("sides", self.options["sides"]["default"])
        self.align = self.parameters.get("align",
                                         self.options["align"]["default"])
        window = convert_to_int(
            self.parameters.get("window", self.options["window"]["default"]),
            5) + 1
        query = self.parameters.get("query", self.options["query"]["default"])
        self.limit = convert_to_int(
            self.parameters.get("limit", self.options["limit"]["default"]),
            100)

        left_branches = []
        right_branches = []

        # do some validation
        if not query.strip() or re.sub(r"\s", "", query) != query:
            self.dataset.update_status(
                "Invalid query for word tree generation. Query cannot be empty or contain whitespace."
            )
            self.dataset.finish(0)
            return

        window = min(window, self.options["window"]["max"] + 1)
        window = max(1, window)

        # find matching posts
        processed = 0
        for post in self.iterate_csv_items(self.source_file):
            processed += 1
            if processed % 500 == 0:
                self.dataset.update_status(
                    "Processing and tokenising post %i" % processed)
            body = post["body"]

            if strip_urls:
                body = link_regex.sub("", body)

            if strip_symbols:
                body = delete_regex.sub("", body)

            body = word_tokenize(body)
            positions = [
                i for i, x in enumerate(body) if x.lower() == query.lower()
            ]

            # get lists of tokens for both the left and right side of the tree
            # on the left side, all lists end with the query, on the right side,
            # they start with the query
            for position in positions:
                right_branches.append(body[position:position + window])
                left_branches.append(body[max(0, position - window):position +
                                          1])

        # Some settings for rendering the tree later
        self.step = self.fontsize * 0.6  # approximately the width of a monospace char
        self.gap = (7 * self.step)  # space for lines between nodes
        width = 1  # will be updated later

        # invert the left side of the tree (because that's the way we want the
        # branching to work for that side)
        # we'll visually invert the nodes in the tree again later
        left_branches = [list(reversed(branch)) for branch in left_branches]

        # first create vertical slices of tokens per level
        self.dataset.update_status("Generating token tree from posts")
        levels_right = [{} for i in range(0, window)]
        levels_left = [{} for i in range(0, window)]
        tokens_left = []
        tokens_right = []

        # for each "level" (each branching point representing a level), turn
        # tokens into nodes, record the max amount of occurences for any
        # token in that level, and keep track of what nodes are in which level.
        # The latter is needed because a token may occur multiple times, at
        # different points in the graph. Do this for both the left and right
        # side of the tree.
        for i in range(0, window):
            for branch in right_branches:
                if i >= len(branch):
                    continue

                token = branch[i].lower()
                if token not in levels_right[i]:
                    parent = levels_right[i - 1][branch[
                        i - 1].lower()] if i > 0 else None
                    levels_right[i][token] = Node(token,
                                                  parent=parent,
                                                  occurrences=1,
                                                  is_top_root=(parent is None))
                    tokens_right.append(levels_right[i][token])
                else:
                    levels_right[i][token].occurrences += 1

                occurrences = levels_right[i][token].occurrences
                self.max_occurrences[i] = max(
                    occurrences, self.max_occurrences[i]
                ) if i in self.max_occurrences else occurrences

            for branch in left_branches:
                if i >= len(branch):
                    continue

                token = branch[i].lower()
                if token not in levels_left[i]:
                    parent = levels_left[i - 1][branch[
                        i - 1].lower()] if i > 0 else None
                    levels_left[i][token] = Node(token,
                                                 parent=parent,
                                                 occurrences=1,
                                                 is_top_root=(parent is None))
                    tokens_left.append(levels_left[i][token])
                else:
                    levels_left[i][token].occurrences += 1

                occurrences = levels_left[i][token].occurrences
                self.max_occurrences[i] = max(
                    occurrences, self.max_occurrences[i]
                ) if i in self.max_occurrences else occurrences

        # nodes that have no siblings can be merged with their parents, else
        # the graph becomes unnecessarily large with lots of single-word nodes
        # connected to single-word nodes. additionally, we want the nodes with
        # the most branches to be sorted to the top, and then only retain the
        # most interesting (i.e. most-occurring) branches
        self.dataset.update_status("Merging and sorting tree nodes")
        for token in tokens_left:
            self.merge_upwards(token)
            self.sort_node(token)
            self.limit_subtree(token)

        for token in tokens_right:
            self.merge_upwards(token)
            self.sort_node(token)
            self.limit_subtree(token)

        # somewhat annoyingly, anytree does not simply delete nodes detached
        # from the tree in the previous steps, but makes them root nodes. We
        # don't need these root nodes (we only need the original root), so the
        # next step is to remove all root nodes that are not the main root.
        # We cannot modify a list in-place, so make a new list with the
        # relevant nodes
        level_sizes = {}
        filtered_tokens_right = []
        for token in tokens_right:
            if token.is_root and not token.is_top_root:
                continue

            filtered_tokens_right.append(token)

        filtered_tokens_left = []
        for token in tokens_left:
            if token.is_root and not token.is_top_root:
                continue

            filtered_tokens_left.append(token)

        # now we know which nodes are left, and can therefore determine how
        # large the canvas needs to be - this is based on the max number of
        # branches found on any level of the tree, in other words, the number
        # of "terminal nodes"
        height_left = self.whitespace * self.fontsize * max([
            self.max_breadth(node)
            for node in filtered_tokens_left if node.is_top_root
        ])
        height_right = self.whitespace * self.fontsize * max([
            self.max_breadth(node)
            for node in filtered_tokens_right if node.is_top_root
        ])
        height = max(height_left, height_right)

        canvas = Drawing(str(self.dataset.get_results_path()),
                         size=(width, height),
                         style="font-family:monospace;font-size:%ipx" %
                         self.fontsize)

        # the nodes on the left side of the graph now have the wrong word order,
        # because we reversed them earlier to generate the correct tree
        # hierarchy - now reverse the node labels so they are proper language
        # again
        for token in tokens_left:
            self.invert_node_labels(token)

        wrapper = SVG(overflow="visible")

        self.dataset.update_status("Rendering tree to SVG file")
        if sides != "right":
            wrapper = self.render(wrapper, [
                token for token in filtered_tokens_left
                if token.is_root and token.children
            ],
                                  height=height,
                                  side=self.SIDE_LEFT)

        if sides != "left":
            wrapper = self.render(wrapper, [
                token for token in filtered_tokens_right
                if token.is_root and token.children
            ],
                                  height=height,
                                  side=self.SIDE_RIGHT)

        # things may have been rendered outside the canvas, in which case we
        # need to readjust the SVG properties
        wrapper.update({"x": 0 if self.x_min >= 0 else self.x_min * -1})
        canvas.update({"width": (self.x_max - self.x_min)})

        canvas.add(wrapper)
        canvas.save(pretty=True)

        self.dataset.update_status("Finished")
        self.dataset.finish(len(tokens_left) + len(tokens_right))
Esempio n. 40
0
    def plot(self, svg: Drawing) -> None:

        recolor: Optional[str] = None

        if isinstance(self.color, list):
            linear_gradient: LinearGradient = svg.linearGradient(
                self.map_((0, self.max_y)),
                self.map_((0, 1)),
                gradientUnits="userSpaceOnUse",
            )
            for index, color in enumerate(self.color):
                linear_gradient.add_stop_color(
                    index / (len(self.color) - 1), color.hex
                )

            gradient: LinearGradient = svg.defs.add(linear_gradient)
            recolor = gradient.get_funciri()

        if isinstance(self.color, Color):
            recolor = self.color.hex

        svg.add(
            svg.rect(
                insert=(0, 0),
                size=("100%", "100%"),
                rx=None,
                ry=None,
                fill=self.background_color.hex,
            )
        )
        self.draw_grid(svg)
        last_text_y = 0

        for xs, ys, color, title in self.data:

            if recolor:
                color = recolor

            assert len(xs) == len(ys)

            xs_second: list[float] = [
                (x - self.min_x).total_seconds() for x in xs
            ]
            points = []

            for index, x in enumerate(xs_second):
                y = ys[index]
                mapped: np.ndarray = map_array(
                    np.array((x, y)),
                    np.array((self.min_x_second, self.max_y)),
                    np.array((self.max_x_second, self.min_y)),
                    self.canvas.workspace[0],
                    self.canvas.workspace[1],
                )
                points.append(mapped)
            previous_point: Optional[np.ndarray] = None

            for point in points:
                if previous_point is not None:
                    line: Line = svg.line(
                        (previous_point[0], previous_point[1]),
                        (point[0], point[1]),
                        stroke=self.background_color.hex,
                        stroke_width=6,
                    )
                    svg.add(line)
                    line: Line = svg.line(
                        (previous_point[0], previous_point[1]),
                        (point[0], point[1]),
                        stroke=color,
                        stroke_width=2,
                    )
                    svg.add(line)
                previous_point = point

            for point in points:
                svg.add(
                    svg.circle(
                        (point[0], point[1]),
                        5.5,
                        fill=self.background_color.hex,
                    )
                )
                svg.add(svg.circle((point[0], point[1]), 3.5, fill=color))

            title: str
            text_y = max(last_text_y + 20, point[1] + 6)
            self.text(svg, (point[0] + 15, text_y), title.upper(), color)
            last_text_y = text_y

        with Path(svg.filename).open("w+") as output_file:
            svg.write(output_file)
Esempio n. 41
0
from svgwrite import Drawing
from xml.etree import ElementTree
from pathlib import Path

from cerebellum_value_map.shape import PathShape
from cerebellum_value_map.path_code import Move, Line

dirname = Path('results')
dirname.mkdir(exist_ok=True)
shape = PathShape(Move([100, 100]), Line([120, 140]), Line([160, 100]))
drawing_orig = Drawing(dirname.joinpath('shape.svg'),
                       size=(200, 200),
                       stroke='black',
                       stroke_width=1)
drawing_orig.add(shape.get_svg())
drawing_orig.save()


def test_flip():
    flip = shape.flip(90)
    xml = ElementTree.tostring(flip.get_svg().get_xml()).decode()
    assert xml == ('<path d="M 80.000, 100.000 L 60.000, 140.000 '
                   'L 20.000, 100.000 Z" />')
    drawing_flip = Drawing(dirname.joinpath('flip.svg'),
                           size=(200, 200),
                           stroke='black',
                           stroke_width=1)
    drawing_flip.add(flip.get_svg())
    drawing_flip.save()
Esempio n. 42
0
	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))
Esempio n. 43
0
class Figure(object):
    def __init__(self):
        self.elements = []
        self.extra = []

        self.ticks = []

        self.svg = Drawing()

    def add(self, element, xy):

        self.elements.append(element)
        self.extra.append(xy)

        return element

    def add_genome(self, xy, name, length):

        genome = self.add(Genome(name, end=length), xy)

        return genome

    def add_genome_from_file(self, xy, file):

        file_format = file.split(".")[-1]

        if file_format in "gb|genbank":

            for record in SeqIO.parse(file, "genbank"):

                genome = self.add(
                    Genome(
                        name=record.id,
                        end=len(record.seq),
                    ), xy)

                for feature in record.features:
                    if feature.type == "CDS":
                        name = feature.qualifiers["locus_tag"][0]
                        genome.add_feature(
                            name=name,
                            start=feature.location.start,
                            end=feature.location.end,
                            strand=feature.location.strand,
                        )

                break

            return genome

    def add_ticks(self, xy, ticks, labels):

        tick = Axis(ticks, labels)
        self.elements.append(tick)
        self.extra.append(xy)

        return tick

    def homology(self, name, color):

        h**o = Homology(name, color)
        self.elements.append(h**o)
        self.extra.append([0, 0])

        return h**o

    def save(self, filename="out.svg"):

        scale = 1200.0 / max([
            i.length - i.break_length
            for i in self.elements if isinstance(i, Genome)
        ])
        genomes = []

        for i, e in enumerate(self.elements):
            if isinstance(e, Genome):
                genomes.append(
                    e.plot(scale=scale,
                           x=self.extra[i][0],
                           y=self.extra[i][1],
                           stroke="black",
                           stroke_width=2))
                continue

            self.svg.add(
                e.plot(scale=scale,
                       x=self.extra[i][0],
                       y=self.extra[i][1],
                       stroke="black",
                       stroke_width=2))

        for g in genomes:
            self.svg.add(g)

        self.svg.saveas(filename, pretty=True)
Esempio n. 44
0
# create svg
dwg = Drawing("test.svg", size=(width,height))
dwg.defs.add(dwg.style(css))

data = read_csv(indata)
labels = data.iloc[:,0]
cols = data.iloc[:,1:]

ncols = cols.shape[1]
nlines = ncols - 1
colspace = h - nlines*200
colwidth = colspace / float(ncols)
collocs = (arange(ncols) + 1)*colwidth

# pad
g = dwg.add(dwg.g(transform="translate(%i,%i)" % (padding,padding)))
title = g.add(dwg.g())

for i in range(ncols):
    if i==0:
        title.add(dwg.text(cols.columns[i], insert=(collocs[i],0), text_anchor='end', font_size='%ipx' % titlefont))
    elif i==ncols-1:
        title.add(dwg.text(cols.columns[i], insert=(collocs[i],0), font_size='%ipx' % titlefont))

g = g.add(dwg.g(transform="translate(0,%i)" % (titlefont+fontsize)))
# loop over and add labels
vmin = min(cols.values)
vmax = max(cols.values)

def scale(val, src=(vmin, vmax), dst=(0, h)):
    return ((float(val) - src[0]) / (src[1]-src[0])) * (dst[1]-dst[0]) + dst[0]