コード例 #1
0
def run(save_dir: str):
    pp = PPTXCreator(TemplateExample())
    slide_01 = pp.add_slide("Table style example 01 - slide 01")
    slide_02 = pp.add_slide("Table style example 01 - slide 02")
    slide_03 = pp.add_slide("Table style example 01 - slide 03")
    slide_04 = pp.add_slide("Table style example 01 - slide 04")
    slide_05 = pp.add_slide("Table style example 01 - slide 05")
    slide_06 = pp.add_slide("Table style example 01 - slide 06")

    # data for a table with 5 rows and 3 cols.
    table_data = []
    table_data.append([1, "The second column is longer."])  # rows can have different length
    table_data.append([2, "Table entries don't have to be strings,"])  # there is specific type needed for entries (implemented as text=f"{entry}")
    table_data.append([3, "because its implemented as text=f'{entry}'"])
    table_data.append([4, "also note: the number of entries per row is", " not fixed"])
    table_data.append([5, "That's it for now."])

    # We can add these data as a table title_slide with PPTXCreator.add_table()...
    table_01 = pp.add_table(slide_01, table_data)
    # ... but if you open the slide in PowerPoint there are a few issues:
    #         1) the table is positioned in the top left corner - overlapping the title
    #         2) the first row is formated differently (like a column header)
    #         3) all columns have the same width (1 inch)
    #         4) the table width is too small (for the used paragraph size)

    # Lets handle the the position first using optional PPTXPosition parameter
    table_02 = pp.add_table(slide_02, table_data, PPTXPosition(0.02, 0.14))

    # for more control we use PPTXTableStyle
    table_style = PPTXTableStyle()
    table_style.first_row_header = False
    table_style.width = 6.1  # table width in inches
    table_style.col_ratios = [0.3, 5, 1.3]

    table_03 = pp.add_table(slide_03, table_data, PPTXPosition(0.02, 0.14), table_style)

    # It's also possible to add the position directly to the table style:
    table_style.position = PPTXPosition(0.02, 0.14)
    # or to set the table width as a fraction of slide width:
    table_style.set_width_as_fraction(0.49)
    # change row/col bending
    table_style.col_banding = True
    table_style.row_banding = False
    table_04 = pp.add_table(slide_04, table_data, table_style=table_style)

    # we could also add a paragraph-style and a cell-style
    table_style.font_style = PPTXFontStyle().set(italic=True, name="Arial", color_rgb=(100, 200, 30))
    # todo: cell-style
    table_05 = pp.add_table(slide_05, table_data, table_style=table_style)

    # you could also use a table style on an existing table
    table_06 = pp.add_table(slide_06, table_data)
    table_style.write_shape(table_06)

    pp.save(os.path.join(save_dir, "table_style_example_01.pptx"), overwrite=True)
コード例 #2
0
def create_pptx_for_nanoindents(path, pptx_filename, pptx_template: Optional[AbstractTemplate] = None):
    pptx = PPTXCreator(template=pptx_template)
    pptx.add_title_slide(f"AFM on Nanoindents - {path.stem}")
    measurements = load_pygdf_measurements(path)
    for measurement in measurements:
        indent_analyzer = GDEFIndentAnalyzer(measurement)
        print(measurement.comment)
        slide = pptx.add_slide(measurement.comment)

        figure = measurement.create_plot()
        if figure is None:
            continue
        pptx.add_matplotlib_figure(figure, slide, position_2x2_00())
        table_shape = pptx.add_table(slide, measurement.get_summary_table_data(), position_2x2_01(),
                                     table_style=summary_table())
        minimize_table_height(table_shape)
        # figure.savefig(f"{measurement.basename.with_suffix('.png')}")  # , transparent=transparent)

        indent_analyzer.add_indent_pile_up_mask_to_axes(figure.axes[0], roughness_part=0.05)
        # figure.savefig(f"{measurement.basename.with_name(measurement.basename.stem + '_masked.png')}", dpi=96)
        pptx.add_matplotlib_figure(figure, slide, position_2x2_10())
        table_shape = pptx.add_table(slide, indent_analyzer.get_summary_table_data(), position_2x2_11(),
                                     table_style=summary_table())
        minimize_table_height(table_shape)
        figure.clear()
    pptx.save(path.joinpath(f"{pptx_filename}.pptx"),
              overwrite=True)  # todo: remove overwrite=True when testing is finished
