def create_from_config(self, svg_name='avatar'): """Create an avatar SVG from the configuration. TODO: * Deprecate in favor of request param based view using templates. """ payload = self.config icon_width = self.ICON_SIZE[0] icon_height = self.ICON_SIZE[1] components = [ icon_width, icon_height, Line([(0, icon_height / 2), (icon_width, icon_height / 2)], width=f'{icon_height}px', color=f"#{payload.get('Background')}") ] for k, v in payload.items(): if k not in [ 'Background', 'ClothingColor', 'HairColor', 'SkinTone' ]: components.append( build_avatar_component( f"{v.get('component_type')}/{v.get('svg_asset')}", self.ICON_SIZE)) with NamedTemporaryFile(mode='w+', suffix='.svg') as tmp: avatar = Figure(*components) avatar.save(tmp.name) with open(tmp.name) as file: if self.profile_set.exists(): svg_name = self.profile_set.last().handle self.svg.save(f"{svg_name}.svg", File(file), save=True)
def create_pensive_cowboy_emoji(self, input, output_dir, offset): """ Takes an emoji as input and applies a cowboy hat, then puts it in a city and tells it some bad news. """ print(f"pensiving and cowboyfy-ing {input}.... haw yee.") # create output path, if it doesn't exist Path(output_dir).mkdir(parents=True, exist_ok=True) # get filename without path or extension input_filename = Path(input).stem # load input svg input_file = sg.fromfile(input) # move input slightly down input_root = input_file.getroot() input_root.moveto(0, offset) # load the all knowing pensive face svg. all_knowing_face = sg.fromfile('res/pensive.svg') # move pensive face to same spot as input svg all_knowing_root = all_knowing_face.getroot() # the pensive face is 20x26, so account for that and move it, move it. all_knowing_root.moveto(5, offset + 8) # apply the offset to the expected height final_height = self.standard_size + offset # overlay the emojis on a workspace and save that as an output svg Figure(f"{self.standard_size}px", f"{final_height}px", input_root, self.all_powerful_root, all_knowing_root).save(f"{output_dir}/{input_filename}.svg")
def concatenate_svgs( svgs, max_columns=None, scale=None, label=False, size=12, weight="bold", inset=(0.1, 0.1), ): """Create a grid of SVGs, with a maximum number of columns. Parameters ---------- svgs : list Items may be raw SVG strings, or any objects with a ``tostring`` or ``to_str`` method. max_columns : int or None max number of columns, or if None, only use one row scale : float or None scale the entire composition label : bool whether to add a label for each SVG (cycle through upper case letters) size : int label font size weight : str label font weight inset : tuple inset the label by x times the SVG width and y times the SVG height Returns ------- svgutils.compose.Figure """ # TODO could replace svgutils with use of lxml primitives from svgutils.compose import Figure, Text label_iter = cycle("ABCDEFGHIJKLMNOPQRSTUVWXYZ") svg_composes, dimensions = zip( *[string_to_compose(get_svg_string(svg)) for svg in svgs]) if scale: [svg.scale(scale) for svg in svg_composes] dimensions = [(w * scale, h * scale) for (w, h) in dimensions] (width, height), positions = tessellate_rectangles(dimensions, max_columns) elements = [] for svg, (x, y), (w, h) in zip(svg_composes, positions, dimensions): elements.append(svg.move(x, y)) if label: elements.append( Text( next(label_iter), x=x + inset[0] * w, y=y + inset[1] * h, size=size, weight=weight, )) return Figure(width, height, *elements)
def stack_svgs(file_list, opt_file=None, canvas_size=None): """ Stack materials into a .svg image Support .png material only """ import cairosvg from svgutils.compose import Figure, Image #,SVG if not opt_file: opt_file = 'stack.svg' if canvas_size: canvas_w, canvas_h = canvas_size else: canvas_w, canvas_h = 0, 0 for file in file_list: width, height = get_size(file) if width > canvas_w: canvas_w = width if height > canvas_h: canvas_h = height print('Canvas size:', (canvas_w, canvas_h)) # if svg, convert to png first file_list_png = [] for file in file_list: basename, ext = os.path.splitext(file) if ext == '.svg': png_file = basename + '.png' cairosvg.svg2png(url=file, write_to=png_file) file_list_png.append(png_file) elif ext == '.png': file_list_png.append(file) else: raise ValueError('File type not availale!') image_list = [] # for file in file_list_png: print('File:', file) width, height = get_size(file) img = Image(width, height, file) img.move(int((canvas_w-width)/2), int((canvas_h-height)/2)) image_list.append(img) Figure(canvas_w, canvas_h, *image_list).save(opt_file)
def create_cowboy_emoji(self, input, output_dir, offset): """ Takes an emoji as input and applies a cowboy hat. Yeah, I'm glad it exists too. """ print(f"cowboyfy-ing {input}.... yee haw.") # create output path, if it doesn't exist Path(output_dir).mkdir(parents=True, exist_ok=True) # get filename without path or extension input_filename = Path(input).stem # load input svg input_file = sg.fromfile(input) # move input slightly down input_root = input_file.getroot() input_root.moveto(0, offset) # apply the offset to the expected height final_height = self.standard_size + offset # overlay the emojis on a workspace and save that as an output svg Figure( f"{self.standard_size}px", f"{final_height}px", input_root, self.all_powerful_root).save(f"{output_dir}/{input_filename}.svg")
def build_avatar_svg(svg_path='avatar.svg', line_color='#781623', icon_size=None, payload=None, temp=False): from .models import BaseAvatar icon_size = icon_size or BaseAvatar.ICON_SIZE icon_width = icon_size[0] icon_height = icon_size[1] if payload is None: # Sample payload payload = { 'background_color': line_color, 'icon_size': BaseAvatar.ICON_SIZE, 'avatar_size': None, 'skin_tone': '#3F2918', 'ears': { 'item_type': '0', }, 'clothing': { 'primary_color': '#18C708', 'item_type': 'cardigan', }, 'head': { 'item_type': '0', }, 'hair': { 'primary_color': '#29F998', 'item_type': '0', }, 'mouth': '0', 'nose': '0', 'eyes': '0', 'wallpaper': None } # Build the list of avatar components components = [ icon_width, icon_height, Line([(0, icon_height / 2), (icon_width, icon_height / 2)], width=f'{icon_height}px', color=payload.get('background_color')), ] customizable_components = ['clothing', 'ears', 'head', 'hair'] flat_components = ['eyes', 'mouth', 'nose', 'wallpaper'] multi_components = ['accessories'] for component in customizable_components: if component in payload: primary_color = payload.get( component, {}).get('primary_color') or payload.get('skin_tone') components.append( build_temporary_avatar_component( component_category=component, component_type=payload.get(component, {}).get('item_type', 'cardigan'), primary_color=primary_color, )) for component in flat_components: if component in payload: components.append( build_avatar_component( f"{component.title()}/{payload.get(component, '0')}.svg", icon_size)) for component in multi_components: if component in payload: components.append( build_avatar_component( f"{component.title()}/{payload.get(component)}")) final_avatar = Figure(*components) if temp: return final_avatar result_path = f'{COMPONENT_BASE}{svg_path}' final_avatar.save(result_path) return result_path
def plot_locus(grange, groupby, cellannot, files, size_factor='rdepth', tag='RG', mapq=10, frames_before=None, frames_after=None, normalize=True, palettes=sc.pl.palettes.vega_20_scanpy, add_total=True, style='fill', binsize=50, binarize=False, frame_width=40, add_labels=True, width_overlap=18., extend_window=0, save=None, **kwargs): if isinstance(grange, dict): names = [k for k in grange] ranges = [grange[k] for k in grange] elif not isinstance(grange, list): ranges = [grange] names = [''] elif isinstance(grange, list): names = [''] * len(grange) ranges = granges if frames_before is None: frames_before = Frame() if extend_window > 0: ranges = [_extend(gr, extend_window) for gr in ranges] with tempfile.TemporaryDirectory() as tmpdir: for i, (name, gr) in enumerate(zip(names, ranges)): sct = SingleCellTracks(cellannot, files, size_factor=size_factor, tag=tag, mapq=mapq) frame = copy.deepcopy(frames_before) frame.properties['title'] = name fig = sct.plot(gr, groupby, frames_before=frame, frames_after=frames_after, normalize=normalize, palettes=palettes, add_total=add_total, style=style, binsize=binsize, add_labels=add_labels if i == (len(names) - 1) else False, binarize=binarize, **kwargs) fig.savefig(os.path.join(tmpdir, f'{name}_{gr}.svg')) panel = SVG(os.path.join(tmpdir, f'{name}_{gr}.svg')) width, height = panel.width, panel.height composite_figure = Figure( f"{(width-width_overlap)*len(names)+width_overlap}pt", f"{height}pt", *[ SVG(os.path.join(tmpdir, f'{name}_{gr}.svg')).move( (width - width_overlap) * i, 0) for i, (name, gr) in enumerate(zip(names, ranges)) ]) if save is not None: composite_figure.save(save) os.makedirs(save.split('.')[0], exist_ok=True) for name, gr in zip(names, ranges): shutil.copy(os.path.join(tmpdir, f'{name}_{gr}.svg'), save.split('.')[0]) return composite_figure
#!/usr/bin/env python #coding=utf-8 from sys import argv from svgutils.compose import Figure, SVG Figure( 20, 20, SVG(argv[1]), SVG(argv[2]), ).save(argv[3])
def pyx_script_pmsm(ad, best_chromosome, best_idx, Q, p, proj_name): if proj_name is None: name = 'Q%dp%didx%d' % (Q, p, best_idx) else: name = 'Q%dp%didx%d%s' % (Q, p, best_idx, proj_name) # output location 1 filename_cross_sectional_view = "../_pemd2020/%s.svg" % ( "Figure_selected_optimal_design_%s" % (name)) # output location 2 filename_cross_sectional_view = ad.solver.output_dir + "%s.svg" % ( "Figure_selected_optimal_design_%s" % (name)) # output location 3 filename_cross_sectional_view = '../release/' + "%s.svg" % ( "Figure_selected_optimal_design_%s" % (name)) # Plot cross section view import bearingless_spmsm_design spmsm_best = bearingless_spmsm_design.bearingless_spmsm_design( spmsm_template=ad.spec.acm_template, x_denorm=best_chromosome[:-3], counter=999, counter_loop=1) spmsm_best.ID = name import VanGogh tool_tikz = VanGogh.VanGogh_TikZPlotter() spmsm_best.draw_spmsm( tool_tikz, bool_pyx=True) # collecting track_path list for tool_tikz # 就算可以直接画出来,也只有最小部分而已,没有做镜像和旋转! # tool_tikz.c.writePDFfile("../test"+proj_name) # tool_tikz.c.writeEPSfile("Figure_selected_optimal_design_%s"%(name)) tool_tikz.c.writePDFfile(filename_cross_sectional_view[:-4]) tool_tikz.c.writeSVGfile("../a") # print('Write to pdf file:', "../test"+proj_name) # raise Exception('DEBUG HERE') tool_tikz.c = pyx.canvas.canvas() # Use tool_tikz.track_path to redraw the model def redraw_cross_section_outline_with_pyx(tool_tikz, no_repeat_stator, no_repeat_rotor, mm_rotor_outer_radius, mm_air_gap_length, mm_rotor_outer_steel_radius, mm_rotor_inner_radius): # PyX tool_tikz.c = pyx.canvas.canvas( ) # clear the canvas because we want to redraw 90 deg with the data tool_tikz.track_path print('Index | Path data') p_stator = None #pyx.path.path() p_rotor = None #pyx.path.path() for index, path in enumerate( tool_tikz.track_path ): # track_path is passed by reference and is changed by mirror # Failed to fill the closed path, because there is no arc-like path available. # p = pyx.path.line(4, 0, 5, 0) << pyx.path.line(5, 0, 5, 1) << pyx.path.line(5, 1, 4, 1) # p.append(path.closepath()) # tool_tikz.c.stroke(p) # tool_tikz.c.stroke(path.rect(0, 0, 1, 1), [pyx.style.linewidth.Thick, # pyx.color.rgb.red, # pyx.deco.filled([pyx.color.rgb.green])]) path_mirror = deepcopy(path) # for mirror copy (along x-axis) path_mirror[1] = path[1] * -1 path_mirror[3] = path[3] * -1 # for mirror copy (along y-axis) # path_mirror[0] = path[0]*-1 # path_mirror[2] = path[2]*-1 bool_exclude_path = False # rotate path and plot if is_at_stator(path, mm_rotor_outer_radius, mm_air_gap_length): Q = no_repeat_stator else: Q = no_repeat_rotor * 2 EPS = 1e-6 if is_at_stator(path, mm_rotor_outer_radius, mm_air_gap_length): # 按照Eric的要求,把不必要的线给删了。 if abs(path[1] + path[3]) < EPS: # 镜像对称线 bool_exclude_path = True if abs(path[0] - path[2]) + np.cos( 2 * np.pi / Q / 2) < EPS: # 旋转对称线(特别情况,tan(90°) = ∞ bool_exclude_path = True else: if abs( abs((path[1] - path[3]) / (path[0] - path[2])) - abs(np.tan(2 * np.pi / Q / 2))) < EPS: # 旋转对称线 bool_exclude_path = True if not is_at_stator(path, mm_rotor_outer_radius, mm_air_gap_length): # 按照Eric的要求,把不必要的线给删了。 if (abs(np.sqrt(path[0]**2+path[1]**2) - mm_rotor_inner_radius)<EPS or abs(np.sqrt(path[2]**2+path[3]**2) - mm_rotor_inner_radius)<EPS) \ and (len(path)==4): # 转子铁芯内径到外径的直线(len(path)==4) bool_exclude_path = True # # 特别的是,画永磁体的时候,边界要闭合哦。 # if abs(np.sqrt(path[0]**2+path[1]**2) - mm_rotor_outer_steel_radius) < EPS or abs(np.sqrt(path[2]**2+path[3]**2) - mm_rotor_outer_steel_radius) < EPS: # bool_exclude_path = False # A trick that makes sure models with different outer diameters have the same scale. # tool_tikz.draw_arc([125,0], [-125,0], relangle=sign*180, untrack=True) tool_tikz.c.fill( pyx.path.circle(0, 0, 125), [pyx.color.transparency(1)] ) # use this if THICK is used. <- Warn: Transparency not available in PostScript, proprietary ghostscript extension code inserted. (save as eps format) # tool_tikz.c.fill(pyx.path.circle(0, 0, 125), [pyx.color.rgb.white]) # use this if THICK is used. <- this will over-write everthing... how to change zorder? _ = 2 * np.pi / Q if True: # full model for counter in range(Q): # 转子:旋转复制 if not is_at_stator(path, mm_rotor_outer_radius, mm_air_gap_length): path[0], path[1] = rotate(_, path[0], path[1]) path[2], path[3] = rotate(_, path[2], path[3]) 路径 = tool_tikz.pyx_draw_path( path, sign=1, bool_exclude_path=bool_exclude_path, bool_stroke=True) if 路径 is not None: if p_rotor is None: p_rotor = 路径 else: p_rotor = p_rotor << 路径 # 定子:镜像+旋转复制 if is_at_stator(path, mm_rotor_outer_radius, mm_air_gap_length): path[0], path[1] = rotate(_, path[0], path[1]) path[2], path[3] = rotate(_, path[2], path[3]) 路径 = tool_tikz.pyx_draw_path( path, sign=1, bool_exclude_path=bool_exclude_path, bool_stroke=True) # print(index, '\t|', ',\t'.join(['%g'%(el) for el in path])) if 路径 is not None: if p_stator is None: p_stator = 路径 else: p_stator = p_stator << 路径 path_mirror[0], path_mirror[1] = rotate( _, path_mirror[0], path_mirror[1]) path_mirror[2], path_mirror[3] = rotate( _, path_mirror[2], path_mirror[3]) 路径 = tool_tikz.pyx_draw_path( path_mirror, sign=-1, bool_exclude_path=bool_exclude_path, bool_stroke=True) if 路径 is not None: if p_stator is None: p_stator = 路径 else: p_stator = p_stator << 路径 # break else: # backup # 转子:旋转复制 if not is_at_stator(path, mm_rotor_outer_radius, mm_air_gap_length): path[0], path[1] = rotate(0.5 * np.pi - 0.5 * 0.5 * _, path[0], path[1]) path[2], path[3] = rotate(0.5 * np.pi - 0.5 * 0.5 * _, path[2], path[3]) pyx_draw_path(tool_tikz, path, sign=1, bool_exclude_path=bool_exclude_path) # print(index, '\t|', ',\t'.join(['%g'%(el) for el in path])) # path[0], path[1] = rotate(0.5*np.pi - 0*0.5*_, path[0], path[1]) # path[2], path[3] = rotate(0.5*np.pi - 0*0.5*_, path[2], path[3]) # pyx_draw_path(tool_tikz, path, sign=1, bool_exclude_path=bool_exclude_path) # 定子:镜像+旋转复制 if is_at_stator(path, mm_rotor_outer_radius, mm_air_gap_length): path[0], path[1] = rotate(0.5 * np.pi - 0.5 * _, path[0], path[1]) path[2], path[3] = rotate(0.5 * np.pi - 0.5 * _, path[2], path[3]) pyx_draw_path(tool_tikz, path, sign=1, bool_exclude_path=bool_exclude_path) # print(index, '\t|', ',\t'.join(['%g'%(el) for el in path])) path_mirror[0], path_mirror[1] = rotate( 0.5 * np.pi - 0.5 * _, path_mirror[0], path_mirror[1]) path_mirror[2], path_mirror[3] = rotate( 0.5 * np.pi - 0.5 * _, path_mirror[2], path_mirror[3]) pyx_draw_path(tool_tikz, path_mirror, sign=-1, bool_exclude_path=bool_exclude_path) # 注意,所有 tack_path 中的 path 都已经转动了90度了! # for mirror copy (along y-axis) path[0] *= -1 path[2] *= -1 pyx_draw_path(tool_tikz, path, sign=-1, bool_exclude_path=bool_exclude_path) path_mirror[0] *= -1 path_mirror[2] *= -1 pyx_draw_path(tool_tikz, path_mirror, sign=1, bool_exclude_path=bool_exclude_path) # You can have a cool logo if you un-comment this... # tool_tikz.c.fill(p_stator, [pyx.color.gray(0.8)]) # tool_tikz.c.fill(p_rotor, [pyx.color.gray(0.4)]) # tool_tikz.c.stroke(p_stator) # tool_tikz.c.stroke(p_rotor) if True: # Draw the outline? redraw_cross_section_outline_with_pyx( tool_tikz, spmsm_best.Q, spmsm_best.p, spmsm_best.Radius_OuterRotor, spmsm_best.Length_AirGap, spmsm_best.Radius_OuterRotorSteel, spmsm_best.Radius_InnerRotor) # tool_tikz.c.writePDFfile("../Test_Fill_Plot" + proj_name) tool_tikz.c.writeSVGfile("../b") tool_tikz.c.writePDFfile(filename_cross_sectional_view[:-4] + 'outline') print('Final cross sectional outline files are printed to', filename_cross_sectional_view[:-4] + 'outline') # tool_tikz.c.writePDFfile("Figure_selected_optimal_design_%s"%(name)) # tool_tikz.c.writeEPSfile("Figure_selected_optimal_design_%s"%(name)) # tool_tikz.c.writeSVGfile("Figure_selected_optimal_design_%s"%(name)) # print('Write to pdf file: Figure_selected_optimal_design_%s.pdf.'%(name)) # os.system('start %s'%("selected_optimal_design%s.pdf"%(spmsm_best.name))) # quit() # Option 1 if True: from svgutils.compose import Figure, SVG # https://svgutils.readthedocs.io/en/latest/tutorials/composing_multipanel_figures.html Figure( "5cm", "5cm", SVG("../a.svg"), SVG("../b.svg"), # the order of a and b matters. ).save(filename_cross_sectional_view) os.system( 'inkscape --file=%s --export-area-drawing --without-gui --export-pdf=%s.pdf' % (filename_cross_sectional_view, filename_cross_sectional_view[:-4])) else: # Option 2 import svgutils.transform as sg #create new SVG figure fig = sg.SVGFigure("16cm", "6.5cm") # load matpotlib-generated figures fig1 = sg.fromfile('../a.svg') fig2 = sg.fromfile('../b.svg') # get the plot objects plot1 = fig1.getroot() plot2 = fig2.getroot() # plot2.moveto(280, 0, scale=0.5) # append plots and labels to figure fig.append([plot1, plot2]) fig.save("../d.svg")