Creating a PowerPoint Report File

NOTE: Running this example requires installing the pptx Python module

To create a PowerPoint file, we will use the PPTX python module, which is made specifically for manipulating and creating PowerPoint files.

Instead of pages in a PDF, this report is going to show individual slides for each of the turbines from our wind turbine demo.

The best way to start a PowerPoint report is to begin with a template. In this case, we're beginning with a file called Base.pptx.

Setting Up Master Slides

As a shortcut, you can pre-configure some common slide layouts by creating Slide Masters in the template PowerPoint file.

In the example provided, we have two key slides - the first which is a title slide and another which is a chart slide.

The title slide contains two placeholders, one for the title and one for the date. The chart slide contains only one placeholder - a full-page chart.

The Code

import os
import sys
 
sys.path.insert(0,os.path.dirname(os.path.dirname(__file__)))
 
import datetime
import traceback
import ardiapi
import mplreport
import traceback
 
#Import PPTX
from pptx import Presentation
from pptx.chart.data import ChartData
from pptx.enum.chart import XL_CHART_TYPE
from pptx.enum.chart import XL_LEGEND_POSITION
from pptx.util import Pt
 
import matplotlib.pyplot as plt
 
@mplreport.ardireport("Oven Temperatures")
def CreateReport(report,args):       
    #Figure out the number of samples we are going to need (in this case, 10-second samples).
    samples = 1000
 
    #Our AQL query goes here
    query = "('Oven #1') ASSET 'Oven Sequence' RELATIONSHIP 'downi' RELATED ('Temperature - Oven') PROPERTYEX VALUES"    
 
    #Get the pandas data-frame with the results.
    df = report.GetHistory(query,samples=samples)

Apart from importing pytx, this is a normal start for a report. It's where we'd normally start drawing our content where things change…

    prs = Presentation(os.path.dirname(__file__) + "/Base.pptx")
 
    title = prs.slides.add_slide(prs.slide_layouts[0])
    title.placeholders[0].text = report.name
    title.placeholders[1].text = args.localstart.strftime("%c") + " to\n" + args.localend.strftime("%c")

This creates a new PowerPoint presentation, adds a new slide (based on Layout 0, which is our title slide).

We then use the two placeholders to set the title and the range to be displayed on the opening page.

    dformat = report.DateFormat()
 
    failed = False
    indx = 0    
    for col in df.columns:
        indx += 1
        try:
            #Assemble the X & Y data for the line chart
            yset = [0] * len(df[col].index)
            xset = [0] * len(df[col].index)
            q = -1
            for k,v in df[col].items():
                q += 1
                yset[q] = round(v,0)
                xset[q] = k.strftime(dformat)            
 
            #Add a Slide
 
        except:
            traceback.print_exc()
            failed = True
 
    prs.save(args.target + ".pptx")

The code above loops through each of the columns in the dataframe (since in this case we're only getting a single property per turbine).

For each column/turbine, we build two arrays - one containing the X data (timestamps) for a line chart, the other containing the Y data (speed).

Next, we need to create the chart itself.

Building Charts

            #Create PowerPoint Chart Data
            chart_data = ChartData()
            chart_data.categories = xset
            chart_data.add_series('Turbine ' + str(indx) + ' Speed',yset)        
 
            #Add a PowerPoint Chart Slide
            sld = prs.slides.add_slide(prs.slide_layouts[2])
 
            #Get a reference to the chart placeholder on the new slide...
            chart = sld.placeholders[13].insert_chart(XL_CHART_TYPE.LINE,chart_data).chart
            chart.series[0].smooth = True
            chart.vary_by_categories = False
            chart.has_data_labels = False
 
            #Format the X axis
            category_axis = chart.category_axis
            category_axis.has_major_gridlines = True                               
            category_axis.tick_labels.font.size = Pt(10)
 
            #Format the Y axis
            value_axis = chart.value_axis
            value_axis.has_major_gridlines = True                             
            value_axis.tick_labels.font.size = Pt(10)
 
            #Disable the legend
            chart.has_legend = False   
 
            print("Charted Turbine " + str(indx))

After getting those arrays for our X and Y axes, we need to build the report. The code above…

* Creates a PowerPoint 'ChartData' object containing both the X and Y data.
* Creates a new slide that contains a full-page chart object,
* Gets the chart object from the new slide, sets the data and formats the X & Y axis.

Finishing

Finally, we need to save the report.

    prs.save(args.target + ".pptx")

Using The Report

When using the report on an ARDI server, you'd be able to…

* Produce a pre-generated daily version of the presentation.
* Store the last several days of the presentation for people to go back to,
* Allow users to create custom presentations for their own time-ranges, and
* Automatically upload presentations to shared locations, such as Teams folders or Sharepoint.

Continue Reading