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_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 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 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 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}")
def add_title(self, fig, title, y_pos=-0.2, w=None): """ `fig`: a plotly/svgutils Figure object, or the path of a png file. `title`: figure title. `w`: output image width in px. """ if isinstance(fig, str): if not os.path.exists(fig): print('File %s does exist!'%(fig)) return if not os.path.splitext(os.path.abspath(fig))[-1]=='.png': print('Only png image supported.') return im = Image.open(fig) if w: _w = w else: _w = self.output_width _scalar = _w * 1.0 / im.width svg_fig = sc.Figure(_w, ceil(_scalar * im.height), sc.Image( im.width, im.height, fig ).scale(_scalar) ) fig = svg_fig assert isinstance(fig, go.Figure) or isinstance(fig, sc.Figure) # if input a plotly Figure object, convert it into a svg file first title_txt = '%s%s '%(self.prefix, self.current_num) + title if isinstance(fig, go.Figure): # compute image size if w: _w = w else: _w = self.output_width if not fig.layout.width is None: _scalar = _w * 1.0 / fig.layout.width else: # default width is 700px _scalar = _w * 1.0 / 700 if not fig.layout.height is None: _h = fig.layout.height * _scalar else: # default height is 450px _h = 450.0 * _scalar title_annotation = go.layout.Annotation( xref = 'paper', yref = 'paper', x = 0.5, y = y_pos, xanchor = 'center', yanchor = 'top', text = title_txt, font = dict( family = self.font_family, size = self.font_size, color = "#000000", ), showarrow = False, ) fig.update_layout( width = _w, height = _h, annotations = list(fig.layout['annotations']) + [title_annotation], ) # increasing counter number self.current_num += 1 return fig else: # compute image size if w: _w = w else: _w = self.output_width _scalar = _w * 1.0 / fig.width.value _h = fig.height.value * _scalar + 25 if y_pos==-0.2: text_y = _h - 5 else: assert y_pos<=1 and y_pos>=0 text_y = int(_h*(1-y_pos)) # if w < default output width, add margin if _w < self.output_width: _outw = self.output_width _move_x = int((_outw - _w) / 2) else: _outw = _w _move_x = int((_outw - _w) / 2) # add title new_figure = sc.Figure(_outw, _h, fig.scale(_scalar).move(_move_x, 0), sc.Text(title_txt, _outw / 2, text_y, anchor='middle', size=self.font_size, font=self.font_family, ) ) # increasing counter number self.current_num += 1 return new_figure