def drawCircle(self): colorList = self.dataSourceTableWithoutXcolumn.rowsColors xCenter = self.xCenter yCenter = self.yCenter # ======================================================================== x = self.r / (len(self.dataSourceTableWithoutXcolumn.columns)) r = self.r + x # ================================================================ for column in self.dataSourceTableWithoutXcolumn.columns: if column.columnType == enums.ColumnDataType.Measures.value: if (column != self.xColumn): r -= (x) oldEndangle = 0 endAngle = 0 length = 0 b = 0 for cell, cell2, i in zip( self.xColumn.cells, column.cells, range(0, len(self.xColumn.cells))): if (i != 0): length += self.heightView / len(self.xColumn.cells) startangle = oldEndangle endAngle += self.getAngle(double(cell2.value), column) oldEndangle = endAngle radiansconversion = np.pi / 180. xstartpoint = xCenter + r * np.cos( startangle * radiansconversion) ystartpoint = yCenter - r * np.sin( startangle * radiansconversion) xendpoint = xCenter + r * np.cos( endAngle * radiansconversion) yendpoint = yCenter - r * np.sin( endAngle * radiansconversion) large_arc_flag = 0 if endAngle - startangle > 180: large_arc_flag = 1 M = ("M %s %s" % (xstartpoint, ystartpoint)) a = ("A %s %s 0 %s 0 %s %s" % (r, r, large_arc_flag, xendpoint, yendpoint)) L = ("L %s %s" % (xCenter, yCenter)) p = draw.Path(stroke_width=self.stroke, stroke="white", fill=colorList[i - 1], fill_opacity=1, d=M + a + L, Class=str(self.Index)) self.metaData.append( str(self.xColumn.name + " : " + str(cell.value) + "->" + column.name + " : " + str( self.percentageOfValue( cell2.value, column)) + "%")) self.Index += 1 p.Z() self.d.append(p) if (b == 0): text = str(cell.value) c = draw.Circle(self.widthView - self.widthView / 4.5, length, self.stroke * 2, fill=colorList[i - 1], fill_opacity=1, stroke_width=0) t = draw.Text( text=str(text), fontSize=self.stroke * 4, style="font-size :" + str(self.stroke * 4), x=self.widthView - self.widthView / 6, y=length - length / 50) if self.animation: t.appendAnim( draw.Animate( 'x', str((length / 150) - 0.2) + 's', from_or_values=0, to=self.widthView - self.widthView / 6, repeatCount='1')) c.appendAnim( draw.Animate('cx', str(length / 150) + 's', from_or_values=0, to=self.widthView - self.widthView / 4.5, repeatCount='1')) c.appendAnim( draw.Animate( 'r', '3.2s', from_or_values=self.stroke * 2 * 5, to=abs(self.stroke * 2), repeatCount='1')) self.d.append(t) self.d.append(c) b += 1
draw.Lines(-80, -45, 70, -49, 95, 49, -90, 40, close=False, fill='#eeee00', stroke='black')) d.append(draw.Rectangle(0, 0, 40, 50, fill='#1248ff')) d.append(draw.Circle(-40, -10, 30, fill='red', stroke_width=2, stroke='black')) p = draw.Path(stroke_width=2, stroke='green', fill='black', fill_opacity=0.5) p.M(-30, 5) # Start path at point (-30, 5) p.l(60, 30) # Draw line to (60, 30) p.h(-70) # Draw horizontal line to x=-70 p.Z() # Draw line to start d.append(p) d.append( draw.ArcLine(60, -20, 20, 60, 270, stroke='red', stroke_width=5, fill='red',
def draw_bloch_sphere(d, inner_proj=euclid3d.identity(3), label='', axis=None, rot_proj=None, rot_deg=180, outer_labels=(), inner_labels=(), extra_opacity=1, inner_opacity=1, background='white'): spin = euclid3d.rotation(3, 0, 2, 2 * np.pi / 16 / 2 * 1.001) tilt = euclid3d.rotation(3, 1, 2, np.pi / 8) trans = tilt @ spin @ euclid3d.axis_swap((1, 2, 0)) proj = euclid3d.perspective3d(np.pi / 8, view_size=4) @ trans zx = euclid3d.axis_swap((2, 0, 1)) xy = euclid3d.identity(3) yz = euclid3d.axis_swap((1, 2, 0)) proj_zx = proj @ zx proj_xy = proj @ xy proj_yz = proj @ yz if background: d.append(draw.Rectangle(-100, -100, 200, 200, fill=background)) def draw_band(proj, trans, r_outer=1, r_inner=0.9, color='black', z_mul=1, opacity=1, divs=4, d=d, **kwargs): color = (color * divs)[:divs] if isinstance(color, list) else [color] * divs points = np.array([[-1, -1, 1, 1], [-1, 1, 1, -1]]).T sqr12 = 0.5**0.5 overlap = np.pi / 500 * (divs != 4) start_end_points = [ np.array([[ np.cos(pr - 2 * np.pi / divs - overlap), np.sin(pr - 2 * np.pi / divs - overlap) ], [np.cos(pr + overlap), np.sin(pr + overlap)], [np.cos(pr - np.pi / divs), np.sin(pr - np.pi / divs)]]) for pr in np.linspace(0, 2 * np.pi, num=divs, endpoint=False) ] for i in range(divs): p = draw.Path(fill=color[i], stroke='none', stroke_width=0.002, **kwargs, opacity=opacity) z = trans.project_point( (r_inner + r_outer) / 2 * start_end_points[i][2])[2] e = shapes.EllipseArc.fromBoundingQuad( *proj.project_list(points * r_outer)[:, :2].flatten(), *proj.project_list(start_end_points[i] * r_outer)[:, :2].flatten(), ) if e: e.drawToPath(p) if r_inner > 0: e = shapes.EllipseArc.fromBoundingQuad( *proj.project_list(points * r_inner)[:, :2].flatten(), *proj.project_list(start_end_points[i] * r_inner)[:, :2].flatten(), ) if e: e.reversed().drawToPath(p, includeL=True) p.Z() d.append(p, z=z * z_mul) if False: d.draw(shapes.EllipseArc.fromBoundingQuad( *proj.project_list( (r_outer + r_inner) / 2 * points)[:, :2].flatten(), *proj.project_list((r_outer + r_inner) / 2 * start_end_points[i])[:, :2].flatten(), ), fill='none', stroke_width=0.02, stroke=color[i], **kwargs, z=z * z_mul) xycolors = ['#56e', '#239', '#56e', '#56e'] yzcolors = ['#e1e144', '#909022', '#e1e144', '#e1e144'] zxcolors = ['#9e2', '#6a1', '#9e2', '#9e2'] draw_band(proj_xy, trans @ xy, 1, 0.925, z_mul=10, color=xycolors) draw_band(proj_yz, trans @ yz, 1, 0.925, z_mul=10, color=yzcolors) draw_band(proj_zx, trans @ zx, 1, 0.925, z_mul=10, color=zxcolors) # Inner g = draw.Group(opacity=inner_opacity) z_center = trans.project_point((0, 0, 0))[2] d.append(g, z=z_center) inner_xy = proj @ inner_proj @ xy # Darker colors: #34b, #a8a833, #7b2 draw_band(proj @ inner_proj @ xy, trans @ inner_proj @ xy, 0.8, 0.7, color=xycolors, d=g) draw_band(proj @ inner_proj @ yz, trans @ inner_proj @ yz, 0.8, 0.7, color=yzcolors, divs=4, d=g) draw_band(proj @ inner_proj @ zx, trans @ inner_proj @ zx, 0.8, 0.7, color=zxcolors, divs=8 // 2, d=g) elevation_lines = False if elevation_lines: for elevation in (*np.linspace(0, np.pi / 2, 4, True)[1:-1], *np.linspace(-np.pi / 2, 0, 3, False)[1:]): y = 0.75 * np.sin(elevation) r = 0.75 * np.cos(elevation) draw_band(proj @ inner_proj @ xy @ euclid3d.translation((0, 0, y)), trans @ inner_proj @ xy @ euclid3d.translation( (0, 0, y)), r_outer=r - 0.01, r_inner=r + 0.01, color='#bbb', opacity=1, d=g) arrow = draw.Marker(-0.1, -0.5, 0.9, 0.5, scale=4, orient='auto') arrow.append( draw.Lines(-0.1, -0.5, -0.1, 0.5, 0.9, 0, fill='black', close=True)) g.append(draw.Line(*inner_xy.p2(-0.65, 0, 0), *inner_xy.p2(0.6, 0, 0), stroke='black', stroke_width=0.015, marker_end=arrow), z=z_center) g.append(draw.Line(*inner_xy.p2(0, -0.65, 0), *inner_xy.p2(0, 0.6, 0), stroke='black', stroke_width=0.015, marker_end=arrow), z=z_center) g.append(draw.Line(*inner_xy.p2(0, 0, -0.65), *inner_xy.p2(0, 0, 0.6), stroke='black', stroke_width=0.015, marker_end=arrow), z=z_center) for pt, (x_off, y_off), elem in inner_labels: x, y = (proj @ inner_proj).p2(*pt) g.append(draw.Use(elem, x + x_off, y + y_off), z=10000) # Outer arrows and text arrow = draw.Marker(-0.1, -0.5, 0.9, 0.5, scale=4, orient='auto') arrow.append( draw.Lines(-0.1, -0.5, -0.1, 0.5, 0.9, 0, fill='black', close=True)) d.append(draw.Line(*proj_xy.p2(1, 0, 0), *proj_xy.p2(1.2, 0, 0), stroke='black', stroke_width=0.02, marker_end=arrow), z=100) d.append(draw.Line(*proj_xy.p2(0, 1, 0), *proj_xy.p2(0, 1.2, 0), stroke='black', stroke_width=0.02, marker_end=arrow), z=100) d.append(draw.Line(*proj_xy.p2(0, 0, 1), *proj_xy.p2(0, 0, 1.2), stroke='black', stroke_width=0.02, marker_end=arrow), z=100) d.append( draw.Line(*proj_xy.p2(-1, 0, 0), *proj_xy.p2(-1.2, 0, 0), stroke='black', stroke_width=0.02)) d.append( draw.Line(*proj_xy.p2(0, -1, 0), *proj_xy.p2(0, -1.2, 0), stroke='black', stroke_width=0.02)) d.append( draw.Line(*proj_xy.p2(0, 0, -1), *proj_xy.p2(0, 0, -1.2), stroke='black', stroke_width=0.02)) d.append(draw.Text(['X'], 0.2, *proj_xy.p2(1.7, 0, 0), center=True, fill='black'), z=100) d.append(draw.Text(['Y'], 0.2, *proj_xy.p2(0, 1.35, 0), center=True, fill='black'), z=100) d.append(draw.Text(['Z'], 0.2, *proj_xy.p2(0, 0, 1.4), center=True, fill='black'), z=100) for pt, (x_off, y_off), elem in outer_labels: x, y = proj.p2(*pt) d.append(draw.Use(elem, x + x_off, y + y_off), z=10000) # Extra annotations #label='', axis=None, rot_proj=None if label: d.append( draw.Text([label], 0.4, -0.6, 1.2, center=True, fill='#c00', text_anchor='end', opacity=extra_opacity)) if axis: g = draw.Group(opacity=extra_opacity) axis = np.array(axis, dtype=float) axis_len = 1.18 axis /= np.linalg.norm(axis) arrow = draw.Marker(-0.1, -0.5, 0.9, 0.5, scale=3, orient='auto') arrow.append( draw.Lines(-0.1, -0.5, -0.1, 0.5, 0.9, 0, fill='#e00', close=True)) z = 100 #10 * proj_xy.project_point(axis*1)[2] g.append( draw.Line(*proj_xy.p2(0, 0, 0), *proj_xy.p2(*axis * axis_len), stroke='#e00', stroke_width=0.04, marker_end=arrow)) d.append(g, z=z) if rot_proj is not None: rot_proj = inner_proj @ rot_proj r_inner, r_outer = 0.1, 0.16 points = np.array([[-1, -1, 1, 1], [-1, 1, 1, -1]]).T start_end_points = np.array([[1, 0], [-1, 0], [0, 1]]) p = draw.Path(fill='orange', fill_rule='nonzero', opacity=extra_opacity) z = 9 * (trans @ rot_proj).project_point(start_end_points[2])[2] e = shapes.EllipseArc.fromBoundingQuad( *(proj @ rot_proj).project_list(points * r_outer)[:, :2].flatten(), *(proj @ rot_proj).project_list(start_end_points * r_outer)[:, :2].flatten(), ) if e: e.reversed().drawToPath(p) e = shapes.EllipseArc.fromBoundingQuad( *(proj @ rot_proj).project_list(points * r_inner)[:, :2].flatten(), *(proj @ rot_proj).project_list(start_end_points * r_inner)[:, :2].flatten(), ) if e: e.drawToPath(p, includeL=True) sa = 2.5 * (r_outer - r_inner) xa = -(r_inner + r_outer) / 2 p.L(*(proj @ rot_proj).p2(xa, 0.3 * sa)) p.L(*(proj @ rot_proj).p2(xa + 0.5 * sa, 0.3 * sa)) p.L(*(proj @ rot_proj).p2(xa, -0.7 * sa)) p.L(*(proj @ rot_proj).p2(xa - 0.5 * sa, 0.3 * sa)) p.L(*(proj @ rot_proj).p2(xa, 0.3 * sa)) p.Z() d.append(p, z=z) return d
def draw_band(proj, trans, r_outer=1, r_inner=0.9, color='black', z_mul=1, opacity=1, divs=4, d=d, **kwargs): color = (color * divs)[:divs] if isinstance(color, list) else [color] * divs points = np.array([[-1, -1, 1, 1], [-1, 1, 1, -1]]).T sqr12 = 0.5**0.5 overlap = np.pi / 500 * (divs != 4) start_end_points = [ np.array([[ np.cos(pr - 2 * np.pi / divs - overlap), np.sin(pr - 2 * np.pi / divs - overlap) ], [np.cos(pr + overlap), np.sin(pr + overlap)], [np.cos(pr - np.pi / divs), np.sin(pr - np.pi / divs)]]) for pr in np.linspace(0, 2 * np.pi, num=divs, endpoint=False) ] for i in range(divs): p = draw.Path(fill=color[i], stroke='none', stroke_width=0.002, **kwargs, opacity=opacity) z = trans.project_point( (r_inner + r_outer) / 2 * start_end_points[i][2])[2] e = shapes.EllipseArc.fromBoundingQuad( *proj.project_list(points * r_outer)[:, :2].flatten(), *proj.project_list(start_end_points[i] * r_outer)[:, :2].flatten(), ) if e: e.drawToPath(p) if r_inner > 0: e = shapes.EllipseArc.fromBoundingQuad( *proj.project_list(points * r_inner)[:, :2].flatten(), *proj.project_list(start_end_points[i] * r_inner)[:, :2].flatten(), ) if e: e.reversed().drawToPath(p, includeL=True) p.Z() d.append(p, z=z * z_mul) if False: d.draw(shapes.EllipseArc.fromBoundingQuad( *proj.project_list( (r_outer + r_inner) / 2 * points)[:, :2].flatten(), *proj.project_list((r_outer + r_inner) / 2 * start_end_points[i])[:, :2].flatten(), ), fill='none', stroke_width=0.02, stroke=color[i], **kwargs, z=z * z_mul)
def toSVG(read_path, path, path2): pth = read_path.split("/") for i in pth[-1]: if i == '.': dotindx = pth[-1].index(".", 0) pth[-1] = pth[-1][0:dotindx] ############ #################### # parsing the def file def_parser = DefParser(read_path) def_parser.parse() macro = "" for key, val in def_parser.components.comp_dict.items(): x = str(val).split() macro = macro + " " + x[3] + " " + str(x[5]).strip("[,") + " " + str( x[6]).strip("]") + " " + str(x[7]) nets = [] for key, val in def_parser.nets.net_dict.items( ): # extracting nets information and putting in list nets += str(val).split() # print(nets) def_scale = def_parser.scale # scalling the def # print("DEF scale: ",def_scale) MACRO = macro.split() # DEF INFO CARRIER # print(MACRO) # getting the die area of the circuit z = def_parser.diearea pos = re.split('[, ()]', str(z)) # diearea coordinates in string x1 = pos[1] # diearea coordinates in string x2 = pos[3] # diearea coordinates in string x3 = pos[7] # diearea coordinates in string x4 = pos[9] dx0 = int(x1) # diearea coordinates in int dy0 = int(x2) # diearea coordinates in int dx1 = int(x3) # diearea coordinates in int dy1 = int(x4) # diearea coordinates in int width = int(x3) - int( x1) # getting the width of the are lower left - upper right height = int(x4) - int( x2) # getting the hihgt of the are lower left - upper right clip = draw.ClipPath() d = draw.Drawing(width, height, origin=(0, -height), id="svgContainer") # drawing of diearea d.append( draw.Rectangle( dx0, -(height + dy0), width, height, fill='#D8FEEA', fill_opacity=0.4, )) # parsing the lef file lef_parser = LefParser(path) # getting the lef file path lef_parser.parse() x = "" for i in lef: # putting lef infrmation in list x = x + i + " " lef_info = x.split() # print(lef_info) k = 0 # g = "" counter = 0 for i in range(0, len(MACRO)): # for loop for drawing of components if k < len(MACRO): # if we still have macro we keep drawing g = draw.Group() for j in range( 0, len(lef_info), 2 ): # loop on th size of the block in the LEF file on details of a macro if MACRO[k] == lef_info[j]: # Matching macros from LEF / DEF counter = counter + 1 # print(MACRO[k]) opacity = 0.6 # opacity of all rectangles, opacity only changes if OBS xplacement = float( MACRO[k + 1] ) # extracting and storing placement and orientation of macro from DEF yplacement = float(MACRO[k + 2]) orientation = MACRO[k + 3] endindx = lef_info.index("END", j) # Extracting macros's details for m in range(j, endindx): if (lef_info[m] == "Size"): swidth = float( lef_info[m + 1]) * 100 # width size of macro sheight = float(lef_info[ m + 2]) * 100 # height width size of macrp d.append( draw.Rectangle(xplacement - dx0, -(height - (yplacement - dy0)), swidth, sheight, fill='#a877f2', stroke='#412f5c', stroke_width=10, fill_opacity=0.2, class_="cell", name=MACRO[k], id=MACRO[k] + "_c" + str(counter))) elif (lef_info[m] == "Layer:" or lef_info[m] == "Layer" or lef_info[m] == "LAYER"): # Layer met = lef_info[m + 1] if (lef_info[m + 1] == "metal1"): # COLOR CODE For each metal color = "#7D5AB1" elif (lef_info[m + 1] == "metal2"): # COLOR CODE For each meta2 color = "#8C8E8E" elif (lef_info[m + 1] == "metal3"): # COLOR CODE For each meta3 color = "#FF839D" elif (lef_info[m + 1] == "metal4"): # COLOR CODE For each meta4 color = "#83C9FF" elif (lef_info[m + 1] == "via1"): # COLOR CODE For each via1 color = "#83FFC3" elif (lef_info[m + 1] == "via2"): # COLOR CODE For each via2 color = "#FFD683" elif (lef_info[m + 1] == "via3"): # COLOR CODE For each via3 color = "#83FFE1" elif ((lef_info[m] == "PIN:")): # metal info met = lef_info[m + 1] # pin info pin = lef_info[m + 1] # PIN NAME elif ((lef_info[m] == "OBS" )): # setting different opacity for rectangles met = lef_info[m + 1] opacity = 0.6 elif ( (lef_info[m] == "RECT" )): # extracting dimensions of rectangles in LEF # x left x0 = float(lef_info[m + 1]) * 100 # y left y0 = float(lef_info[m + 2]) * 100 # x right x01 = float(lef_info[m + 3]) * 100 # y right y01 = float(lef_info[m + 4]) * 100 # width of the rects rwidth = x01 - x0 # width of rectangle # height of the rects rheight = y01 - y0 # height of rectangle if (orientation == "N"): g.append( draw.Rectangle(xplacement - dx0 + x0, -(height - (yplacement - dy0 + y0)), rwidth, rheight, fill=color, fill_opacity=opacity, class_=met)) g.append( draw.Text(pin, 20, xplacement - dx0 + x0, -(height - (yplacement - dy0 + y0)), centre='origin', class_=met)) elif (orientation == "FN"): FNx = x0 + ((swidth / 2 - x0) * 2) - rwidth g.append( draw.Rectangle(xplacement - dx0 + FNx, -(height - (yplacement - dy0 + y0)), rwidth, rheight, fill=color, fill_opacity=opacity, class_=met)) g.append( draw.Text(pin, 20, xplacement - dx0 + FNx, -(height - (yplacement - dy0 + y0)), centre='origin', class_=met)) elif (orientation == "FS"): FSy = y0 + ((sheight / 2 - y0) * 2) - rheight g.append( draw.Rectangle(xplacement - dx0 + x0, -(height - (yplacement - dy0 + FSy)), rwidth, rheight, fill=color, fill_opacity=opacity, class_=met)) g.append( draw.Text(pin, 20, xplacement - dx0 + x0, -(height - (yplacement - dy0 + FSy)), centre='origin', class_=met)) elif (orientation == "S"): Sx = x0 + ((swidth / 2 - x0) * 2) - rwidth Sy = y0 + ((sheight / 2 - y0) * 2) - rheight g.append( draw.Rectangle(xplacement - dx0 + Sx, -(height - (yplacement - dy0 + Sy)), rwidth, rheight, fill=color, fill_opacity=opacity, Class=met)) g.append( draw.Text(pin, 35, xplacement - dx0 + Sx, -(height - (yplacement - dy0 + Sy)), centre='origin', class_=met)) d.append(g) k = k + 4 nx = "" ny = "" for i in range(0, len(nets)): # for loop to draw vias if (nets[i] == "M2_M1" or nets[i] == "M3_M2" or nets[i] == "M4_M3"): ny = nets[i - 1] nx = nets[i - 2] nx = int(nx.strip("[],")) ny = int(ny.strip("[],")) opacity = 0.5 NETstartindx = lef_info.index(nets[i]) if (nets[i] == "M2_M1" or nets[i] == "M3_M2"): NETendindx = lef_info.index("VIA", NETstartindx) elif (nets[i] == "M4_M3"): NETendindx = lef_info.index("Macro", NETstartindx) for n in range(NETstartindx, NETendindx): if (lef_info[n] == "LAYER"): # Layer if (lef_info[n + 1] == "metal1"): color = "#7D5AB1" # COLOR CODE For each metal elif (lef_info[n + 1] == "metal2"): # COLOR CODE For each meta2 color = "#8C8E8E" elif (lef_info[n + 1] == "metal3"): # COLOR CODE For each meta3 color = "#FF839D" elif (lef_info[n + 1] == "metal4"): # COLOR CODE For each meta4 color = "#83C9FF" elif (lef_info[n + 1] == "via1"): # COLOR CODE For each via1 color = "#83FFC3" elif (lef_info[n + 1] == "via2"): # COLOR CODE For each via2 color = "#FFD683" elif (lef_info[n + 1] == "via3"): # COLOR CODE For each via3 color = "#83FFE1" elif ((lef_info[n] == "RECT" )): # extracting dimensions of rectangles in # x left x0 = float(lef_info[n + 1]) * 100 # y left y0 = float(lef_info[n + 2]) * 100 # xright x01 = float(lef_info[n + 3]) * 100 # y right y01 = float(lef_info[n + 4]) * 100 rwidth = x01 - x0 # width of rectangle rheight = y01 - y0 # height of rectangle d.append( draw.Rectangle(nx - dx0 + x0, -(height - (ny - dy0 + y0)), rwidth, rheight, fill=color, fill_opacity=opacity, class_=lef_info[n + 1])) i = 0 RouteEnd = 0 RouteStart = 0 print(nets) for i in range(0, len(nets)): # checking that am at metal components if (nets[i] == "NET_DEF:"): net_ident = nets[i + 1] #g = draw.Group(fill="Black", Class="net", id=net_ident) net_ident = net_ident.replace('<', '') net_ident = net_ident.replace('>', '') g = draw.Group() if (nets[i] == "metal1" or nets[i] == "metal2" or nets[i] == "metal3" or nets[i] == "metal4" or nets[i] == "via1" or nets[i] == "via2" or nets[i] == "via3"): RouteStart = i if (nets[i] == "metal1"): met = nets[i] color = "#7D5AB1" # COLOR CODE For each metal strokewidth = 0.6 * 100 # width of metal elif (nets[i] == "metal2"): # COLOR CODE For each meta2 met = nets[i] color = "#8C8E8E" # width of meta2 strokewidth = 0.6 * 100 elif (nets[i] == "metal3"): met = nets[i] # COLOR CODE For each meta3 color = "#FF839D" # width of meta3 strokewidth = 0.6 * 100 elif (nets[i] == "metal4"): met = nets[i] # COLOR CODE For each meta4 color = "#83C9FF" # width of meta4 strokewidth = 1.2 * 100 elif (nets[i] == "via1"): # COLOR CODE For each via1 met = nets[i] color = "#83FFC3" strokewidth = 0.6 * 100 elif (nets[i] == "via2"): # COLOR CODE For each via2 met = nets[i] color = "#FFD683" strokewidth = 0.6 * 100 elif (nets[i] == "via3"): met = nets[i] # COLOR CODE For each via3 color = "#83FFE1" strokewidth = 0.6 * 100 # print(RouteStart) for j in range(i + 1, len(nets)): if (nets[j] == "M2_M1" or nets[j] == "M3_M2" or nets[j] == "M4_M3" or nets[j] == "metal1" or nets[j] == "metal2" or nets[j] == "metal3" or nets[j] == "metal4" or nets[j] == ";"): RouteEnd = j # print(RouteEnd) break no_of_pairs = int((RouteEnd - RouteStart - 1) / 2) # number of pairs of coordinates (x,y) temp = RouteStart if ( no_of_pairs > 1 ): # if number of pairs=1 , then only via and it's already drawn in previous loop for k in range( 0, no_of_pairs - 1 ): # extracting placement of wires and drawing routing route_wirex0 = int(nets[temp + 1].strip("[],")) route_wirey0 = int(nets[temp + 2].strip("[],")) route_wirex1 = int(nets[temp + 3].strip("[],")) route_wirey1 = int(nets[temp + 4].strip("[],")) rw = route_wirex1 - route_wirex0 rh = route_wirey1 - route_wirey0 p = draw.Path(stroke_width=strokewidth, stroke=color, stroke_opacity=0.7, fill_opacity=0) # d.append(draw.Lines(route_wirex0,route_wirey1,stroke_width=strokewidth, stroke=color, stroke_opacity=0.7, fill_opacity=0)) p.M(route_wirex0 - dx0, -(height - (route_wirey0 - dy0))) # Start path at point p.l(rw, rh) # Draw line to g.append(p) d.append( draw.Rectangle(route_wirex0 - dx0, -(height - (route_wirey0 - dy0)), rh, strokewidth, fill=color, stroke_opacity=0.7, fill_opacity=0, class_=met)) #d.append(draw.Rectangle(route_wirex0 - dx0,-(height - (route_wirey0 - dy0)),abs(rw)+50 ,abs(rh)+50,stroke_width=strokewidth, stroke="#FFF300", stroke_opacity=0, fill_opacity=0.5, class_="net",id=net_ident+"_net")) #d.append(draw.Lines(route_wirex0,route_wirey1,stroke_width=strokewidth, stroke=color, stroke_opacity=0.7, fill_opacity=0)) temp = temp + 2 d.append(g) pin_info = [] # Contains the needed details to draw the pins splt = "" for keys, val in def_parser.pins.pin_dict.items(): # print(keys) splt = str(val) # print(val) splt = splt.split() pin_info.append(splt[3]) pin_info.append(splt[9].strip("[],")) pin_info.append(splt[10].strip("[],")) pin_info.append(splt[11].strip("[],")) pin_info.append(splt[12].strip("[],")) pin_info.append(splt[13].strip("[],")) pin_info.append(splt[15].strip("[],")) pin_info.append(splt[16].strip("[],")) pin_info.append(splt[17].strip("[],")) # print(pin_info) for b in range(0, len(pin_info)): if (pin_info[b] == "metal1" or pin_info[b] == "metal2" or pin_info[b] == "metal3" or pin_info[b] == "metal4"): pinx0 = int(pin_info[b + 1]) piny0 = int(pin_info[b + 2]) pinx1 = int(pin_info[b + 3]) piny1 = int(pin_info[b + 4]) pin_pos1 = int(pin_info[b + 5]) pin_pos2 = int(pin_info[b + 6]) pin_name = pin_info[b - 1] PINS = pin_name.replace('<', '') PINS = PINS.replace('>', '') d.append( draw.Rectangle(pin_pos1 - dx0, -(height - (pin_pos2 - dy0)), pinx1 - pinx0 + 200, piny1 - piny0 + 200, fill='#B1725A', fill_opacity=0.6, Class="PIN", id=PINS)) d.append( draw.Text(pin_name, 40, pin_pos1 - dx0, -(height - (pin_pos2 - dy0 - 20)), centre='origin', Class="PINNames")) #drc_parser=[] #read_path = input("Enter DRC file path: ") #ENTER DRC FILE PATH HERE! drc = DRC_parser(path2) drc.parse() # x = drc_parser.DRC_parser() SVG = str(pth[-1]) + ".html" d.saveSvg("templates/" + SVG) # draw svg image and give it a file name with open('htmlHead.txt', 'r') as file: Head = file.read() with open('htmlTail.txt', 'r') as file: Tail = file.read() with open("templates/" + SVG, 'r+') as f: content = f.read() contentX = content.replace(str(height), "950", 1) contentX = contentX.replace(str(width), "950", 1) f.seek(0, 0) f.write(Head + contentX + Tail) return SVG
def main(svg_file): print('Parsing file:', svg_file) doc = minidom.parse(svg_file) g = doc.getElementsByTagName('g')[0] transform = g.getAttribute('transform') if not transform == '': if len(transform.split(')')) > 2: print('Only support translation on the whole SVG at the moment.') if not transform.split('(')[0] == 'translate': print('Only supports translation on the whole SVG at the moment.') coords = transform.split('(')[1][:-1] dx = float(coords.split(',')[0]) dy = float(coords.split(',')[1]) else: dx = 0 dy = 0 print('Extracting path strings.') path_strings = [(path.getAttribute('style'), path.getAttribute('d'), path.getAttribute('transform')) for path in g.getElementsByTagName('path')] print('Extracting text strings.') text_strings = [] for text in g.getElementsByTagName('text'): sty = text.getAttribute('style') x = float(text.getAttribute('x')) y = -1 * (float(text.getAttribute('y'))) if not text.firstChild.firstChild == None: string = text.firstChild.firstChild.nodeValue text_strings.append((sty, x, y, string)) width = doc.getElementsByTagName('svg')[0].getAttribute('width') height = doc.getElementsByTagName('svg')[0].getAttribute('height') if width.endswith('mm'): width = round(float(width[:-2]), 0) else: print('unknown width unit') sys.exit(0) if height.endswith('mm'): height = round(float(height[:-2]), 0) else: print('unknown height unit') sys.exit(0) doc.unlink() path_styles = [] paths = [] transforms = [] for (s, p, t) in path_strings: style_map = dict() styles = s.split(';') for s_string in styles: spl = s_string.split(':') style_map[spl[0]] = spl[1] path_styles.append(style_map) paths.append(p) transforms.append(t) print('Parsing transforms.') transforms, orderings = parse_transforms_strings(transforms) print('Extracting red segment paths.') red_paths = extract_paths(paths, path_styles, '#ff0000', transforms, orderings) print('Splitting overlapping red paths.') red_lines = split_paths(red_paths) red_lines = red_lines + [(l[1], l[0]) for l in red_lines] print('Creating red segment polygons.') polygons = [] for line in red_lines: found = False current_polygon = [line] used_lines = [line, (line[1], line[0])] current_line = line while not found: # first get all lines that connect to point 2 current_line = current_polygon[-1] line_start = current_line[0] line_end = current_line[1] line_vec = (line_end[0] - line_start[0], line_end[1] - line_start[1]) connecting_lines = [ l for l in red_lines if (app_eq(l[0], line_end) or app_eq(l[1], line_end)) and not l in used_lines ] #print(connecting_lines) max_angle = -10000 chosen_line = None for cl in connecting_lines: cl_end = cl[0] if app_eq(line_end, cl[1]) else cl[1] cl_start = cl[1] if app_eq(line_end, cl[1]) else cl[0] new_cl = (cl_start, cl_end) cl_vec = (cl_end[0] - cl_start[0], cl_end[1] - cl_start[1]) angle = angle_between(line_vec, cl_vec) if angle > max_angle: max_angle = angle chosen_line = new_cl current_polygon.append(chosen_line) used_lines.append(chosen_line) used_lines.append((chosen_line[1], chosen_line[0])) if app_eq(chosen_line[1], current_polygon[0][0]): found = True polygons.append(current_polygon) print('Filtering duplicate segments.') unique_polygons = [polygons[0]] for i, p in enumerate(polygons): same = False for j, q in enumerate(unique_polygons): if check_same_lines(p, q): same = True if same == False: unique_polygons.append(p) print('Extracting aligment marker paths.') blue_paths = extract_paths(paths, path_styles, '#0000ff', transforms, orderings) print('Extracting all black paths.') black_paths = extract_paths(paths, path_styles, '#000000', transforms, orderings) print('Splitting overlapping black paths.') black_lines = split_paths(black_paths) print('Extracting fill area paths.') fill_paths, fill_path_styles = extract_paths(paths, path_styles, 'none', transforms, orderings, True) print('Converting all paths to Shapely lines or polygons.') black_ls = [] for line in black_lines: black_ls.append( LineString( [Point(line[0][0], line[0][1]), Point(line[1][0], line[1][1])])) blue_ls = [] for line in blue_paths: blue_ls.append( LineString( [Point(line[0][0], line[0][1]), Point(line[1][0], line[1][1])])) text_points = [] for ts in text_strings: # (style,x,y,value) text_points.append(Point(ts[1], ts[2])) fill_polys = [] for points in fill_paths: fill_polys.append(Polygon([Point(x, y) for (x, y) in points])) shapely_polys = [] for polygon in unique_polygons: poly_points = [] for i, line in enumerate(polygon): if len(poly_points) == 0: poly_points.append(Point(line[0][0], line[0][1])) if i < len(polygon) - 1: poly_points.append(Point(line[1][0], line[1][1])) poly_points.append(Point(polygon[0][0][0], polygon[0][0][1])) lr = Polygon(poly_points) shapely_polys.append(lr) svgs = [] print('Drawing each segment, lines and fill, and converting to SVG.') for q, polygon in enumerate(shapely_polys): outset = 6 origin = (-dx - outset, -(height + outset + 1) + dy) d = draw.Drawing(width + 1 + 2 * outset, height + 2 + 2 * outset, origin=origin) d.setRenderSize( str(width + (2 * 6.35)) + 'mm', str(height + (2 * 6.35)) + 'mm') lr = polygon expand_lr = lr.buffer(1.5, resolution=16, join_style=2, mitre_limit=30).exterior expand_lr = Polygon(expand_lr.coords) # compute seam allowance, dist 6 == 1/4 inch outset = lr.buffer(6, resolution=16, join_style=2, mitre_limit=45).exterior outset = [(l[0], l[1]) for l in outset.coords] biggest = True for r, other_poly in enumerate(shapely_polys): if not expand_lr.contains(other_poly): biggest = False if biggest: continue #plt.plot(*lr.exterior.xy,c='b') #plt.plot(*expand_lr.xy,c='r') within_idxs = [] for i, bl in enumerate(black_ls): if expand_lr.contains(bl): within_idxs.append(i) within_lines = [ x for i, x in enumerate(black_lines) if i in within_idxs ] marker_idxs = [] for i, bl in enumerate(blue_ls): if lr.intersects(bl): marker_idxs.append(i) align_lines = [x for i, x in enumerate(blue_paths) if i in marker_idxs] text_idxs = [] for i, tp in enumerate(text_points): if lr.contains(tp): text_idxs.append(i) text_locations = [ x for i, x in enumerate(text_strings) if i in text_idxs ] fill_idxs = [] for i, fp in enumerate(fill_polys): if expand_lr.contains(fp): fill_idxs.append(i) fill_poly_paths = [ x for i, x in enumerate(fill_paths) if i in fill_idxs ] fill_poly_styles = [ x for i, x in enumerate(fill_path_styles) if i in fill_idxs ] for i, points in enumerate(fill_poly_paths): colour = fill_poly_styles[i]['fill'] p = draw.Path(stroke_width=0, fill=colour, fill_opacity=1) p.M(points[0][0], points[0][1]) for point in points[1:]: p.L(point[0], point[1]) d.append(p) for points in unique_polygons[q]: p = draw.Path(stroke_width=3, stroke='red', fill_opacity=0, opacity=0.3) p.M(points[0][0], points[0][1]) for point in points[1:]: p.L(point[0], point[1]) d.append(p) for points in within_lines: p = draw.Path(stroke_width=1, stroke='black', fill_opacity=0) p.M(points[0][0], points[0][1]) for point in points[1:]: p.L(point[0], point[1]) d.append(p) for points in align_lines: p = draw.Path(stroke_width=1, stroke='blue', fill_opacity=0) p.M(points[0][0], points[0][1]) for point in points[1:]: p.L(point[0], point[1]) d.append(p) for ts in text_locations: size = float([ x.split(':')[1] for x in ts[0].split(';') if x.split(':')[0] == 'font-size' ][0][:-2]) colour = [ x.split(':')[1] for x in ts[0].split(';') if x.split(':')[0] == 'fill' ][0] p = draw.Text(ts[3], size, float(ts[1]), float(ts[2]), fill=colour) if ts[3].isalpha(): letter = ts[3] d.append(p) # add seam allowance p = draw.Path(stroke='black', stroke_dasharray=3, fill_opacity=0, opacity=1) p.M(outset[0][0], outset[0][1]) for point in outset[1:]: p.L(point[0], point[1]) d.append(p) svgs.append((d, letter)) print("Saving generated segment SVG's to file.") directory = svg_file[:-4] if not os.path.exists(directory): os.mkdir(directory) for svg, letter in svgs: svg.saveSvg(directory + '/' + letter + '.svg') print('Done.')
def draw_share_progress(): goal = int(getattr(settings, "SHARE_PROGRESS_GOAL", "10") or "10") offset = int(getattr(settings, "SHARE_PROGRESS_OFFSET", "0") or "0") baseline = int(getattr(settings, "SHARE_PROGRESS_BASELINE", "0") or "0") baseline_progress = baseline / goal ordered = Share.objects.filter( cancelled_date__isnull=True).count() + offset ordered_progress = ordered / goal paid = Share.objects.filter(cancelled_date__isnull=True, paid_date__isnull=False).count() + offset paid_progress = paid / goal d = draw.Drawing(1.8, 1.6, origin='center') arrow = draw.Marker(-0.2, -0.5, 0.9, 0.5, scale=20, orient='auto') arrow.append( draw.Lines(-0.2, -0.5, 0, 0, -0.2, 0.5, 0.9, 0, fill='black', close=True)) arc = draw.Path(stroke='black', stroke_width=0.002, fill_opacity=0, marker_end=arrow) arc.arc(0, 0, 0.6, 89, 94, cw=True) d.append(arc) d.append(draw.Text(f'{goal}', **on_arc(0.63, 0.99))) d.append(progress_arc(ordered_progress, fill_opacity=0.5)) d.append(progress_arc(paid_progress)) if baseline > 0: d.append(progress_arc(baseline_progress, fill='#083c00')) # text center if goal > ordered: d.append(draw.Text('Noch', 0.1, 0, 0.3, center=True)) d.append( draw.Text(str(goal - ordered), 0.3, 0, 0.12, center=True, font_weight='bold')) d.append(draw.Text('Anteilscheine', 0.09, 0, -0.1, center=True)) # labels d.append( draw.Text(f'{ordered-baseline} neue\nbestellt', **on_arc(0.7, ordered_progress))) d.append( draw.Text(f'{paid-baseline} neue\nbezahlt', **on_arc(0.5, paid_progress, 'inner'))) if baseline > 0: d.append( draw.Text(f'{baseline}\nbisher', fill='white', **on_arc(0.5, baseline_progress - 0.025))) else: d.append(draw.Text('Wir haben es', 0.09, 0, 0.14, center=True)) d.append( draw.Text('Geschafft!', 0.18, 0, 0, center=True, font_weight='bold')) # Display d.setRenderSize(w='100%', h='100%') svg = d.asSvg() return svg[:-6] + """<style type="text/css">
def drawSVG(self, path=None, target='TARGET_0000000001__64__MNXC3', subplot_size=[200,200], #reac_size=[20,60], reac_fill_color='#ddd', reac_stroke_color='black', reac_stroke_width=2, arrow_stroke_color='black', arrow_stroke_width=2, font_family='sans-serif', font_size=10, font_color='black', plot_only_central=True, filter_cofactors=True, filter_sink_species=False): """Generate a reaction SVG image from the rpgraph object. :param rpgraph: rpGraph object to draw the SVG from :param target: source node to calculate the hierarchy tree organisation of the reaction (should be TARGET) :param suboplot_size: The size in pixels of the subplot boxes used to draw the SVG (default: [200, 200]) :param reac_fill_color: Hex (or name) color code to fill of the reaction box (default: '#ddd') :param reac_stroke_color: Hex (or name) color code of the reaction box stroke (default: 'black') :param reac_stroke_width: Size of the reaction rectangle stroke width (default: 2) :param arrow_stroke_color: Hex (or name) color code of the reaction arrows (default: 'black') :param arrow_stroke_width: Size of the reaction arrows (default: 2) :param font_family: The font of the cofactors (default: 'sans-serif' :param font_size: The font size of the cofactors (default: 10) :param font_color: The font color of the cofactors (default: 'black') :param plot_only_central: Do not draw the chemical structure of the non-central species (default: True) :param filter_cofactors: Do not draw the chemical structire of the identified cofactors (see: data/mnx_cofactors.json) (default: True) :param filter_sink_species: Do not draw the chemical structure of sink species (default: False) :type rpgraph: rpGraph :type target: str :type suboplot_size: list :type reac_fill_color: str :type reac_stroke_color: str :type reac_stroke_width: int :type arrow_stroke_color: str :type arrow_stroke_width: int :type font_family: str :type font_size: int :type font_color: str :type plot_only_central: bool :type filter_cofactors: bool :type filter_sink_species: bool :returns: tuple (svg, resG, mod_pos, reac_cofactors_name) - svg - SVG as string - regG - Result networkx object with the cofactors removed - mod_pos - The calculates positions for the objects - reac_cofactors_name - Dictionnary of reactions with the subtrates and products ID's :rtype: tuple """ if not self.G: self.logger.error('The G needs to be initialised') return False #TODO: Check this one: /Users/melchior/Downloads/rpglobalscore_77/rp_109_2.sbml.xml reac_size = [subplot_size[0]/8, subplot_size[1]/2] #gather all the inchis and convert to svg resG, pos, reac_cofactors_id = self.hierarchyPos(self.G, target, plot_only_central=plot_only_central, filter_cofactors=filter_cofactors, filter_sink_species=filter_sink_species) self.logger.debug('+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=') ######## convert the id's to string name ##### reac_cofactors_name = {} for reac_id in reac_cofactors_id: if not reac_id in reac_cofactors_name: reac_cofactors_name[reac_id] = {'substrates': [], 'products': []} for sub in reac_cofactors_id[reac_id]['substrates']: try: name = self.G.node.get(sub)['name'] except KeyError: name = sub if name=='': name = sub reac_cofactors_name[reac_id]['substrates'].append(name) for pro in reac_cofactors_id[reac_id]['products']: try: name = self.G.node.get(pro)['name'] except KeyError: name = pro if name=='': name = pro reac_cofactors_name[reac_id]['products'].append(name) ############# Calculate the size of the image ##### id_inchi = {} self.logger.debug('positions: '+str(pos)) for node in list(resG.nodes): if resG.node.get(node)['type']=='species': id_inchi[node] = resG.node.get(node)['brsynth']['inchi'] id_svg = self.drawChemicalList(id_inchi, subplot_size) self.logger.debug('============================') a = {} for n in pos: if not pos[n][0] in a: a[pos[n][0]] = [] a[pos[n][0]].append(pos[n][1]) self.logger.debug('a: '+str(a)) largest_y = 0 for i in a: if len(a[i])>largest_y: largest_y = len(a[i]) if largest_y==0: largest_y = 1 self.logger.debug('largest_y: '+str(largest_y)) u_x_layers = sorted(list(set([pos[i][0] for i in pos]))) u_y_layers = sorted(list(set([pos[i][1] for i in pos]))) self.logger.debug('u_x_layers: '+str(u_x_layers)) self.logger.debug('u_y_layers: '+str(u_y_layers)) background_len_x = subplot_size[0]*len(u_x_layers) background_len_y = subplot_size[1]*largest_y self.logger.debug('background_len_x: '+str(background_len_x)) self.logger.debug('background_len_y: '+str(background_len_y)) mod_pos = {} #adjust the x axis lications for the boxes to be close to each other #TODO: readjust to equidistant on the y-axis nodes that are not for node in pos: mod_pos[node] = (pos[node][0]*(subplot_size[0]*(len(u_x_layers)-1)), #not sure why I have to correct that (pos[node][1]*background_len_y)) self.logger.debug('============================') self.logger.debug('mod_pos: '+str(mod_pos)) ########### draw the background ############# len_fig_x = background_len_x len_fig_y = background_len_y self.logger.debug('len_fig_x: '+str(len_fig_x)) self.logger.debug('len_fig_y: '+str(len_fig_y)) fig = sg.SVGFigure(str(len_fig_x), str(len_fig_y)) background_white = draw.Drawing(len_fig_x, len_fig_y, origin=(0,0)) background_white.append(draw.Rectangle(0, 0, len_fig_x, len_fig_y, fill='#ffffff')) a = sg.fromstring(background_white.asSvg()) b_w = a.getroot() b_w.moveto(0, background_len_y)#WARNING: not sure why I have to + subpot fig.append(b_w) nodes_attach_locs = {} for node_id in mod_pos: node = self.G.node.get(node_id) self.logger.debug('\tSpecies: '+str(node_id)) if node['type']=='species': self.logger.debug('\tNode pos: '+str(mod_pos[node_id])) self.logger.debug('\tx: '+str(mod_pos[node_id][0])) self.logger.debug('\ty: '+str(mod_pos[node_id][1])) move_x = mod_pos[node_id][0] # because of the nature of the x y locations, need to reverse them here if mod_pos[node_id][1]==0.0: y_coord = mod_pos[node_id][1]+subplot_size[1]/2 move_y = len_fig_y-mod_pos[node_id][1]-subplot_size[1] elif mod_pos[node_id][1]==len_fig_y: y_coord = mod_pos[node_id][1]-subplot_size[1]/2 move_y = len_fig_y-mod_pos[node_id][1] else: y_coord = mod_pos[node_id][1] move_y = len_fig_y-mod_pos[node_id][1]-subplot_size[1]/2 self.logger.debug('\tmove_x: '+str(move_x)) self.logger.debug('\tmove_y: '+str(move_y)) f = sg.fromstring(id_svg[node_id]) p = f.getroot() #Rememeber that you are moving the object on the x and y axis while the coordinates are coordinates so its reversed p.moveto(move_x, move_y) fig.append(p) nodes_attach_locs[node_id] = {'left': (mod_pos[node_id][0], y_coord), 'right': (mod_pos[node_id][0]+subplot_size[0], y_coord)} elif node['type']=='reaction': d = draw.Drawing(subplot_size[0], subplot_size[1], origin=(0,0)) d.append(draw.Rectangle(0, 0, subplot_size[0], subplot_size[1], fill='#FFFFFF')) edge_x = subplot_size[0]/2-reac_size[1]/2 edge_y = subplot_size[1]/2-reac_size[0]/2 self.logger.debug('\tedge_x: '+str(edge_x)) self.logger.debug('\tedge_y: '+str(edge_y)) self.logger.debug('\tx: '+str(mod_pos[node_id][0])) self.logger.debug('\ty: '+str(mod_pos[node_id][1]+subplot_size[1])) if reac_cofactors_name[node_id]['substrates']: d.append(draw.Line(subplot_size[0]/2, edge_y-reac_size[0], subplot_size[0]/2, edge_y-self.arrowhead_comp_x, stroke=arrow_stroke_color, stroke_width=arrow_stroke_width, fill='none', marker_end=self.arrowhead)) if reac_cofactors_name[node_id]['products']: d.append(draw.Line(subplot_size[0]/2, edge_y+reac_size[0], subplot_size[0]/2, (subplot_size[1]/2)+reac_size[1]/3, stroke=arrow_stroke_color, stroke_width=arrow_stroke_width, fill='none', marker_end=self.arrowhead)) y_shift = 0.0 for sub in reac_cofactors_name[node_id]['substrates']: self.logger.debug(sub) d.append(draw.Text(sub, font_size, subplot_size[0]/2, ((subplot_size[1]/2)-reac_size[1]/3)-y_shift-font_size, font_family=font_family, center=True, fill=font_color)) y_shift += font_size y_shift = 0.0 for pro in reac_cofactors_name[node_id]['products']: self.logger.debug(pro) d.append(draw.Text(pro, font_size, subplot_size[0]/2, ((subplot_size[1]/2)+reac_size[1]/3)+y_shift+font_size+self.arrowhead_comp_x, font_family=font_family, center=True, fill=font_color)) y_shift += font_size d.append(draw.Rectangle(edge_x, edge_y, reac_size[1], reac_size[0], fill=reac_fill_color, stroke_width=reac_stroke_width, stroke=reac_stroke_color)) a = sg.fromstring(d.asSvg()) a_r = a.getroot() move_x = mod_pos[node_id][0] if mod_pos[node_id][1]==0.0: move_y = len_fig_y-mod_pos[node_id][1] elif mod_pos[node_id][1]==len_fig_y: move_y = len_fig_y-mod_pos[node_id][1]+subplot_size[1] else: move_y = len_fig_y-mod_pos[node_id][1]-subplot_size[1]/2+subplot_size[1] self.logger.debug('\tmove_x: '+str(move_x)) self.logger.debug('\tmove_y: '+str(move_y)) a_r.moveto(move_x, move_y) fig.append(a_r) nodes_attach_locs[node_id] = {'left': (move_x+edge_x, move_y-subplot_size[1]/2), 'right': (move_x+subplot_size[0]-edge_x+reac_stroke_width/2, move_y-subplot_size[1]/2)} self.logger.debug('\t-------------------------------') self.logger.debug('nodes_attach_locs: '+str(nodes_attach_locs)) self.logger.debug(list(resG.edges)) arrow_box = draw.Drawing(len_fig_x, len_fig_y, origin=(0,0)) ################ Add the arrowhead depending on edge direction ####### #depending on the directions of the node, switch the source and the target #and calculate the center pocitions of the arrows edge_pos = {} strict_edge_pos = {} for edge in list(resG.edges): #left to right if pos[edge[0]][0]>pos[edge[1]][0]: source_x = nodes_attach_locs[edge[0]]['left'][0] source_y = nodes_attach_locs[edge[0]]['left'][1] target_x = nodes_attach_locs[edge[1]]['right'][0] target_y = nodes_attach_locs[edge[1]]['right'][1] edge_pos[edge] = {'source': (round(source_x, 2), round(source_y, 2)), 'L1': (round(source_x+(target_x-source_x)/2, 2), round(source_y, 2)), 'L2': (round(source_x+(target_x-source_x)/2, 2), round(target_y, 2)), 'target': (round(target_x+self.arrowhead_comp_x, 2), round(target_y, 2)), 'arrow_direction': self.rev_arrowhead_flat} strict_edge_pos[edge] = {'source': (int(round(source_x, 0)), int(round(source_y, 0))), 'L1': (int(round(source_x+(target_x-source_x)/2, 0)), int(round(source_y, 0))), 'L2': (int(round(source_x+(target_x-source_x)/2, 0)), int(round(target_y, 0))), 'target': (int(round(target_x, 0)), int(round(target_y, 0))), 'arrow_direction': self.rev_arrowhead_flat} ''' edge_pos[edge] = {'source': [source_x, source_y], 'L1': [source_x+(target_x-source_x)/2+self.arrowhead_comp_y/2, source_y], 'L2': [source_x+(target_x-source_x)/2+self.arrowhead_comp_y/2, target_y], 'target': [target_x+self.arrowhead_comp_x, target_y], 'arrow_direction': self.rev_arrowhead_flat} ''' #right to left elif pos[edge[0]][0]<pos[edge[1]][0]: source_x = nodes_attach_locs[edge[0]]['right'][0] source_y = nodes_attach_locs[edge[0]]['right'][1] target_x = nodes_attach_locs[edge[1]]['left'][0] target_y = nodes_attach_locs[edge[1]]['left'][1] edge_pos[edge] = {'source': (round(source_x, 2), round(source_y, 2)), 'L1': (round(source_x+(target_x-source_x)/2, 2), round(source_y, 2)), 'L2': (round(source_x+(target_x-source_x)/2, 2), round(target_y, 2)), 'target': (round(target_x-self.arrowhead_comp_x, 2), round(target_y, 2)), 'arrow_direction': self.arrowhead_flat} strict_edge_pos[edge] = {'source': (int(round(source_x, 0)), int(round(source_y, 0))), 'L1': (int(round(source_x+(target_x-source_x)/2, 0)), int(round(source_y, 0))), 'L2': (int(round(source_x+(target_x-source_x)/2, 0)), int(round(target_y, 0))), 'target': (int(round(target_x, 0)), int(round(target_y, 0))), 'arrow_direction': self.arrowhead_flat} ''' edge_pos[edge] = {'source': [source_x, source_y], 'L1': [source_x+(target_x-source_x)/2-self.arrowhead_comp_y/2, source_y], 'L2': [source_x+(target_x-source_x)/2-self.arrowhead_comp_y/2, target_y], 'target': [target_x-self.arrowhead_comp_x, target_y], 'arrow_direction': self.arrowhead_flat} ''' else: self.logger.error('Cannot connect same y-axi') #calculate the center positions of the arrows self.logger.debug('edge_pos: '+str(edge_pos)) self.logger.debug('strict_edge_pos: '+str(strict_edge_pos)) ############# Calculate the overlaps ########## #find the edges that have the same source/target locations - if more than that do not go in the same direction # then create a input/output location and update the positions #NOTE: have to make strings from the edge locations to be able to be overlaps_arrow = {'node': {}, 'L': {}} #overlaps_edge = {'node': {}, 'L': {}} for edge in strict_edge_pos: source_id = str(strict_edge_pos[edge]['source'][0])+'-'+str(strict_edge_pos[edge]['source'][1]) target_id = str(strict_edge_pos[edge]['target'][0])+'-'+str(strict_edge_pos[edge]['target'][1]) l1_id = str(strict_edge_pos[edge]['L1'][0])+'-'+str(strict_edge_pos[edge]['L1'][1]) l2_id = str(strict_edge_pos[edge]['L2'][0])+'-'+str(strict_edge_pos[edge]['L1'][1]) ####### make the nodes and arrow overlaps_arrow ####### if not source_id in overlaps_arrow['node']: overlaps_arrow['node'][source_id] = [strict_edge_pos[edge]['arrow_direction']] else: overlaps_arrow['node'][source_id].append(strict_edge_pos[edge]['arrow_direction']) if not target_id in overlaps_arrow['node']: overlaps_arrow['node'][target_id] = [strict_edge_pos[edge]['arrow_direction']] else: overlaps_arrow['node'][target_id].append(strict_edge_pos[edge]['arrow_direction']) if not l1_id in overlaps_arrow['L']: overlaps_arrow['L'][l1_id] = [strict_edge_pos[edge]['arrow_direction']] else: overlaps_arrow['L'][l1_id].append(strict_edge_pos[edge]['arrow_direction']) if not l2_id in overlaps_arrow['L']: overlaps_arrow['L'][l2_id] = [strict_edge_pos[edge]['arrow_direction']] else: overlaps_arrow['L'][l2_id].append(strict_edge_pos[edge]['arrow_direction']) ##### make the overlap edge #### """ if not source_id in overlaps_edge['node']: overlaps_edge['node'][source_id] = [edge] else: overlaps_edge['node'][source_id].append(edge) if not target_id in overlaps_edge['node']: overlaps_edge['node'][target_id] = [edge] else: overlaps_edge['node'][target_id].append(edge) if not l1_id in overlaps_edge['L']: overlaps_edge['L'][l1_id] = [edge] else: overlaps_edge['L'][l1_id].append(edge) if not l2_id in overlaps_edge['L']: overlaps_edge['L'][l2_id] = [edge] else: overlaps_edge['L'][l2_id].append(edge) """ ########## Add entry/exit of node if same side node has multiple types ####### #adjust the perpendecular arrows if there is overlap with reversed directions #TODO: adjust arrows that overlap in the same direction but do not have the same destination self.logger.debug('overlaps_arrow: '+str(overlaps_arrow)) #self.logger.debug('overlaps_edge: '+str(overlaps_edge)) for pos_id in overlaps_arrow['node']: #if the direction of the node locations are not the same then you need seperate the input/output if len(overlaps_arrow['node'][pos_id])>1: if not overlaps_arrow['node'][pos_id].count(self.arrowhead_flat)==len(overlaps_arrow['node'][pos_id]) or overlaps_arrow['node'][pos_id].count(self.rev_arrowhead_flat)==len(overlaps_arrow['node'][pos_id]): for edge in strict_edge_pos: source_id = str(strict_edge_pos[edge]['source'][0])+'-'+str(strict_edge_pos[edge]['source'][1]) target_id = str(strict_edge_pos[edge]['target'][0])+'-'+str(strict_edge_pos[edge]['target'][1]) if source_id==pos_id and strict_edge_pos[edge]['arrow_direction']==self.arrowhead_flat: edge_pos[edge]['source'] = (edge_pos[edge]['source'][0], edge_pos[edge]['source'][1]-self.arrowhead_comp_y/2) edge_pos[edge]['L1'] = (edge_pos[edge]['L1'][0], edge_pos[edge]['L1'][1]-self.arrowhead_comp_y/2) elif source_id==pos_id and strict_edge_pos[edge]['arrow_direction']==self.rev_arrowhead_flat: edge_pos[edge]['source'] = (edge_pos[edge]['source'][0], edge_pos[edge]['source'][1]+self.arrowhead_comp_y/2) edge_pos[edge]['L1'] = (edge_pos[edge]['L1'][0], edge_pos[edge]['L1'][1]+self.arrowhead_comp_y/2) if target_id==pos_id and strict_edge_pos[edge]['arrow_direction']==self.arrowhead_flat: edge_pos[edge]['target'] = (edge_pos[edge]['target'][0], edge_pos[edge]['target'][1]-self.arrowhead_comp_y/2) edge_pos[edge]['L2'] = (edge_pos[edge]['L2'][0], edge_pos[edge]['L2'][1]-self.arrowhead_comp_y/2) elif target_id==pos_id and strict_edge_pos[edge]['arrow_direction']==self.rev_arrowhead_flat: edge_pos[edge]['target'] = (edge_pos[edge]['target'][0], edge_pos[edge]['target'][1]+self.arrowhead_comp_y/2) edge_pos[edge]['L2'] = (edge_pos[edge]['L2'][0], edge_pos[edge]['L2'][1]+self.arrowhead_comp_y/2) #TODO: problem of overlap of arrows #1) loop through all the arrows in the same layer #2) for each node and each entry/exit, record the perpendicular locations #3) if two overlap when they should not then add y_shift # - if they are entry/exit # - if they are entry or exit that overlap with other entry/exit from another reaction #do the same for the the perpendicular ''' for pos_id in overlaps_arrow['edge']: for edge in strict_edge_pos: source_id = str(strict_edge_pos[edge]['source'][0])+'-'+str(strict_edge_pos[edge]['source'][1]) target_id = str(strict_edge_pos[edge]['target'][0])+'-'+str(strict_edge_pos[edge]['target'][1]) ''' #calculate the perpendicular overlaps ''' for edge in edge_pos: perpendicular_layers = [] for comp_edge in edge_pos: #if edge_pos[comp_edge]['L1']==edge_pos[edge]['L1']: x, y = lineIntersection(edge_pos[comp_edge]['L1'][0], edge_pos[comp_edge]['L1'][1], edge_pos[edge]['L1'][0], edge_pos[edge]['L1'][1]) if not x==None and y==None: perpendicular_layers.append(comp_edge) if len(perpendicular_layers)>1: pass #cases to ignore: # - when they overlap but go in the same direction and the same target or source #case when overlap but they go to the same direction and not the same target #case when ''' for pos_id in overlaps_arrow['L']: if len(overlaps_arrow['L'][pos_id])>1: #TODO: need a better overlap algo that takes into consideration if they do not overlap #example /Users/melchior/Downloads/rpglobalscore_101/rp_1_1.sbml.xml #BUG: /Users/melchior/Downloads/rpglobalscore_101/rp_3_2.sbml.xml --> line not detected to be moved #BUG: three perpendicular lines drawn: /Users/melchior/Downloads/rpglobalscore_101/rp_2_2.sbml.xml #BUG: HO being shown, should be cofactor: /Users/melchior/Downloads/rpglobalscore_91/rp_2_1.sbml.xml #BUG: this one should not shift perpendivular lines: /Users/melchior/Downloads/rpglobalscore_101/rp_12_1.sbml.xml if not overlaps_arrow['L'][pos_id].count(self.arrowhead_flat)==len(overlaps_arrow['L'][pos_id]) or overlaps_arrow['L'][pos_id].count(self.rev_arrowhead_flat)==len(overlaps_arrow['L'][pos_id]): '''Close but removes some that should have seperated #ignore cases where there are only 2 that go in opposite direction and actually never meet if len(overlaps_arrow['L'][pos_id])==2: if not strict_edge_pos[overlaps_edge['L'][pos_id][0]]['L1'][1]-strict_edge_pos[overlaps_edge['L'][pos_id][0]]['L2'][1]>0 and not strict_edge_pos[overlaps_edge['L'][pos_id][1]]['L1'][1]-strict_edge_pos[overlaps_edge['L'][pos_id][1]]['L2'][1]>0: continue if not strict_edge_pos[overlaps_edge['L'][pos_id][0]]['L1'][1]-strict_edge_pos[overlaps_edge['L'][pos_id][0]]['L2'][1]<0 and not strict_edge_pos[overlaps_edge['L'][pos_id][1]]['L1'][1]-strict_edge_pos[overlaps_edge['L'][pos_id][1]]['L2'][1]<0: continue ''' #TODO: need to detect if there are any criss-cross of perpendecular arrows at their target of source to seperate in either direction for edge in strict_edge_pos: l1_id = str(strict_edge_pos[edge]['L1'][0])+'-'+str(strict_edge_pos[edge]['L1'][1]) l2_id = str(strict_edge_pos[edge]['L2'][0])+'-'+str(strict_edge_pos[edge]['L1'][1]) if l1_id==pos_id and strict_edge_pos[edge]['arrow_direction']==self.arrowhead_flat: ''' edge_pos[edge]['L1'] = (edge_pos[edge]['L1'][0]-self.arrowhead_comp_y/2, edge_pos[edge]['L1'][1]) edge_pos[edge]['L2'] = (edge_pos[edge]['L2'][0]-self.arrowhead_comp_y/2, edge_pos[edge]['L2'][1]) ''' edge_pos[edge]['L1'] = (edge_pos[edge]['L1'][0]+self.arrowhead_comp_y/2, edge_pos[edge]['L1'][1]) edge_pos[edge]['L2'] = (edge_pos[edge]['L2'][0]+self.arrowhead_comp_y/2, edge_pos[edge]['L2'][1]) elif l1_id==pos_id and strict_edge_pos[edge]['arrow_direction']==self.rev_arrowhead_flat: ''' edge_pos[edge]['L1'] = (edge_pos[edge]['L1'][0]+self.arrowhead_comp_y/2, edge_pos[edge]['L1'][1]) edge_pos[edge]['L2'] = (edge_pos[edge]['L2'][0]+self.arrowhead_comp_y/2, edge_pos[edge]['L2'][1]) ''' edge_pos[edge]['L1'] = (edge_pos[edge]['L1'][0]-self.arrowhead_comp_y/2, edge_pos[edge]['L1'][1]) edge_pos[edge]['L2'] = (edge_pos[edge]['L2'][0]-self.arrowhead_comp_y/2, edge_pos[edge]['L2'][1]) if l2_id==pos_id and strict_edge_pos[edge]['arrow_direction']==self.arrowhead_flat: ''' edge_pos[edge]['L1'] = (edge_pos[edge]['L1'][0]-self.arrowhead_comp_y/2, edge_pos[edge]['L1'][1]) edge_pos[edge]['L2'] = (edge_pos[edge]['L2'][0]-self.arrowhead_comp_y/2, edge_pos[edge]['L2'][1]) ''' edge_pos[edge]['L1'] = (edge_pos[edge]['L1'][0]+self.arrowhead_comp_y/2, edge_pos[edge]['L1'][1]) edge_pos[edge]['L2'] = (edge_pos[edge]['L2'][0]+self.arrowhead_comp_y/2, edge_pos[edge]['L2'][1]) elif l2_id==pos_id and strict_edge_pos[edge]['arrow_direction']==self.rev_arrowhead_flat: ''' edge_pos[edge]['L1'] = (edge_pos[edge]['L1'][0]+self.arrowhead_comp_y/2, edge_pos[edge]['L1'][1]) edge_pos[edge]['L2'] = (edge_pos[edge]['L2'][0]+self.arrowhead_comp_y/2, edge_pos[edge]['L2'][1]) ''' edge_pos[edge]['L1'] = (edge_pos[edge]['L1'][0]-self.arrowhead_comp_y/2, edge_pos[edge]['L1'][1]) edge_pos[edge]['L2'] = (edge_pos[edge]['L2'][0]-self.arrowhead_comp_y/2, edge_pos[edge]['L2'][1]) ############## Finally draw ################## for edge in edge_pos: p = draw.Path(stroke=arrow_stroke_color, stroke_width=arrow_stroke_width, fill='none', marker_end=edge_pos[edge]['arrow_direction']) p.M(edge_pos[edge]['source'][0], edge_pos[edge]['source'][1]).L(edge_pos[edge]['L1'][0], edge_pos[edge]['L1'][1]).L(edge_pos[edge]['L2'][0], edge_pos[edge]['L2'][1]).L(edge_pos[edge]['target'][0], edge_pos[edge]['target'][1]) arrow_box.append(p) a = sg.fromstring(arrow_box.asSvg()) a_b = a.getroot() a_b.moveto(0, background_len_y)#WARNING: not sure why I have to + subpot fig.append(a_b) svg = fig.to_str().decode("utf-8") if path: open(path, 'w').write(svg) return svg, resG, mod_pos, reac_cofactors_name, nodes_attach_locs
def genSVG(nodes, spacing, node_size, width=None, height=None, minValue=1, maxValue=10, node_scaling="linear", connection_type="semi-curved", color_startEnd=True, color_categories=True, nodes_color="gray", start_node_color="green", end_node_color="red", palette=None, show_labels=True, label_text="item", label_font="sans-serif", label_color="black", label_size=5, label_shortening="clip", label_position="nodes", line_opacity=0.5, line_stroke_color="white", line_stroke_width=0.5, line_stroke_thick=0.5, legend=True): """ Generates an SVG from data loaded via the read functions. Parameters: nodes (list): The output of nodify(), a list containingg information about the nodes for the graph spacing (int): the space between the nodes, defaults to 50 node_size (int): default node size, defauults to 10 width (int): width of the visualization, defaults to None, if None they are generated from the size of the nodes, if they are specified the nodes will be rescaled to fit the space height (int): height of the visualization, defaults to None, if None they are generated from the size of the nodes, if they are specified the nodes will be rescaled to fit the space minValue (int): min size of a node , defaults to 1 maxValue (int): max size of a node, defaults to 10 node_scaling (str): "linear" or ... " ", defaults to "linear" connection_type (str): "semi-curved" or "curved" or "linear", defaults to "semi-curved" color_startEnd (bool) : if True it marks the colors of the first and last appearence of a category, defaults to True color_categories (bool): if True the nodes and the lines are colored depending by the subcategory, deafults to True nodes_color (str): the color of the nodes if the previous two options are false, defaults to "gray", used also for the lines and for the middle nodes in case of startEnd option start_node_color (str): Defaults to "green" end_node_color (str): Defaults to "red" palette (tuple): a tuple with the name of the matplotlib palette and the number of colors ("viridis",12), defaults to None show_labels (bool): Defaults to True label_text (str): "item" shows the category, defaults to "item", "item_count" shows the category and the frequency, "item_category" shows the category and the subcategory label_font (str): Defaults to "sans-serif" label_color (str): Defaults to "black" label_size (int): Defaults to 5 label_shortening (str): defaults to "clip", "clip" cuts the text when it overlaps the margin, "resize" changes the size of the font to fit the available space, "new_line" wraps the text when it overlaps the margin and it rescale the size if the two lines overlaps the bottom margin label_position (str): defaults to "nodes", "nodes" shows a label for each node, "start_end" shows a label for the first and last node of a sequence line_opacity (float): Defaults to 0.5 line_stroke_color (str): Defaults to "white" line_stroke_width (float): Defaults to 0.5 line_stroke_thick (float): Defaults to 0.5 legend (bool): If True a Legend is included, defaults to True Returns: (drawSvg.drawing.Drawing): The finished graph """ headers = nodes[0] nodes2 = copy.deepcopy(nodes[1]) sequence = nodes[2] if start_node_color == "green": start_node_color = "#4BA167" if end_node_color == "red": end_node_color = "#A04B83" if nodes_color == "gray": nodes_color = "#EAEBEE" # Resizing of the nodes in relation to the canvas size and to the scaling option m = max([v.value for v in nodes[1]]) new_nodes = [] if width is not None: dx = (width - (spacing * 2)) / len(headers) spacing2 = 2 * (dx / 3) node_size = dx / 3 else: spacing2 = spacing if height is not None: l_col_index = [x.col_index for x in nodes2] l_col_index_max = max([l_col_index.count(y.col_index) for y in nodes2]) sum_values = sum([ x.value for x in nodes2 if l_col_index.count(x.col_index) == l_col_index_max ]) max_values = max([ x.value for x in nodes2 if l_col_index.count(x.col_index) == l_col_index_max ]) if node_scaling == "linear": dy = ((height - (spacing * 2) - (spacing / 5)) * max_values) / (sum_values + ( (maxValue / 2) * l_col_index_max)) else: dy = ((height - (spacing * 2) - (spacing / 5)) * max_values) / (sum_values + ( (max_values / 2) * l_col_index_max)) spacingy = dy / 3 maxValue = 2 * (dy / 3) else: spacingy = spacing / 5 node_x = 0 for n in nodes2: n.width = node_size if n.col_index != nodes2[n.index - 1].col_index and n.index > 0: node_x += node_size n.x += node_x if node_scaling == "linear": n.size = (((n.value + 1) * maxValue) / m) + minValue elif node_scaling == "log": n.size = (((maxValue - minValue) / math.log(m)) * math.log(n.value)) + minValue new_nodes.append(n) # positioning of the nodes on the canvas (x,y) n_x_spacing = spacing n_y_spacing = spacing + spacingy points = [] for n in new_nodes: if n.index > 0 and n.col_index == new_nodes[n.index - 1].col_index: n_y_spacing += spacingy + n.size else: n_y_spacing = spacing + spacingy + n.size if n.index > 0 and n.col_index != new_nodes[n.index - 1].col_index: n_x_spacing += spacing2 points.append( pcf.Node(n.index, n.col_index, n.x + n_x_spacing, n.y + n_y_spacing, n.size, n.value, n.width, n.label, n.category)) # sizing of the canvas if width is None and height is None: width = spacing * 4 + max([x.x for x in points]) height = spacing * 4 + max([x.y for x in points]) + ( (sum([x.size for x in points]) / len(points)) * len(set([x.category for x in points]))) elif height is None: height = spacing * 4 + max([x.y for x in points]) + ( (sum([x.size for x in points]) / len(points)) * len(set([x.category for x in points]))) elif width is None: width = spacing * 4 + max([x.x for x in points]) # COLORS if palette is not None: palette = cm.get_cmap(palette[0], palette[1]).colors count = 0 category_colors = {} for e in set([n.category for n in points]): if count < len(palette): count += 1 category_colors[e] = colors.to_hex(palette[count]) else: # DEFAULT PALETTE: the number of colors is set in relation to the length of the category list palette = cm.get_cmap("tab20c", len(set([n.category for n in points])) + 1).colors count = 0 category_colors = {} for e in set([n.category for n in points]): if count < len(palette) - 1: count += 1 category_colors[e] = colors.to_hex(palette[count]) d = draw.Drawing(width, height, displayInline=True) r = draw.Rectangle(0, 0, width, height, stroke_width=2, stroke='black', fill="white") d.append(r) # headers h_x_shift = [points[0].x] for x in points: if x.x != points[x.index - 1].x and x.index > 0: h_x_shift.append(x.x) n2 = h_x_shift[1] - h_x_shift[0] for h, x in zip(headers, h_x_shift): l = label_size if label_shortening == "resize": while len(h) * (l / 2) > n2 + points[0].size - (n2 / 8) and l > 1: if x != max(h_x_shift): l -= 1 else: break d.append( draw.Text(h, x=x, y=height - spacing, fontSize=l, font_family=label_font, fill=label_color)) elif label_shortening == "clip": clip = draw.ClipPath() clip.append(draw.Rectangle(x, height - spacing, n2, label_size)) d.append( draw.Text(h, x=x, y=height - spacing, fontSize=l, font_family=label_font, clip_path=clip, fill=label_color)) elif label_shortening == "new_line": if len(h) * (label_size / 2) > n2 + points[0].size - (n2 / 8): margin = int( (n2 + points[0].size - (n2 / 8)) / (label_size / 2)) txt = [h[x:x + margin] for x in range(0, len(h), margin)] while len(txt) * l > (l + n2 / 5) and l > 1: l -= 1 else: txt = h d.append( draw.Text(txt, x=x, y=height - spacing, fontSize=l, font_family=label_font, fill=label_color)) # lines for n in sequence.items(): if len(n[1]) > 1: for k in n[1][:-1]: if color_categories: color = category_colors[points[k].category] else: color = nodes_color if connection_type.lower() == "semi-curved": p = draw.Path(fill=color, stroke=line_stroke_color, opacity=line_opacity, stroke_width=line_stroke_width) p.M(points[k].x + points[k].width, height - points[k].y) p.L(points[k].x + points[k].width, height - points[k].y + points[k].size) if points[k].y == points[n[1][n[1].index(k) + 1]].y: p.L(points[n[1][n[1].index(k) + 1]].x, height - points[k].y + points[k].size) p.L(points[n[1][n[1].index(k) + 1]].x, height - points[k].y) else: xMedium = ((points[n[1][n[1].index(k) + 1]].x - (points[k].x + points[k].width)) / 2) + (points[k].x + points[k].width) yMedium = ( ((height - points[k].y + points[k].size) - (height - points[n[1][n[1].index(k) + 1]].y + points[k].size)) / 2) + (height - points[n[1][n[1].index(k) + 1]].y) yMedium2 = ( ((height - points[k].y) - (height - points[n[1][n[1].index(k) + 1]].y)) / 2) + (height - points[n[1][n[1].index(k) + 1]].y) p.Q(points[k].x + points[k].width + (spacing / 2), height - points[k].y + points[k].size, xMedium + line_stroke_thick, yMedium + points[k].size) p.T( points[n[1][n[1].index(k) + 1]].x, height - points[n[1][n[1].index(k) + 1]].y + points[n[1][n[1].index(k) + 1]].size) p.L(points[n[1][n[1].index(k) + 1]].x, height - points[n[1][n[1].index(k) + 1]].y) p.Q(points[n[1][n[1].index(k) + 1]].x - (spacing / 2), height - points[n[1][n[1].index(k) + 1]].y, xMedium - line_stroke_thick, yMedium2) p.T(points[k].x + points[k].width, height - points[k].y) p.Z() d.append(p) elif connection_type.lower() == 'curved': p = draw.Path(fill=color, stroke=line_stroke_color, opacity=line_opacity, stroke_width=line_stroke_width) size_start = points[k].size size_end = points[n[1][n[1].index(k) + 1]].size x1_start = points[k].x + points[k].width y1_start = height - points[k].y + size_start x1_end = points[n[1][n[1].index(k) + 1]].x y1_end = height - points[n[1][n[1].index(k) + 1]].y + size_end x2_start = x1_start y2_start = y1_start - size_start x2_end = x1_end y2_end = y1_end - size_end x_diff = x1_end - x1_start y_diff = y2_start - y1_end height_factor = 2 width_factor = 0 if points[k].y == points[n[1][n[1].index(k) + 1]].y: p.M(x1_start, y1_start) p.L(x2_start, y2_start) p.L(x2_end, y2_end) p.L(x1_end, y1_end) p.Z() d.append(p) pass else: p.M(x1_start, y1_start) cx1 = x1_end - (x_diff / 4 * 3) cy1 = y1_start ex1 = x1_end - (x_diff / 2) ey1 = y1_end + (y_diff / 2) p.Q(cx1, cy1, ex1, ey1) cx2 = x1_start + (x_diff / 4 * 3) cy2 = y1_end - (size_end / height_factor) p.Q(cx2, cy2, x1_end, y1_end) p.L(x2_end, y2_end) cx3 = (x2_end - (x_diff / 4)) cy3 = (y2_end - (size_end / height_factor)) ex3 = (x2_end + ((x1_start - x1_end) / 2) - width_factor) ey3 = (y2_end + (((y1_start - y1_end) / 2) - (( (size_start + size_end) / 2)) / height_factor)) p.Q(cx3, cy3, ex3, ey3) cx4 = x2_start + (x_diff / 4) cy4 = y2_start p.Q(cx4, cy4, x2_start, y2_start) p.Z() d.append(p) elif connection_type.lower() == 'straight': p = draw.Path(fill=color, stroke=line_stroke_color, opacity=line_opacity, stroke_width=line_stroke_width) size_start = points[k].size size_end = points[n[1][n[1].index(k) + 1]].size x1_start = points[k].x + points[k].width y1_start = height - points[k].y x1_end = points[n[1][n[1].index(k) + 1]].x y1_end = height - points[n[1][n[1].index(k) + 1]].y x2_start = x1_start y2_start = y1_start + size_start x2_end = x1_end y2_end = y1_end + size_end p.M(x1_start, y1_start) p.L(x2_start, y2_start) p.L(x2_end, y2_end) p.L(x1_end, y1_end) p.Z() d.append(p) else: print('This connection type is not implemented.') raise KeyError # nodes # return points col_index_max = 0 for node in points: if node.col_index > col_index_max: col_index_max = node.col_index for node in points: if color_startEnd == True and color_categories == True: if node.label not in [n.label for n in points][:node.index]: color = start_node_color elif node.label not in [ n.label for n in points ][node.index + 1:] and node.col_index < col_index_max: #and node.index<len(points): color = end_node_color else: color = category_colors[node.category] elif color_startEnd and not color_categories: if node.label not in [n.label for n in points][:node.index]: color = start_node_color elif node.label not in [ n.label for n in points ][node.index + 1:] and node.col_index < col_index_max: #and node.index<len(points): color = end_node_color else: color = nodes_color elif not color_startEnd and color_categories: color = category_colors[node.category] elif not color_startEnd and not color_categories: color = nodes_color if node.label != '': r = draw.Rectangle(node.x, height - node.y, node.width, node.size, fill=color, stroke=color) #stroke="black" d.append(r) if show_labels: if label_text == "item": txt = node.label elif label_text == "item_count": txt = node.label + ' (' + str(node.value) + ')' elif label_text == "item_category": txt = node.label + ' (' + str(node.category) + ')' l = label_size if label_shortening == "resize": while len(txt) * (l / 2) > spacing - (spacing / 8): if node.x != max([n.x for n in points]) and l > 1: l -= 1 else: break elif label_shortening == "clip": clip = draw.ClipPath() clip.append( draw.Rectangle(node.x, height - node.y - (spacing / 5), n2 - (n2 / 8), node.size + 2 * (spacing / 5))) elif label_shortening == "new_line": if len(txt) * (label_size / 2) > n2 - 2 * (n2 / 8): margin = int((n2 - 2 * (n2 / 8)) / (label_size / 2)) txt = [ txt[x:x + margin] for x in range(0, len(txt), margin) ] while len(txt) * l > node.size + 2 * (spacing / 8) and l > 1: l -= 1 label_pos_y = height - node.y + (node.size / 2) - (l / 2) if label_position == "start_end": if node.label not in [ n.label for n in points ][:node.index] or node.label not in [ n.label for n in points ][node.index + 1:] and node.index < len(points) and node.x != max( [n.x for n in points]): if label_shortening == "clip": label = draw.Text(txt, x=node.x + node.width + (n2 / 8), y=label_pos_y, fontSize=l, font_family=label_font, fill=label_color, clip_path=clip) else: label = draw.Text(txt, x=node.x - (n2 / 8), y=label_pos_y, fontSize=l, font_family=label_font, fill=label_color, text_anchor="end") elif label_position == "nodes": if label_shortening == "clip": label = draw.Text(txt, x=node.x + node.width + (n2 / 8), y=label_pos_y, fontSize=l, font_family=label_font, fill=label_color, clip_path=clip) else: label = draw.Text(txt, x=node.x + node.width + (n2 / 8), y=label_pos_y, fontSize=l, font_family=label_font, fill=label_color) d.append(label) # Add legend to canvas if color_categories and legend: offset = 5 # Alternative: offset = spacing spacing_bottom = 5 # Alternative: spacing_bottom = spacing symbol_size = sum([x.size for x in points]) / len(points) legend_height = (symbol_size + offset) * len(category_colors) legend_header_y = legend_height + symbol_size + spacing_bottom + ( offset) legend_header = draw.Text("Legend", x=points[0].x, y=legend_header_y, fontSize=label_size, font_family=label_font, fill=label_color) if debug_legend: print('Legend Title') print('legend_height: {}'.format(legend_height)) print('legend_header_y: {}'.format(legend_header_y)) print('points[0].x: {}'.format(points[0].x)) print('legend_header_y'.format(legend_header_y)) print() d.append(legend_header) symbol_y_shift = 0 for e in category_colors.items(): legend_label_y = spacing_bottom + legend_height + ( symbol_size / 2) - (label_size / 2) - offset - symbol_y_shift symbol = draw.Rectangle(points[0].x, spacing_bottom + legend_height - offset - symbol_y_shift, points[0].width, symbol_size, fill=e[1], stroke=e[1]) #stroke="black" if debug_legend: print(e) print('points[0].x: {}'.format(points[0].x)) print('spacing_bottom+legend_height-offset-symbol_y_shift: {}'. format(spacing_bottom + legend_height - offset - symbol_y_shift)) print('points[0].width: {}'.format(points[0].width)) print('symbol_size: {}'.format(symbol_size)) print() name = draw.Text(e[0], x=points[0].x + node.width + (n2 / 12), y=legend_label_y, fontSize=label_size, fill=label_color) d.append(symbol) d.append(name) if spacing_bottom + legend_height - ( offset) - symbol_y_shift > spacing_bottom: symbol_y_shift += offset + symbol_size else: symbol_y_shift = 0 return d
def draw(self, save=False, retEls=False, off=(0, 0)): els = [] d = draw.Drawing(1.2 * self.width, 1.2 * self.height, origin=self.origin) self.dim_sorted() hstep = self.width / len(self.dims) for i in range(len(self.dims)): l = draw.Line(off[0] + self.width - i * hstep, off[1] + 0, off[0] + self.width - i * hstep, off[1] + self.height, stroke="black", stroke_width=2, fill=None) els.append(l) for dim, count in self.dims.items(): for i in range(count): vstep = self.height / count c = draw.Circle(off[0] + self.width - dim * hstep, off[1] + vstep * i, self.diam, fill="blue", stroke_width=2, stroke="black") els.append(c) for dif in self.diff: base = dif["0"] coefs = dif["coefs"] vstep = self.height / self.dims[base[0]] baseCoor = (off[0] + self.width - base[0] * hstep, off[1] + vstep * base[1]) middle = lambda x, y: (x[0] / 2 + y[0] / 2, x[1] / 2 + y[1] / 2 + 10) for gen, coef in coefs.items(): vstep = self.height / self.dims[base[0] - 1] endCoor = (off[0] + self.width - (base[0] - 1) * hstep, off[1] + vstep * gen) l = draw.Line(*baseCoor, *endCoor, stroke="grey", stroke_width=1, fill=None) els.append(l) p = draw.Path(stroke_width=2, stroke='lime', fill='black', fill_opacity=0.2) p.M(*baseCoor) # Start path at point (-10, 20) p.L(*endCoor) # Draw a curve to (70, 20) if coef != 1: text = draw.Text(str(coef), 12, *middle(baseCoor, endCoor), text_anchor='start', valign='middle') els.append(text) if retEls: return els else: for el in els: d.append(el) return d
current_wall = map_file.walls[sector.wall_pointer] for _ in range(sector.wall_number): bounds.extend((current_wall.x, current_wall.y)) current_wall = map_file.walls[current_wall.point2] print(bounds) d = drawSvg.Drawing(65000, 65000, origin='center') for sector in map_file.sectors: current_wall = map_file.walls[sector.wall_pointer] current_point = current_wall.x, current_wall.y first_point = current_point p = drawSvg.Path(stroke_width=4, stroke='black') p.M(*current_point) for _ in range(sector.wall_number): next_wall = map_file.walls[current_wall.point2] next_point = next_wall.x, next_wall.y p.L(*next_point) current_wall = next_wall p.L(*first_point) p.Z() d.append(p) d.saveSvg('/Users/Joshua/Desktop/e1l1.svg') sys.exit(0)