コード例 #3
0
def run(save_dir: str):
    pp = PPTXCreator(TemplateExample())

    PPTXFontStyle.lanaguage_id = MSO_LANGUAGE_ID.ENGLISH_UK
    PPTXFontStyle.name = "Roboto"

    title_slide = pp.add_title_slide("General example 01 - title slide")
    font = font_title(
    )  # returns a PPTXFontStyle instance with bold paragraph and size = 32 Pt
    font.write_shape(
        title_slide.shapes.title
    )  # change paragraph attributes for all paragraphs in shape

    slide2 = pp.add_slide("General example 01 - page2")
    pp.add_slide("General example 01 - page3")
    pp.add_slide("General example 01 - page4")
    pp.add_content_slide()  # add slide with hyperlinks to all other slides

    text = "This text has three paragraphs. This is the first.\n" \
           "Das ist der zweite ...\n" \
           "... and the third."
    my_font = font_default()
    my_font.size = 16
    text_shape = pp.add_text_box(title_slide, text, PPTXPosition(0.02, 0.24),
                                 my_font)

    my_font.set(size=22,
                bold=True,
                language_id=MSO_LANGUAGE_ID.GERMAN,
                strikethrough=TEXT_STRIKE_VALUES.SingleStrike,
                caps=TEXT_CAPS_VALUES.All)

    my_font.write_paragraph(text_shape.text_frame.paragraphs[1])

    my_font.set(size=18,
                bold=False,
                italic=True,
                name="Vivaldi",
                language_id=MSO_LANGUAGE_ID.ENGLISH_UK,
                underline=MSO_TEXT_UNDERLINE_TYPE.WAVY_DOUBLE_LINE,
                color_rgb=(255, 0, 0),
                strikethrough=None,
                caps=None)

    my_font.write_paragraph(text_shape.text_frame.paragraphs[2])

    table_data = []
    table_data.append([1, 2])  # rows can have different length
    table_data.append(
        [4, slide2, 6]
    )  # there is specific type needed for entries (implemented as text=f"{entry}")
    table_data.append(["", 8, 9])

    table = pp.add_table(title_slide, table_data, PPTXPosition(0.02, 0.4))
    paragraph_style = PPTXParagraphStyle()
    paragraph_style.set(alignment=PP_PARAGRAPH_ALIGNMENT.CENTER)
    paragraph_style.write_shape(table)

    if matplotlib_installed:
        fig = create_demo_figure()
        pp.add_matplotlib_figure(fig, title_slide, PPTXPosition(0.3, 0.4))
        pp.add_matplotlib_figure(fig,
                                 title_slide,
                                 PPTXPosition(0.3, 0.4, fig.get_figwidth(),
                                              -1.0),
                                 zoom=0.4)
        pp.add_matplotlib_figure(fig,
                                 title_slide,
                                 PPTXPosition(0.3, 0.4, fig.get_figwidth(),
                                              0.0),
                                 zoom=0.5)
        pp.add_matplotlib_figure(fig,
                                 title_slide,
                                 PPTXPosition(0.3, 0.4, fig.get_figwidth(),
                                              1.5),
                                 zoom=0.6)

        pp.add_text_box(title_slide,
                        "Use latex-like syntax \nto create formula:",
                        PPTXPosition(0.748, 0.23))
        pp.add_latex_formula(f"\mu={5}^{5}", title_slide,
                             PPTXPosition(0.75, 0.35))
        formula02 = "\\int_0^\\infty e^{-x^2} dx=\\frac{\\sqrt{\\pi}}{2}"
        pp.add_latex_formula(formula02, title_slide, PPTXPosition(0.75, 0.45))
        pp.add_latex_formula(formula02,
                             title_slide,
                             PPTXPosition(0.75, 0.55),
                             font_size=24,
                             color="red")
        formula03 = "\\hat{x}, \\check{x}, \\tilde{a}, \\bar{\\ell}, \\dot{y}, \\ddot{y}, \\vec{z_1}, \\vec{z}_1"
        pp.add_latex_formula(formula03,
                             title_slide,
                             PPTXPosition(0.75, 0.65),
                             font_size=24,
                             color="blue")
        formula04 = r"\frac{3}{4} \binom{3}{4} \genfrac{}{}{0}{}{3}{4}"
        pp.add_latex_formula(formula04,
                             title_slide,
                             PPTXPosition(0.75, 0.75),
                             font_size=44,
                             color="g")
    pp.save(os.path.join(save_dir, "general_example_01.pptx"))

    try:  # only on Windows with PowerPoint installed:
        filename_pptx = os.path.join(save_dir, "general_example_01.pptx")
        filename_pdf = os.path.join(save_dir, "general_example_01.pdf")
        foldername_png = os.path.join(save_dir, "general_example_01_pngs")

        # use absolute path, because its not clear where PowerPoint saves PDF/PNG ... otherwise
        pp.save(filename_pptx, create_pdf=True, overwrite=True)
        pp.save_as_pdf(filename_pdf, overwrite=True)
        pp.save_as_png(foldername_png, overwrite_folder=True)
    except Exception as e:
        print(e)
