Plots
Plot is a graphical way to represent a value in a report. Other names it might be referred to are chart or graph, but for clarity we will use plot in the documentation.
Plotly
As an underlying plot engine for plot generation we use Plotly for Python. It's an open source library that allows a generation of plots that can be viewed and interacted with in a browser when working with interactive version of report document (Dash). Additionally, with a help of kaleido package, those interactive plots can be rendered to static images, and added to static report document (Word).
This feature was essential when choosing the solution for our plotting engine, since we wanted to serve both interactive and static reports with the same tool. With Plotly, the plot can be defined only once, and depending on the report output you are working with, the appropriate format of the plot is added to the report document.
Combine it with great documentation, flexibility and extensibility, and you have a really nice solution for working with the plots in our reporting engine.
General concepts
In order to integrate well with selected plotting library we have adopted our solution to work well with general Plotly concepts.
In the Plotly library for Python, the key conceptual unit is the "Figure". A figure in Plotly effectively serves as a container that encompasses all the various elements of the plot, including the data, layout, and annotations, all of which collaborate to define the final visual representation of the plot.
The data in a Plotly figure is represented as a list of "traces". A trace is an object that describes a single type of visual data representation on the plot. This can be anything from a line chart to a bar chart, scatter plot, or many other types of graphical representations. Each trace contains information about the data that is being represented, as well as how to style and render that data. Importantly, you can have multiple traces in a single figure, which allows for complex plots with multiple types of data represented simultaneously.
Each trace is drawn on axes that provide a framework within which the data can be understood. These axes can be adjusted and manipulated to change the scale, labels, and orientation of the visualized data. They essentially set the coordinate system for the traces and provide context to help interpret the data.
Lastly, the "layout" of a Plotly figure represents the higher-level aspects of the figure's appearance. This includes elements like the title of the plot, any legends or color scales, and the axis labels. The layout can also dictate the overall theme or style of the plot, setting aspects such as the background color, font styles, and grid lines. Essentially, the layout allows you to adjust the non-data elements of the figure to ensure that the final plot communicates the data effectively and in a visually appealing manner.
Figures
Because, figure is the center component of the plotting in the smartreport solution.
Report Outputs have implemented method called add_figure that can be used to
add a Figure to the report document.
Any valid Plotly figure can be added to the report document!
However, to make the report look coherent, and not to reinvent each plot over and over again, we have developed several functions that returns a figure based on provided data, and optional styling arguments.
As an outcome you will receive a plot, that conforms to the ABB UX standards, and handles the edge cases when dealing with incomplete or partially corrupted data.
Developing new plot
Figures are composed of data (traces) and layout. This structure is reflected, in how we develop a new figure.
When creating a new plot we need to take data as an input, and then add it as one or more traces to the figure. Finally, we need to define a layout for the figure.
Because, quite often, final figure is a combination of similar trace types and layouts we propose to extract trace drawing logic into a separate functions that can be reused and to create layout building classes.
Example
To make new plotting function that can be used to create a figure, that we can later add to the report document follow the example below:
from plotly.graph_objects import Figure
from smartreport.plot.layout.vertical import VerticalPlotLayout
from smartreport.datatypes.trend import Trend
from smartreport.datatypes.threshold import Threshold
from smartreport.v3.plot.traces.line import draw_trend_line
from smartreport.v3.plot.traces.threshold import draw_threshold
def plot_trend_line_with_threshold(trend: Trend, threshold: Threshold, **kwargs) -> Figure:
# Initialize layout
layout = VerticalPlotLayout()
# Each layout should implement an empty plot property that is returned when the data in not sufficient.
if trend.empty:
return layout.empty_plot
# Initialize basic figure object
fig = Figure()
# Add a trace with trend line to the figure
fig = draw_trend_line(figure=fig, data=trend, **kwargs)
# Draw Threshold trace
fig = draw_threshold(figure=fig, threshold=threshold, **kwargs)
# Apply layout to the figure, we do it at the end because some logic in the layout making code,
# might require data inspection in the figure. For example, setting the plot range requires the knowledge about
# the min max values in the data.
layout.apply_to_figure(figure=fig)
return fig