Summary Horizontal Bar Chart

This code sample of a horizontal bar chart report.

Horizontal bar charts are ideal when you want to show a discrete value (such as an on/off or open/closed/transitioning status) over time.

In this case, we're showing a summary of how much time across the report range that the various assets were in different states.

Asset names vary wildly in terms of length. Because of this, we suggest placing your asset names inside the report rather than placing them on one of your axes.

400

Customising
ElementReplace With
[PROPERTY]The name of the property you want to report on
[ASSETTYPE]The title to show on the Y axis
The Code
import os
import sys
 
sys.path.insert(0,os.path.dirname(os.path.dirname(__file__)))
 
import mplreport
import discretepatterns as dp
import pandas as pd
import datetime
 
@mplreport.ardireport("Sample Report")
def CreateReport(report,args):    
 
    #Create a page containing a single plot.
    fig,ax = report.CreatePage(1)
 
    #Print a title block for the page.
    report.Title()                   
 
    #Our AQL query goes here
    query = "('[PROPERTY]') PROPERTY ALLPOINTS"
 
    #Get the pandas data-frame with the results. Use the extended version that includes metadata.
    hist = report.FetchHistory(query)        
    df = hist.data
 
    #Use the 'Discrete Patterns' class to convert discrete data into
    #  time frames
    patterns = dp.DiscretePatterns()
    patterns.SetDataframe(df)
    patterns.Ready()        
 
    #Establish a preferred order for the values
    order = [1,0]
 
    #Calculate total report time
    totaltime = (report.defaultend - report.defaultstart).total_seconds()
 
    #An array of asset names and summaries
    summaries = []
 
    #Draw the bar chart
    indx = len(df.columns)-1
    for col in df.columns:
        #Convert a discrete value into a set of time frames
        frames = patterns.GetAllTimeframes(col)
 
        #Get both colour and value maps
        map = report.GetDiscreteColourMap(hist,col)
        vmap = hist.GetValueMap(col)
 
        #We'll summarise the different values here...
        txt = ""
 
        #Go through the different values in the specified order
        realtotal = 0
        for n in order:
            #Calculate the total time spent with this value
            total = 0
            if n in frames:
                for frame in frames[n]:
                    total += (frame[1] - frame[0]).total_seconds()            
 
            #If there's anything to show...
            if total > 0:
                #Convert the total into a percentage...
                total = (total / totaltime) * 100
                #Draw the total
                ax.broken_barh([(realtotal,total)],(indx,0.9),color=map[n])
                realtotal += total
 
                #And update the line of text
                if txt != "":
                    txt += " "
                txt += str(int(total*10)/10) + "% " + vmap[n]
 
        #Add the asset name to the line of text, and add it to the list.
        txt = col.replace(" [PROPERTY]","") + " - " + txt
        summaries.append(txt)
 
        indx-=1
 
    #Draw in names
    indx = len(df.columns)-1
    for col in summaries:
        ax.text(1, indx+0.18, col.strip(), c=(0,0,0,0.7))
        indx -= 1
 
    #Clear the Y axis
    ax.set_yticks(range(0,len(df.columns)))
    ax.set_yticklabels([""] * len(df.columns))        
 
    #Clean up and prettify        
    ax.set_ylabel("[ASSETTYPE]")
    ax.set_xlabel("Time (%)")    
    ax.margins(0,0)    
    legend = report.GetDiscreteLegend(hist,df.columns[0])
    ax.legend(handles=legend[0])
 
    #Save this report out.
    report.Save()