コード例 #4
0
class GDEFReporter:
    """
    Class to create *.pptx files with results from AFM-measurements (*.gdf)
    """
    def __init__(self,
                 gdf_containers: Union[GDEFContainer, List[GDEFContainer],
                                       None] = None):
        """
        :param gdf_containers: list of GDEFContainer objects, that contain measurements from a single *.gdf file each
        """
        self.gdf_containers: GDEFContainerList = GDEFContainerList(
            gdf_containers)
        self.primary_gdf_folder = gdf_containers[
            0].path.parent  # todo: check for multiple folders
        self.title = f"AFM - {self.primary_gdf_folder.stem}"
        self.subtitle = self.title
        self.pptx = None
        self.title_slide = None

    def create_summary_pptx(self,
                            filtered: bool = False,
                            pptx_template=TemplateExample()):
        self.pptx = PPTXCreator(template=pptx_template)
        self.title_slide = self.pptx.add_title_slide(self.title)

        table_data = self.get_files_date_table_data()

        table_style = PPTXTableStyle()
        table_style.set_width_as_fraction(0.55)
        self.pptx.add_table(self.title_slide, table_data,
                            PPTXPosition(0.0, 0.224, 0.1, 0.1), table_style)

        for container in self.gdf_containers:
            slide = self.pptx.add_slide(f"Overview - {container.basename}.gdf")
            if filtered:
                measurements = container.measurements
            else:
                measurements = container.filtered_measurements

            self.pptx.add_matplotlib_figure(
                self.create_summary_figure(measurements),
                slide,
                PPTXPosition(0, 0.115),
                zoom=0.62)

            table_style = summary_table()
            table_style.font_style.set(size=11)
            table_style.set_width_as_fraction(0.245)
            table_data = measurements[0].get_summary_table_data()
            table_data.append(["comment", measurements[0].comment])
            table_shape = self.pptx.add_table(slide, table_data,
                                              PPTXPosition(0.75, 0.115),
                                              table_style)
            minimize_table_height(table_shape)

        return self.pptx

    def get_files_date_table_data(self):
        result = [["file", "date"]]
        for container in self.gdf_containers:
            result.append([
                f"{container.path.stem}.gdf",
                container.last_modification_datetime
            ])
        return result

    # todo: split up and move part to GDEF_Plotter or plotter_utils
    def create_summary_figure(self,
                              measurements: List[GDEFMeasurement],
                              figure_size=(16, 10)):
        n = len(measurements)
        if n == 0:
            return plt.subplots(1, figsize=figure_size, dpi=300)

        optimal_ratio = figure_size[0] / figure_size[1]
        dummy_fig = measurements[0].create_plot()
        single_plot_ratio = dummy_fig.get_figwidth() / dummy_fig.get_figheight(
        )
        optimal_ratio /= single_plot_ratio

        possible_ratios = []
        for i in range(1, n + 1):
            for j in range(1, n + 1):
                if i * j >= n:
                    x, y = i, j
                    possible_ratios.append((x, y))
                    break

        # sort ratios by best fit to optimal ratio:
        possible_ratios[:] = sorted(
            possible_ratios,
            key=lambda ratio: abs(ratio[0] / ratio[1] - optimal_ratio))
        best_ratio = possible_ratios[0][1], possible_ratios[0][0]

        result, ax_list = plt.subplots(*best_ratio,
                                       figsize=figure_size,
                                       dpi=300)
        for i, measurement in enumerate(measurements):
            y = i // best_ratio[0]
            x = i - (y * best_ratio[0])
            if best_ratio[1] > 1:
                measurement.set_topography_to_axes(ax_list[x, y], True)
            elif best_ratio[0] > 1:
                measurement.set_topography_to_axes(ax_list[x], True)
            else:
                measurement.set_topography_to_axes(ax_list, True)
        i = len(measurements)
        while i < best_ratio[0] * best_ratio[1]:
            y = i // best_ratio[0]
            x = i - (y * best_ratio[0])
            ax_list[x, y].set_axis_off()
            i += 1
        result.tight_layout()
        return result

    @classmethod
    def create_stiched_data(cls,
                            measurements,
                            initial_x_offset_fraction=0.35,
                            show_control_plots=False):
        values_list = []
        for measurement in measurements:
            values_list.append(measurement.values)
        return GDEFSticher(values_list, initial_x_offset_fraction,
                           show_control_plots).values

    @classmethod
    def _create_image_data(cls, data: np.ndarray):
        """
        Transform given data array into a n array with uint8 values between 0 and 255.
        :param data:
        :return:
        """
        data_min = np.nanmin(data)
        data = (data - np.min([0, data_min])) / (np.nanmax(data) - np.min(
            [0, data_min]))  # normalize the data to 0 - 1
        data = 255 * data  # Now scale by 255
        return data.astype(np.uint8)

    @classmethod
    def data_to_png(cls, data: np.ndarray, mode='L'):
        """
        Can be used to get a png-object for pptx or to save to hard disc.
        Mode 'L' means greyscale. Mode'LA' is greyscale with alpha channel.
        """
        image_data = cls._create_image_data(data)
        return png.from_array(image_data,
                              mode=mode)  # .save(f"{samplename}_stiched.png")
