Report Models

A report is composed of model objects whose classes are defined in pbreports.model. Typically, a report object is created and then attributes, tables, or plotGroups are added to the report. Lastly, the report is serialized as json to a file.

The objects that comprise a report extend BaseReportElement. All report elements have an id.

When the report is converted to a dictionary before serialization, each report element’s id is prepended with its parent id, which has also been prepended. For example, given the nested elements of report –> plotGroup –> plot, with respective ids “r”, “pg”, and “p”, the plot id would be “” in the dictionary.

This allows elements of a report to be looked up id, such as “mapping_stats.n_mapped_bases” for a report Attribute (i.e., metric), or a specific plot group, such as “filter_report.filtered_subreads”.


Once a report element id has been assigned, it should not change.


Report is the root class of the model hierarchy. It’s instantiated with an id (should be a short string), which defines its namespace. This example shows how a report is with one attribute, plotGroup, and table is created and written.

import os
import logging

from import Report, Attribute, PlotGroup, Table

log = logging.getLogger(__name__)

def make_report():
    """Write a simple report"""
    table = create_table() # See example below
    attribute = create_attribute() # See example below
    plotGroup = create_plotGroup() # See example below

    # Id must match ^[a-z0-9_]+$
    r = Report('loading', title="Loading Report",

    # Alternatively



An attribute represents a key-value pair with an optional name. The id is the key. A report contains a list of attributes.

import os
import logging

from import Attribute

log = logging.getLogger(__name__)

def create_attribute():
    """Return an attribute"""
    a = Attribute('alpha', 1234, name='Alpha')
    b = Attribute('beta', "value", name="Beta Display Name")
    return a


A table contains a list of column objects and has an optional title and id. A report contains a list of tables. In general, the paradigm for creating a table is to instantiate a table and a series of columns. Add the columns to the table in the desired order. Finally, iterate over your data set and append data to the columns by index.

import os
import logging
import random

from import Attribute, Table, Column

log = logging.getLogger(__name__)

def create_table():
    """Return a table with 2 columns"""
    columns = [Column( 'c1id', header='C1 header'),
            Column('c2id', header='C2 header')]

    t = Table('myid', title='My Table', columns=columns)

    #Now append data to the columns
    #Assume data is a list of tuples of len == 2
    datum = [(, random.random()) for c in columns]
    for column_id, value in datum:
        t.add_data_by_column_id(column_id, value)

    # Alternatively
    cx = Column("cx", header="X", values=[1,2,3,4])
    cy = Column("cy", header="Y", values=[1,4,9,16])
    t = Table("xy", title="X vs Y", columns=[cx, cy])
    return t


A Plot Group represents a logical grouping or collection of plots that convey related information, such coverage across 5 contigs. A plotGroup has an id, an optional thumbnail (to represent the group in SMRT Link in a preview), an optional legend and a list of plots.

import os
import logging

from import PlotGroup, Plot

log = logging.getLogger(__name__)

def create_plotGroup():
    """Return a PlotGroup with 1 plot"""
    # Image paths must be relative to the dir where the final Report is written

    plot = Plot('plot_id', image='image.png', caption='this is a plot')
    p = PlotGroup('myid', title='some title', thumbnail='image_thumb.png', plots=[plot])

    return p


The image paths must be written relative to where the report JSON file will be written.


Currently, only PNG is supported

Report Specs

A parallel family of models in the same module handles specifications for individual reports, i.e. enumerating the data items expected for each model type, along with view metadata. The overall structure and names of objects in the hierarchy is identical to the Report model. For any of the nodes in the hierarchy, the following view metadata may be specified:

  • a UI label, usually title (or name for Attributes, header for table columns)
  • a description suitable for formal documentation or mouseover text
  • a boolean isHidden attribute that controls visibility

There is some redundancy between the report specifications and the actual reports - for example the Report title and Attribute name occur in both models. This was due to the lack of a clear model for view metadata in previous versions of SMRTAnalysis; the Report model may be slimmed down in the future as the view rules are deployed and utilized.

The pbcommand module itself does not actually define any reports; currently most of these are part of the pbreports module.

Format strings

For formatting numerical attribute and column values, we are using a lightweight syntax based on Python’s str.format(…) method. If the format attribute is set to None (null in JSON), the value should simply be directly converted to string without any formatting. (In the case of string and boolean values, the format should always be left unset.) More complex operations values must match this regular expression:


The [GMkp] group specifies scaling - if one of these characters is present, the value should be divided by one billion (G), one million (M), or one thousand (k) before formatting, or multiplied by 100 (p). The period or comma after the colon modifies the display of floating-point and integer values respectively. The following characters before the closing brace correspond to conventional format string syntax. The format can optionally include a suffix to be appended to the formatted value.

Examples of use:

format_value("{:,d}", 123456)           # 123,456
format_value("{:.2f)", 1.23456)         # 1.23
format_value("{G:.2f} Gb", 1234567890)  # 1.23 Gb
format_value("{p:5g}%", 0.987654321)    # 98.765%
format_value(None, 0.987654321)         # 0.987654321