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)
Esempio n. 2
0
    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)
Esempio n. 4
0
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)
Esempio n. 5
0
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
Esempio n. 6
0
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)
Esempio n. 7
0
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)
Esempio n. 8
0
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}")
Esempio n. 9
0
    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