コード例 #5
0
class PI88ToPPTX:
    def __init__(self, measurements_path=None, template=None):
        self.path = measurements_path
        self.measurements = []
        if self.path:
            self.load_tdm_files(measurements_path)
        self.plotter = PI88Plotter(self.measurements)
        self.pptx_creator = PPTXCreator(template=template)
        self.prs = self.pptx_creator.prs
        self.position = self.pptx_creator.default_position

        self.poisson_ratio = 0.3
        self.beta = 1.0

        self.measurements_unloading_data: dict = {}

    def load_tdm_files(self,
                       path: str,
                       sort_key=os.path.getctime
                       ):  # sorted by creation time (using windows)
        self.measurements.extend(load_tdm_files(path, sort_key))

    def add_measurements(
        self, measurements: Union[PI88Measurement,
                                  Iterable[PI88Measurement]]) -> None:
        """
        Adds a single PI88Measurement or a list o PI88Measurement's to the plotter.
        """
        if measurements:
            try:
                self.measurements.extend(measurements)
            except TypeError:
                self.measurements.append(measurements)

    def clear_measurements(self):
        self.measurements = []
        self.measurements_unloading_data = {}

    def add_matplotlib_figure(self,
                              fig: Figure,
                              slide: Slide,
                              position: PPTXPosition = None,
                              **kwargs):
        """
        :param fig:
        :param slide_index:
        :param position:
        :param kwargs: e.g. width and height
        :return: prs.shapes.picture.Picture
        """
        return self.pptx_creator.add_matplotlib_figure(fig, slide, position,
                                                       **kwargs)

    def create_summary_slide(self, title: str = None, layout=None):
        if title is None:
            title = f"Summary - {self.path}"
        result = self.pptx_creator.add_slide(title, layout)

        plotter = PI88Plotter(self.measurements)
        fig = plotter.get_load_displacement_plot()
        fig.axes[0].legend(loc="best")
        self.add_matplotlib_figure(fig, result, PPTXPosition(0.02, 0.15))
        self.create_measurements_result_data_table(result)
        return result

    def create_modulus_hardness_summary_slide(self, layout=None):
        title = "Summary - reduced modulus and hardness"
        result = self.pptx_creator.add_slide(title, layout)

        plotter = PI88Plotter(self.measurements)
        fig = plotter.get_reduced_modulus_plot()
        self.add_matplotlib_figure(fig, result, PPTXPosition(0.02, 0.15))
        avg_reduced_modulus = statistics.mean(fig.axes[0].lines[0].get_ydata())

        fig = plotter.get_hardness_plot()
        self.add_matplotlib_figure(fig, result, PPTXPosition(0.52, 0.15))
        avg_hardness = statistics.mean(fig.axes[0].lines[0].get_ydata())

        text = f"avg. Er = {avg_reduced_modulus} GPa   -   avg. H = {avg_hardness}"
        self.pptx_creator.add_text_box(result, text, PPTXPosition(0.05, 0.85))

        return result

    def create_title_slide(self,
                           title=None,
                           layout=None,
                           default_content=False):
        if title is None:
            title = f"NI results {self.path}"
        result = self.pptx_creator.add_title_slide(title, layout)
        self.create_measurements_meta_table(result)

        plotter = PI88Plotter(self.measurements)
        fig = plotter.get_load_displacement_plot()
        self.add_matplotlib_figure(fig, result, PPTXPosition(0.57, 0.24))
        return result

    def create_measurement_slide(self,
                                 measurement: PI88Measurement,
                                 layout=None,
                                 graph_styler=None):
        title = measurement.base_name  # filename[:-4].split("/")[-1].split("\\")[-1]
        result = self.pptx_creator.add_slide(title, layout)

        self.create_measurement_result_table(result, measurement)
        self.create_measurement_meta_data_table(result, measurement)

        plotter = PI88Plotter(measurement)
        if graph_styler is not None:
            plotter.graph_styler = graph_styler
        fig = plotter.get_load_displacement_plot()

        if (measurement, self.poisson_ratio,
                self.beta) in self.measurements_unloading_data:
            fit_data = self.measurements_unloading_data[(measurement,
                                                         self.poisson_ratio,
                                                         self.beta)]
            fit_disp, fit_load = get_power_law_fit_curve(**fit_data)
            fig.axes[0].plot(fit_disp,
                             fit_load,
                             **get_power_law_fit_curve_style().dict,
                             label="power-law-fit")

        self.add_matplotlib_figure(fig, result, PPTXPosition(0.02, 0.15))
        return result

    def create_measurement_slides(self,
                                  measurements: Optional[
                                      List[PI88Measurement]] = None,
                                  layout=None) -> list:
        result = []
        if measurements is None:
            measurements = self.measurements

        graph_styler = GraphStyler(len(self.measurements))

        for measurement in measurements:
            result.append(
                self.create_measurement_slide(measurement, layout,
                                              graph_styler))

        return result

    def create_measurement_meta_data_table(
            self,
            slide,
            measurement,
            table_style: PPTXTableStyle = None) -> Shape:
        table_data = get_measurement_meta_table_data(measurement)
        result = self.pptx_creator.add_table(slide, table_data,
                                             PPTXPosition(0.521, 0.16))
        if table_style is None:
            table_style = style_sheets.table_no_header()
            table_style.set_width_as_fraction(0.4)
        table_style.write_shape(result)
        return result

    def _get_measurement_result_table_data(self, measurement: PI88Measurement,
                                           poisson_ratio: float,
                                           beta: float) -> list:
        if (measurement, poisson_ratio,
                beta) in self.measurements_unloading_data:
            data = self.measurements_unloading_data[(measurement,
                                                     poisson_ratio, beta)]
        else:
            data = calc_unloading_data(measurement,
                                       beta=self.beta,
                                       poisson_ratio=self.poisson_ratio)
            self.measurements_unloading_data[(measurement, poisson_ratio,
                                              beta)] = data
        return get_measurement_result_table_data(measurement, data)

    def create_measurement_result_table(
            self,
            slide,
            measurement,
            table_style: PPTXTableStyle = None) -> Shape:
        table_data = self._get_measurement_result_table_data(
            measurement, self.poisson_ratio, self.beta)

        result = self.pptx_creator.add_table(slide, table_data,
                                             PPTXPosition(0.521, 0.56))
        if table_style is None:
            table_style = style_sheets.table_no_header()
            table_style.set_width_as_fraction(0.4)
        table_style.write_shape(result)
        return result

    def create_measurements_meta_table(self,
                                       slide,
                                       table_style: PPTXTableStyle = None):
        table_data = get_measurements_meta_table_data(self.measurements)

        result = self.pptx_creator.add_table(slide, table_data)
        if table_style is None:
            table_style = table_style_measurements_meta()
        table_style.write_shape(result)
        return result

    def create_measurements_result_data_table(
            self, slide, table_style: PPTXTableStyle = None):
        for measurement in self.measurements:
            if measurement not in self.measurements_unloading_data.keys():
                self._get_measurement_result_table_data(
                    measurement, self.poisson_ratio,
                    self.beta)  # todo: better method (name change?)
        table_data = get_measurements_result_table_data(
            self.measurements_unloading_data.values())
        result = self.pptx_creator.add_table(slide, table_data)
        if table_style is None:
            table_style = table_style_summary()
        table_style.write_shape(result)
        return result

    def get_average_measurements_unloading_data(self):
        sum_Er = sum_E = sum_hardness = 0
        for data in self.measurements_unloading_data.values():
            sum_Er += data['Er']
            sum_E += data['E']
            sum_hardness += data['hardness']
        n = len(self.measurements_unloading_data.values())
        if n > 0:
            return sum_Er / n, sum_E / n, sum_hardness / n
        else:
            return 0, 0, 0

    def save(self, filename="delme.prs"):
        self.prs.save(filename)