def panel4x4(fn0, fn1, fn2, fn3, fn_out): single_size = plot_config.single_figure_size sc.Figure( str(single_size[0] * 150) + "px", str(single_size[1] * 150) + "px", sc.Panel(sc.SVG(fn0).scale(1.0).move(0, 0)), sc.Text("A", 5, 25, size=plot_config.fontsize_xhuge, weight='bold'), sc.Panel(sc.SVG(fn1).scale(1.0).move(single_size[0] * 150 / 2., 0)), sc.Text("B", single_size[0] * 150 / 2 + 5., 25, size=plot_config.fontsize_xhuge, weight='bold'), sc.Panel(sc.SVG(fn2).scale(1.0).move(0, single_size[1] * 150 / 2.)), sc.Text("C", 5, single_size[1] * 150 / 2. + 25, size=plot_config.fontsize_xhuge, weight='bold'), sc.Panel( sc.SVG(fn3).scale(1.0).move(single_size[0] * 150 / 2., single_size[1] * 150 / 2.)), sc.Text("D", single_size[0] * 150 / 2. + 5, single_size[1] * 150 / 2. + 25, size=plot_config.fontsize_xhuge, weight='bold'), ).save(fn_out)
def plot(self, gr1=None, gr2=None): """ Parameters ---------- gr1 : {str, GenomeRange} First genome range gr2 : {str, GenomeRange}, optional Second genome range """ frame2grange = self.frame_granges(gr1, gr2) gr1, gr2 = self.current_range sub_frames = self.properties['sub_frames'] frame_svgs = self.plot_frames(frame2grange) center_svg = self.plot_center(gr1, gr2) center_offsets = self.__get_center_offsets(sub_frames) center_svg.move(*self.cm2px(center_offsets)) self.__transform_sub_svgs(frame_svgs, sub_frames, center_offsets) figsize = self.cm2px(self.__get_figsize(sub_frames)) fig = sc.Figure(f"{figsize[0]}px", f"{figsize[1]}px", sc.Panel(center_svg), *[sc.Panel(svg) for svg in frame_svgs.values()]) return fig
def plot_analysis(self, display=True): figdir = set_figdir(verbose=False) figure_name = f"{figdir}/{timestamp()}-analysis.svg" fig_handles = [ self.plot_singular_vals(savefig=True, verbose=False, display=False)[-1], self.plot_eigs(savefig=True, verbose=False, display=False)[-1], self.plot_power_spectrum(savefig=True, verbose=False, display=False)[-1] ] svgs = [] for fig in fig_handles: svgs.append(sc.SVG(fig + '.svg', fix_mpl=True)) os.remove(f"{fig}.svg") sc.Figure( sum(svg.width for svg in svgs), max([svg.height for svg in svgs]), sc.Panel(svgs[0], sc.Text("(a)", 6, 16, size=11)).move(0, 0), sc.Panel(svgs[1], sc.Text("(b)", 6, 16, size=11)).move(svgs[0].width, 0), sc.Panel(svgs[2], sc.Text("(c)", 6, 16, size=11)).move(svgs[0].width + svgs[1].width, 0)).save(figure_name) if display: IPython.display.display(IPython.display.SVG(figure_name))
def layout(codes, filename): """export pdf A4 pages filled with these barcodes, so that they can be printed as stickers filename will prefix temporary files produced and removed during the process, it shouldn't have any extension TODO: I guess it's possible achieving this without creating so many intermediate files. Try to get rid of them ;) """ # A4 sheet_size = WH(210., 297.) * XY.mm sticker_size = EAN13Data.full_size # so how many codes fit on one sheet? n_stickers = sheet_size / sticker_size n_stickers = np.floor(n_stickers).astype(int) stickers_per_sheet = n_stickers.w * n_stickers.h # so how many sheets do we need? n_sheets = ceil(len(codes) / stickers_per_sheet) sheets = [] # store produced .pdf sheets filenames here # iterate until they are all consumed stickers = iter(codes) for n in range(n_sheets): panels = [] # according to sc logic try: for i in range(n_stickers.w): for j in range(n_stickers.h): # export this code as svg temp file code = next(stickers) tpfile = code.id + '.svg' code.draw(tpfile) panels.append( sc.Panel( sc.SVG(tpfile).scale(1.).move( i * sticker_size.w, j * sticker_size.h))) # cleanup os.remove(tpfile) except StopIteration: pass # no more stickers to print sheetname = filename + ('-' + str(n + 1) if n_sheets > 1 else '') ssvg = sheetname + '.svg' spdf = sheetname + '.pdf' sc.Figure(sheet_size.w, sheet_size.h, *panels).save(ssvg) # convert to .pdf renderPDF.drawToFile(svg2rlg(ssvg), spdf) # remove .svg file os.remove(ssvg) # remember this other temp file sheets.append(spdf) # bring all sheets together into pdf pages if n_sheets > 1: final = PdfFileWriter() for sheet in sheets: append_pdf(PdfFileReader(sheet), final) final.write(open(filename + '.pdf', 'wb')) # so we can now supress them while sheets: os.remove(sheets.pop())
def panel2x2(fn0, fn1, fn_out, single_size=plot_config.single_figure_size): sc.Figure( str(single_size[0] * 150) + "px", str(single_size[1] * 80) + "px", sc.Panel(sc.SVG(fn0).scale(1.0).move(0, 15)), sc.Text("A", 4, 12, size=plot_config.fontsize_large, weight='bold', font='serif'), sc.Panel(sc.SVG(fn1).scale(1.0).move(single_size[0] * 150 / 2., 15)), sc.Text("B", single_size[0] * 150 / 2 + 4., 12, size=plot_config.fontsize_large, weight='bold', font='serif')).save(fn_out)
def compose_svg(svg_board, svg_plot, svg_combined): """ Create a combined SVG in which the board image is put in the background of the axes area of the plot image. :param svg_board: filename of existing board image :type svg_board: str :param svg_plot: filename of existing plot image :type svg_plot: str :param svg_combined: filename of combined image, to be written :type svg_combined: str """ scale = TOP_RIGHT_MARGIN - LEFT_BOTTOM_MARGIN xdel = LEFT_BOTTOM_MARGIN * SIZE ydel = (1.0 - TOP_RIGHT_MARGIN) * SIZE compose.Figure( SIZE, SIZE, compose.Panel(compose.SVG(svg_board).scale(scale).move(xdel, ydel)), compose.Panel(compose.SVG(svg_plot))).save(svg_combined)
def draw_plot(data, output): """Draws piecharts from given data on lab012 background Args: data - list of lists of three points with experiment results output - name of generated svg file """ positions = [[1.6, 1], [1.6, 3], [1.6, 5], [5, 1], [5, 3], [5, 5], [8.7, 1], [8.7, 3], [8.7, 5], [12, 1], [12, 3], [12, 5]] # prepare background fig, ax = plt.subplots() ax.imshow([[[0, 0, 0, 0]], [[0, 0, 0, 0]]], extent=[-1, 13.25, -1, 7.3]) ax.patch.set_alpha(0.0) ax.axis('off') # robot blob draw_single_pie([1.3, 5.7], 0.3, [1, 1, 1], ax, ('k', 'k', 'k'), plot_labels=False) ax.text(1.6, 5.9, "Mikrofon") # draw points for i, d in enumerate(zip(positions, data)): draw_single_pie(d[0], 0.5, d[1], ax, ('blue', 'orange', 'green'), str(i + 1)) # save fig.tight_layout() fig.savefig("out.svg", dpi=200, transparent=True) # merge with proper background sc.Figure("247.59521mm", "129.31232mm", sc.Panel(sc.SVG("./assets/012-base.svg").scale(0.352)), sc.Panel(sc.SVG("out.svg").scale(0.6).move(-25, -40))).save(output) os.remove("./out.svg")
def make_multipanel_fig(FIGS, CAP_SIZE=14,\ fig_name="fig.svg",\ transparent=True, correc_factor=70., DPI=100.): """ take a list of figures and make a multi panel plot""" label = list(string.ascii_uppercase)[:len(FIGS)] SIZE = [] for fig in FIGS: SIZE.append(fig.get_size_inches()) width = np.max([s[0] for s in SIZE]) height = np.max([s[1] for s in SIZE]) LABELS, XCOORD, YCOORD, SCALE = [], [], [], [] for i in range(len(FIGS)): ff = 'f.svg' FIGS[i].savefig('/tmp/' + str(i) + '.svg', format='svg', transparent=transparent) if translate_to_bitmap_if_too_big(FIGS[i], '/tmp/' + str(i) + '.svg'): SCALE.append(.7) else: SCALE.append(1.) LABELS.append(label[i]) XCOORD.append((i % 3) * width * correc_factor) YCOORD.append(int(i / 3) * height * correc_factor) PANELS = [] for i in range(len(FIGS)): PANELS.append(sg.Panel(\ sg.SVG('/tmp/'+str(i)+'.svg').move(XCOORD[i],YCOORD[i]).scale(SCALE[i]),\ sg.Text(LABELS[i], 25, 20, size=22, weight='bold').move(\ XCOORD[i]-15,YCOORD[i]))\ ) sg.Figure(str((min(len(FIGS)%3,3))*inch_to_cm(width))+"cm",\ str(inch_to_cm(height)*(int(len(FIGS)/3.01)+1))+"cm",\ *PANELS).save(fig_name)
def put_list_of_figs_to_svg_fig( FIGS, fig_name="fig.svg", initial_guess=True, visualize=False, export_as_png=False, Props=None, figsize=None, fontsize=9, SCALING_FACTOR=1.34, # needed to get the right cm size ... with_top_left_letter=False, transparent=True): """ take a list of figures and make a multi panel plot""" label = list(string.ascii_uppercase)[:len(FIGS)] SIZE = [] for fig in FIGS: if type(fig) == str: SIZE.append([1., 1.]) else: SIZE.append(fig.get_size_inches()) width = np.max([s[0] for s in SIZE]) height = np.max([s[1] for s in SIZE]) if Props is None: LABELS, XCOORD, YCOORD = [], [], [] # saving as svg for i in range(len(FIGS)): LABELS.append(label[i]) XCOORD.append((i % 3) * width * 100) YCOORD.append(int(i / 3) * height * 100) XCOORD_LABELS,\ YCOORD_LABELS = XCOORD, YCOORD else: XCOORD, YCOORD = Props['XCOORD'],\ Props['YCOORD'], if 'LABELS' in Props: LABELS = Props['LABELS'] else: LABELS = ['' for x in XCOORD] if 'XCOORD_LABELS' in Props: XCOORD_LABELS,\ YCOORD_LABELS = Props['XCOORD_LABELS'],\ Props['YCOORD_LABELS'] else: XCOORD_LABELS,\ YCOORD_LABELS = XCOORD, YCOORD LOCATIONS = [] for i in range(len(FIGS)): if type(FIGS[i]) is str: LOCATIONS.append(FIGS[i]) else: LOCATIONS.append(os.path.join(gettempdir(), str(i) + '.svg')) FIGS[i].savefig(LOCATIONS[-1], format='svg', transparent=transparent) PANELS = [] for i in range(len(FIGS)): PANELS.append(sg.Panel(\ sg.SVG(LOCATIONS[i]).move(XCOORD[i],YCOORD[i]))) for i in range(len(LABELS)): PANELS.append(sg.Panel(\ sg.Text(LABELS[i], 15, 10, size=fontsize, weight='bold').move(\ XCOORD_LABELS[i],YCOORD_LABELS[i]))\ ) sg.Figure("21cm", "29.7cm", *PANELS).scale(SCALING_FACTOR).save(fig_name) # if figsize is None: # sg.Figure("21cm", "29.7cm", *PANELS).save(fig_name) # else: # sg.Figure(str(inch2cm(figsize[0]*A0_format['width'])[0])+"cm",\ # str(inch2cm(figsize[1]*A0_format['height'])[0])+"cm",\ # *PANELS).scale(SCALING_FACTOR).save(fig_name) if visualize: os.system('open ' + fig_name) # works well with 'Gapplin' on OS-X
def main(self): settings = self.settings SMILESSTRING = settings['SMILESSTRING'] resulting_plots = [] pRList = [] mol_svg, d2d, dm = self.draw_smiles() replace_index = [] for scope_plot in self.plots: # for each scope plot, make a vals list containing empty first items for the wedge with alpha=0 if type(scope_plot) != dict: continue sizes = [ 360 - scope_plot['coverangle_wedges'] ] + [scope_plot['coverangle_wedges'] / scope_plot['no_wedges'] ] * scope_plot['no_wedges'] label_inner_circle, label_outer_circle = [ '' ] + [''] * scope_plot['no_wedges'], [ '' ] + [''] * scope_plot['no_wedges'] if (len(scope_plot['value_inner_circle']) != scope_plot['no_wedges'] or len(scope_plot['value_outer_circle']) != scope_plot['no_wedges']): print('not equal') value_inner_circle, value_outer_circle = scope_plot[ 'value_inner_circle'], scope_plot['value_outer_circle'] rounding_boundary = scope_plot['rounding_boundary'] value_groups = scope_plot['value_groups'] for i in range(scope_plot['no_wedges']): if scope_plot['rounding']: if value_inner_circle[i] >= rounding_boundary: label_inner_circle[i + 1] = ">" + str( value_inner_circle[i]) else: label_inner_circle[i + 1] = str(value_inner_circle[i]) if value_outer_circle[i] >= rounding_boundary: label_outer_circle[i + 1] = ">" + str( value_outer_circle[i]) else: label_outer_circle[i + 1] = str(value_outer_circle[i]) else: label_inner_circle[i + 1] = str(value_inner_circle[i]) label_outer_circle[i + 1] = str(value_outer_circle[i]) j = 0 for i, item in enumerate(value_groups): if item[0] == '~': replace_index.append(('~' + str(j), item[1:])) value_groups[i] = '~' + str(j) j = j + 1 vals = [ sizes, # size of the wedges, the first wedge is transparent and will not be shown [0] + value_inner_circle, # colormap values for the inner circle, maximum value determines intensity, first is for the transparent wedge and should stay 0 [0] + value_outer_circle, # colormap values for the outer circle, maximum value determines intensity, first is for the transparent wedge and should stay 0 label_inner_circle, #labels for the inner circle label_outer_circle, #labels for the outer circle [""] + value_groups, #groups ] resulting_plots.append( self.plot_figure_and_colorbar(scope_plot, vals)) # get the atom id from the settings and save its position rIdx = scope_plot['attach_atom_id'] pRList.append( d2d.GetDrawCoords( Geometry.Point2D(dm.GetConformer().GetAtomPosition(rIdx)))) # take colorbar from first plot #ToDo extension to multiple colorbars colorbar = compose.Panel( strSVG(resulting_plots[0][1]).scale(0.8).move(-350, 400)) panels = [compose.Panel(strSVG('<svg></svg>'))] * len(resulting_plots) for i, plot in enumerate(resulting_plots): panels[i] = strSVG(resulting_plots[i][0]).move( -369, -358).scale(1).move(pRList[i].x, pRList[i].y) #panels[i]=strSVG(resulting_plots[i][0]).move(-369*1,-358*1).scale(0.4).move(pRList[i].x,pRList[i].y) compose.Figure( "600", "600", #720 default` compose.Panel(strSVG(mol_svg).scale(1).move(0, 0)), colorbar, *panels #).move(350,350).scale(self.settings['scalefactor']).save("substrate_scope.svg") ).move(350, 100).scale( self.settings['scalefactor']).save("substrate_scope.svg") new_svg = SVG('substrate_scope.svg')._data for item in replace_index: new_svg = self.replace_label_with_smiles(svg_file=new_svg, smiles=item[1], search_index=item[0]) if settings['use_bold_font']: new_svg.replace('font-weight:normal', 'font-weight:bold') f = open("substrate_scope_replaced.svg", "w") f.write(new_svg) f.close() print('File written to:', os.getcwd() + '/substrate_scope_replaced.svg')
def multipanel_figure(graph_env, FIGS, X = None, Y = None, Labels=None, LABELS = None, X_LABELS = None, Y_LABELS = None, width=85.,# mm height=None, # mm grid=False, autoposition=False, SCALING_FACTOR = 1.34, fontsize=None, fontweight='bold', export_to_png=False, bg='white', fig_name='fig.svg'): """ """ # building the figure matrix if not explicited if type(FIGS) is mpl.figure.Figure: FIGS = [[FIGS]] elif type(FIGS) is list: if (len(FIGS)>0) and (type(FIGS[0]) is mpl.figure.Figure): FIGS = [FIGS] elif (len(FIGS)>0) and (type(FIGS[0]) is str): FIGS = [FIGS] # else should be list of list if autoposition: X, Y = [], [] y = [0] for i, lfig in enumerate(FIGS): Y.append([np.max(y) for fig in lfig]) x = [] for fig in lfig: if type(fig) is not str: x.append(72.*fig.get_size_inches()[0]) y.append(72.*fig.get_size_inches()[1]) else: x.append(120) y.append(80) X.append([0]+list(np.cumsum(x))) y = [dy+Y[-1][0] for dy in y] Y.append([np.max(y)]) print('X = ', X) print('Y = ', Y) if X is None: X = [[0 for fig in lfig] for lfig in FIGS] if Y is None: Y = [[0 for fig in lfig] for lfig in FIGS] if LABELS is None: LABELS = [['' for fig in lfig] for lfig in FIGS] if X_LABELS is None: X_LABELS = X if Y_LABELS is None: Y_LABELS = Y if height is None: try: height = np.max([50, Y[-1][-1]])*0.27 # TO BE SET UP except IndexError: height = 50 # size if width=='single-column': width = 85. elif width=='one-and-a-half-column': width = 114. elif width=='one-column-and-a-half': width = 114. elif width=='double-column': width = 174. if fontsize is None: fontsize = graph_env.fontsize+1 LOCATIONS, PANELS = [], [] for i, lfig in enumerate(FIGS): LOCATIONS.append([]) for j, fig in enumerate(lfig): if type(FIGS[i][j]) is str: LOCATIONS[i].append(FIGS[i][j]) # 1.26625 -- NEW SCALING FACTOR else: LOCATIONS[i].append(os.path.join(gettempdir(), '%i_%i.svg' % (i,j))) FIGS[i][j].savefig(LOCATIONS[i][j], format='svg', transparent=graph_env.transparency) PANELS.append(sg.Panel(sg.SVG(LOCATIONS[i][j]).move(X[i][j], Y[i][j]))) for i, labels in enumerate(LABELS): for j, label in enumerate(labels): if label!='': PANELS.append(sg.Panel(sg.Text(label, 3, 10, size=fontsize, weight=fontweight).move(\ X_LABELS[i][j],Y_LABELS[i][j]))) if grid: sg.Figure("%.1fcm" % (width/10.), "%.1fcm" % (height/10.), *PANELS, sg.Grid(40,40)).scale(SCALING_FACTOR).save(fig_name.replace('.png', '.svg')) else: sg.Figure("%.1fcm" % (width/10.), "%.1fcm" % (height/10.), *PANELS).scale(SCALING_FACTOR).save(fig_name.replace('.png', '.svg')) if fig_name.endswith('.png'): export_as_png(fig_name.replace('.png', '.svg'), dpi=300, background=bg) os.remove(fig_name.replace('.png', '.svg')) print('[ok] removed %s' % fig_name.replace('.png', '.svg')) elif export_to_png: export_as_png(fig_name, dpi=300, background=bg)
def fsapt_analyze(lig_dir, mode, ene_type): lig_name = os.path.basename(os.path.abspath(lig_dir)) matrix_dfs = [] outfiles = glob('%s/FSAPT*out' % lig_dir) for of in outfiles: df = _get_ene_matrix(of, ene_type) if not df is None: matrix_dfs.append(df) all_df = pd.concat(matrix_dfs, axis=1) mean_df = all_df.stack().groupby(level=[0, 1]).mean().unstack() std_df = all_df.stack().groupby(level=[0, 1]).std().unstack() if mode in ['prolig', 'proliglig']: old_columns = mean_df.columns[:] new_labels = [] numbering = [] for old_label in old_columns: if old_label == 'Total': new_labels.append('Total') numbering.append(100000) else: labels = old_label.split('-') if len(labels) == 2: new_labels.append(''.join(labels)) numbering.append(float(labels[-1])) elif len(labels) == 3: new_labels.append('-'.join(labels[1:])) numbering.append(0.5 * (float(labels[-1]) + float(labels[-2]))) new_columns = [nl for _, nl in sorted(zip(numbering, new_labels))] old_columns = [ol for _, ol in sorted(zip(numbering, old_columns))] new_mean_df = pd.DataFrame() new_std_df = pd.DataFrame() for nc, oc in zip(new_columns, old_columns): new_mean_df[nc] = mean_df[oc] new_std_df[nc] = std_df[oc] mean_df = new_mean_df std_df = new_std_df mean_anno = mean_df.applymap(lambda x: '%+.2f\n' % x) std_anno = std_df.applymap(lambda x: r'+/-%.2f' % x) all_anno = mean_anno + std_anno matrix_svg = '%s/ene_matrix_%s.svg' % (lig_dir, ene_type) plot_matrix(mean_df, all_anno, matrix_svg, mode, ene_type) mean_df.to_csv('%s/ene_mean_%s_%s_%s.csv' % (lig_dir, lig_name, mode, ene_type)) std_df.to_csv('%s/ene_std_%s_%s_%s.csv' % (lig_dir, lig_name, mode, ene_type)) # Plot the ligand dpi = 96 width = len(mean_df.columns) + 2 height = 4 ligmol = cs._RdkitMolBase.from_file('MD/%s/cmp_sybyl.mol2' % lig_name) ligmol._init_atominfo(reset=False) ligmol.charged_mol2file = 'MD/%s/cmp_sybyl.mol2' % lig_name ligmol.get_noh_mol() AllChem.Compute2DCoords(ligmol.noh_mol, canonOrient=True, bondLength=1.5) drawer = rdMolDraw2D.MolDraw2DSVG(width * dpi, height * dpi) opts = drawer.drawOptions() opts.additionalAtomLabelPadding = 0.1 frag_dict, _ = fragment_mol(ligmol, 'L1') for noha in ligmol.noh_mol.GetAtoms(): noh_idx = noha.GetIdx() h_idx = ligmol.noh_to_h_atom_mapping[noh_idx] frag_label = str(frag_dict[h_idx]['resid']) if not 'L1-%02d' % int(frag_label) in mean_df.index: continue if noha.GetAtomicNum() == 6: opts.atomLabels[noh_idx] = '%02d' % int(frag_label) else: elem = ligmol.GetAtomWithIdx(h_idx).GetProp( '_TriposAtomType').split('.')[0] opts.atomLabels[noh_idx] = '%s/%02d' % (elem, int(frag_label)) drawer.DrawMolecule(ligmol.noh_mol) drawer.FinishDrawing() svg = drawer.GetDrawingText().replace('svg:', '') struct_svg = '%s/lig_frag_%s.svg' % (lig_dir, ene_type) with open(struct_svg, 'w') as fh: fh.writelines(svg) # Consolidate the panels if mode == 'prolig': mat_title = 'Protein-Ligand %s Interaction' % ene_type.capitalize() else: mat_title = 'Ligand-Ligand %s Interaction' % ene_type.capitalize() mat_title = sc.Panel(sc.Text(mat_title, size=24)).move(20, 20) mat_panel = sc.Panel(sc.SVG(matrix_svg).scale(1.4)).move(0, 20) struct_title = sc.Panel(sc.Text('Ligand %s' % lig_name, size=24)).move(20, dpi * len(mean_df) + 20) struct_panel = sc.Panel(sc.SVG(struct_svg)).move(0, dpi * len(mean_df) + 20) final_figure = sc.Figure(dpi * width, dpi * (len(mean_df) + height) + 40, mat_panel, mat_title, struct_panel, struct_title) final_name = '%s/%s_%s_%s' % (lig_dir, lig_name, mode, ene_type) final_figure.save('%s.svg' % final_name) os.system('convert -density 100 %s.svg %s.pdf' % (final_name, final_name)) os.system('rm -f %s %s' % (matrix_svg, struct_svg)) # Write pdb for pymol inpdb = '%s/frame0/fsapt.pdb' % lig_dir outpdb = '%s_pymol.pdb' % final_name write_pymol_pdb(inpdb, outpdb, mean_df)
def composite( fig_spec: FigureSpec, memoize_panels: bool = False, recompute_panels: bool = True, delete_png: bool = True, ) -> None: """ Function that composites a figure from a FigureSpec. Parameters ---------- fig_spec : FigureSpec memoize_panels : bool recompute_panels : bool delete_png : bool See the pubfig.compositor decorator for a description of the parameters. Returns ------- None """ import tempfile svg_path = fig_spec.output_file if isinstance(svg_path, str): svg_path = Path(svg_path) assert not svg_path.is_dir(), "The output file name you provided is a directory" if svg_path.suffix != ".svg": svg_path = svg_path.with_suffix(".svg") svg_path = svg_path.expanduser() if not svg_path.parent.exists(): svg_path.parent.mkdir(parents=True, exist_ok=True) if memoize_panels: panels_path = svg_path.parent / ".panels" if not panels_path.exists(): panels_path.mkdir() else: panels_path = Path(tempfile.gettempdir()) panels = [] if fig_spec.plot_grid_every > 0: panels.append(_generate_grid(fig_spec.figure_size, fig_spec.plot_grid_every, font_size=8)) auto_label = fig_spec.auto_label_options label_generator = auto_label.label_generator(auto_label.first_char.text) for name in fig_spec.panels._fields: panel = getattr(fig_spec.panels, name) assert isinstance(panel, Panel) panel_elements = [] assert isinstance(panel.fig, (plt.Figure, VectorImage, RasterImage)) content_offset = _location_to_str( panel.location.units or fig_spec.figure_size.units, panel.content_offset ) if isinstance(panel, PanelFig): svg = _get_panel_content(panels_path, panel, name, memoize_panels, recompute_panels) panel_elements.append(svg.move(*content_offset)) elif isinstance(panel.fig, VectorImage): scale = panel.scale or panel.fig.scale print(f"Scaling vector image {panel.fig.file.absolute()} by {scale:.3f}") panel_elements.append(panel.fig.svg.scale(scale).move(*content_offset)) elif isinstance(panel.fig, RasterImage): img_size = panel.fig.img_size scale = panel.scale or 1. img = sc.Image( img_size.units.to_px(img_size.width), img_size.units.to_px(img_size.height), f"{panel.fig.file}", ) panel_elements.append(img.scale(scale).move(*content_offset)) else: raise TypeError(f"Unknown type of panel content {type(panel.fig)} for panel {name}") if panel.text is not None: panel_text = [ sc.Text( t.text, *_location_to_str(fig_spec.figure_size.units, Location(t.x, t.y, panel.location.units)), **t.kwargs ) for t in panel.text] for t, pt in zip(panel_text, panel.text): # Need separate loop because rotate doesn't return the Text Element t.move(*content_offset).rotate(pt.angle) panel_elements += panel_text if panel.auto_label: label = sc.Text( next(label_generator), *_location_to_str( fig_spec.figure_size.units, Location(auto_label.first_char.x, auto_label.first_char.y) ), **auto_label.first_char.kwargs ) panel_elements.append(label) location = _location_to_str(fig_spec.figure_size.units, panel.location) panels.append(sc.Panel(*panel_elements).move(*location)) fs = fig_spec.figure_size sc.Figure( f"{fs.units.to_px(fs.width):.2f}px", f"{fs.units.to_px(fs.height):.2f}px", *panels ).save(svg_path) if fig_spec.generate_image != ImageType.none: """ Taken from this shell script: #!/bin/sh # Convert all arguments (assumed SVG) to a TIFF acceptable to PLOS # Requires Inkscape and ImageMagick 6.8 (doesn't work with 6.6.9) for i in $@; do BN=$(basename $i .svg) inkscape --without-gui --export-png="$BN.png" --export-dpi 400 $i convert -compress LZW -alpha remove $BN.png $BN.tiff mogrify -alpha off $BN.tiff rm $BN.png done """ basename = f"{svg_path}"[:-4] image_name = f"{basename}.png" _run(f"inkscape --without-gui --export-png='{image_name}' --export-dpi {fig_spec.image_dpi} {svg_path}") if fig_spec.generate_image == ImageType.tiff: tiff_name = f"{basename}.tiff" _run(f"convert -compress LZW -alpha remove {image_name} {tiff_name}") _run(f"mogrify -alpha off {tiff_name}") if delete_png: _run(f"rm {image_name}") image_name = tiff_name _run(f"eog {image_name}")