Plotly
This widget can be used to generate graphs. It is build based on plotly.js, which is a high-level declarative charting library. Plotly.js ships with over 40 chart types.
Refer to the Plotly documentation here for details on how to use any of the available chart types in WebStudio.
This widget is data driven. The data structure should conform to the Plotly documentation provided at the beginning of each different type of chart’s section.
Plotly Options
This section is used to apply plotly specific configuration and layout settings.
{
"plotlyOptions" : {
"config" : {},
"layout" : {},
"layoutByTheme" : { // Light and dark theme layout
"mergeMode" : "deep",
"light" : {},
"dark" : {}
}
}
}
Field | Description | |||
---|---|---|---|---|
|
The configuration options determine how users can interact with the chart.
Setting the |
|||
|
Use this property to manipulate the appearance of the plotly chart. Refer to the layout documentation for details. Some of the commonly set options are:
Example:
The layout configuration, which is optional, can also be used to define temples, allowing many static settings such line and fill colors, names etc. that would otherwise reside in the data section, to be set independently from the plot data. This in turn helps with apply data retrieved from the core and limits the amount of model config needed in the widget |
|||
|
Used to configure |
|||
|
The
|
|||
|
In order to arrive at the effective layout to apply to the chart, the The following
|
Data
The structure of the plotly data element is highly chart specific and typically contains more information than just trace values. See plotly docs for details.
This can present a challenge when trying to render data from the core. Below are examples of possible strategies used to retrieve and process data. The examples show an implementation with a scatter plot but the approach should be applicable to most chart types. Refer to the example compilation to see these in action
Use custom Lua to tailor the data read and process it to match the chart widget model:
This typically involved combining trace data with properties required by the plotly chart. In the example below, mode
, type
and name
are added in addition to the object x
and y
values.
In this example, a custom library (eg. myPlotlyLib) is created and installed on an object in the core (eg. /System/Core/Examples) to contain a function called getScatterData(). The function arguments consist of an array of one or more tag paths, start and end time and a few optional settings to control the aggregation.
The Lua function to retrieve the plot data might look something like this:
local myPlotlyLib = {}
function myPlotlyLib:getScatterData( args, _, _ )
local items = args.items or {} -- array of object paths to get data for
if type(items) == "string" then items = { items } end -- support a single path string.
local endTime = args.endTime or syslib.now() -- default end time to now
local intervals = args.intervals or 100 -- default to 100 points
local startTime = args.startTime or (endTime - (1000 * 60 * 60 )) -- default to 1 hour ago
local aggregate = args.aggregate or "AGG_TYPE_INTERPOLATIVE"
local newTrace = function( name, x, y)
return {
mode = "lines",
type = "scatter",
name = name,
x = x,
y = y
}
end
if #items == 0 then
-- No paths were provided
return { newTrace() }
else
-- Read the historic data
local data = syslib.gethistory( items, startTime, endTime, intervals, {aggregate} )
local retVal = {}
-- Pack it into a plotly data structure.
for i, path in ipairs( items ) do
local obj = syslib.getobject( path )
if ( obj ~= nil ) then
local name = obj.ObjectName
local x = {}
local y = {}
-- Map T and V to X and Y
for j, vqt in ipairs(data[i]) do
x[j] = vqt.T
y[j] = vqt.V
end
table.insert( retVal, newTrace( name, x, y) )
else
table.insert( retVal, newTrace() )
end
end
return retVal
end
end
return myPlotlyLib
On the WebStudio side, the library can be used in an advanced endpoint call of the dataSource
pipeline which goes through the following steps:
-
Initialize the query time range: The
startTime
andendTime
are set and applied to the pipeline message payload -
Invoke the library function: The message payload is merged with the function
farg
and the lib is invoked
{
"type": "plotly",
"dataSource": [
{
"type": "gettime", // Initialize the start and end-times to pass to the lib call
"set": [
{
"name": "startTime",
"value": "*-1d",
"asEpoch": true // Provide the value as an epoch number
},
{
"name": "endTime",
"value": "*",
"asEpoch": true
}
]
},
{
"type": "function",
"ctx": "/system",
"lib": "myPlotlyLib",
"func": "getScatterData",
"farg": {
// Provide function arguments.
"items": [
"/System/Core/Examples/Demo Data/Process Data/DC4711",
"/System/Core/Examples/Demo Data/Process Data/DC666"
],
"intervals": 100
}
}
],
"plotlyOptions": {
},
// ...
}
The data returned from the lua function will look like this, and matches what the scatter chart expects:
[
{
"mode": "lines",
"name": "DC4711",
"type": "scatter",
"x": [], // Data not shown
"y": []
},
{
"mode": "lines",
"name": "DC666",
"type": "scatter",
"x": [], // data not shown
"y": []
}
]
Query the data with syslib endpoints and transform it in a pipeline:
This approach has the benefit that no custom Lua script is needed but comes at the expense of having to transform the data and add required properties on the client side using transform actions.
The dataSource
of the plotly widget in the fragment below has been modified to execute the following steps.
-
Initialize the query time range: The
startTime
andendTime
are set as before -
Invoke the syslib library function: The message payload is merged with the function
farg
and the lib is invoked
Thereadhistoricaldata
call from thesyslib.api
library is used to ready the values. -
Transform the returned data: A
transform
action is used to get the data in the right shape for the widget.
"dataSource": [
{
"type": "gettime",
"set": [
{
"name": "start_time",
"value": "*-1d"
},
{
"name": "end_time",
"value": "*"
}
]
},
{
"type": "function",
"lib": "syslib.api",
"func": "readhistoricaldata",
"farg": {
"processed_as_item_values": false, // Get the data back as separate V, Q and T arrays
"intervals_no": 100,
"items": [
{
"p": "/System/Core/Examples/Demo Data/Process Data/DC4711",
"aggregate": "AGG_TYPE_INTERPOLATIVE"
},
{
"p": "/System/Core/Examples/Demo Data/Process Data/DC666",
"aggregate": "AGG_TYPE_INTERPOLATIVE"
}
]
}
},
{
"type": "transform",
"aggregateOne": [
{
"$project": {
"data": {
"$map": {
"input": "$data.items",
"in": {
"x": "$$this.intervals.T", // Map x and y values.
"y": "$$this.intervals.V",
"mode": "lines", // add chart properties
"type": "scatter",
"name": { // Use the last segment of the path as the name
"$last": {
"$split": [
"$$this.p",
"/"
]
}
}
}
}
}
}
}
]
}
]
Use query endpoints together with plotlyOptions.layout
templates
In this implementation the approach is to place all properties which are not read from the backend into a layout template` inside the model.
In our example the mode
and name
properties are moved to the plotlyOptions.layout
section of the model.
{
"dataSource": [
{
"type": "gettime",
"set": [
{
"name": "start_time",
"value": "*-1d"
},
{
"name": "end_time",
"value": "*"
}
]
},
{
"type": "function",
"lib": "syslib.api",
"func": "readhistoricaldata",
"farg": {
"processed_as_item_values": false,
"intervals_no": 100,
"items": [
{
"p": "/System/Core/Examples/Demo Data/Process Data/DC4711",
"aggregate": "AGG_TYPE_INTERPOLATIVE"
},
{
"p": "/System/Core/Examples/Demo Data/Process Data/DC666",
"aggregate": "AGG_TYPE_INTERPOLATIVE"
}
]
}
},
{
"type": "transform",
"aggregateOne": [
{
"$project": {
"data": {
"$map": {
"input": "$data.items",
"in": { // The transform logic is only concerned with the X and Y values
"x": "$$this.intervals.T",
"y": "$$this.intervals.V"
}
}
}
}
}
]
}
],
"plotlyOptions": {
"layout": {
"xaxis": {
"showgrid": true,
"type": "date", // ensures X values are interpreted as date values
"autorange": true
},
"template": {
"data": {
"scatter": [
{
"mode": "lines",
"name": "DC4711"
},
{
"mode": "lines",
"name": "DC666"
}
]
}
}
}
}
}
onClick events
Plotly Click Events documentation.
Plotly chart can handle on click triggered event. Based on a click event on a Plotly chart, the onClick
action defined
in the Widget model is executed.
When onClick
action is defined, received data format depends on Plotly Display ModeBar
mode selection. Default mode
is Compare data on hover
, with this selection all data points that are defined on the same x axis will be received.
Another option is Show closest data on hover
, when this mode is selected only selected data point is received.
Charts that do not support click events:
-
Gauge charts
-
Bullet chart
-
Indicator
{
"actions": {
"onClick": [
{
"type": "send",
"to": "debugger"
},
{
"type": "transform",
"aggregateOne": [
{
"$project": {
"text": "$points.0.label"
}
}
]
}
]
}
}
Scatter Plots
Plotly Scatter Plots documentation.
-
Mode (Markers, markers+text, line+markers)
-
Name
-
Marker (size, color, opacity)
-
Text (labels, text position, text font)
{
"data": [
{
"type": "scatter",
"x": [
1,
2
],
"y": [
10,
15
],
"mode": "markers+text",
"name": "Team A",
"text": [
"A-1",
"A-2"
],
"textposition": "top center",
"textfont": {
"family": "Raleway, sans-serif"
},
"marker": {
"size": 12
}
}
]
}
Line Charts
Plotly Line Charts documentation.
-
Line (lines, markers, lines+markers)
-
Name
-
Marker (size, color, opacity)
-
Line (color, opacity, width)
{
"data": [
{
"type": "scatter",
"x": [
1,
2
],
"y": [
10,
15
],
"mode": "lines+markers",
"marker": {
"color": "red",
"size": 8
},
"line": {
"color": "red",
"width": 1
}
}
]
}
Bar Charts
Plotly Bar Charts documentation.
-
Orientation (h, v)
-
Name
-
Text
-
Text Position
-
Hover Info
-
Marker (color, opacity, line(color, opacity, width))
{
"data": [
{
"type": "bar",
"x": [
"Line 1",
"Line 2"
],
"y": [
20,
14
],
"name": "Cologne",
"text": [
"20",
"14"
],
"textposition": "auto",
"hoverinfo": "none",
"marker": {
"color": "blue",
"opacity": 0.6,
"line": {
"color": "blue",
"width": 1.5
}
}
}
]
}
Layout Options:
-
Bar Mode (group, stack)
-
Bar Gap
{
"plotlyOptions": {
"layout": {
"barmode": "group",
"bargap" :0.05
}
}
}
Pie Charts
Plotly Pie Charts documentation.
-
Labels
-
Domain (row and column or x and y)
-
Hole (for donut chart)
-
Text Info (label, percent, label+percent)
-
Inside Text Orientation (radial)
-
Auto margin
-
Text Position (outside (inside is default))
{
"data": [
{
"values": [
10,
30,
60
],
"labels": [
"1st",
"2nd",
"3rd"
],
"type": "pie",
"textinfo": "label+percent",
"textposition": "outside",
"insidetextorientation": "radial",
"automargin": true,
"hole": 0.4,
"domain": {
"row": 0,
"column": 0
}
}
]
}
Layout Options:
-
Height
-
Width
-
Grid (rows, columns)
{
"plotlyOptions": {
"layout": {
"height": 400,
"width": 500,
"grid": {
"rows": 2,
"columns": 2
}
}
}
}
Filled Area Plots
Plotly Filled Area Plots documentation.
-
Fill (tozeroy, tonexty, toself)
-
Fill Color
-
Mode (none)
-
Stack Group
-
Group Norm (percent)
-
Hoveron (points+fills)
-
Line (color, opacity)
-
Text
-
Hoverinfo (text)
{
"data": [
{
"type": "scatter",
"x": [
1,
2
],
"y": [
0,
2
],
"fill": "tonexty",
"mode": "none"
}
]
}
Layout Options:
-
X-axis (range)
-
Y-axis (range)
{
"plotlyOptions": {
"layout": {
"xaxis": {
"range": [
0,
5
]
},
"yaxis": {
"range": [
0,
3
]
}
}
}
}
Box Plot
Plotly Box Plot documentation.
-
Box Points
-
Jitter
-
Point Pos
-
Whisker Width
-
Fill Color
-
Marker (color, opacity)
-
Line
-
Box points (false, outliers, suspectedoutliers),
-
Box mean (true, sd)
-
Orientation (h, v)
{
"data": [
{
"type": "box",
"y": [
0,
1,
1,
2,
3,
5,
8,
13,
21
],
"boxpoints": "all",
"jitter": 0.3,
"pointpos": 0,
"whiskerwidth": 0.2,
"fillcolor": "white",
"boxpoints": "Outliers",
"marker": {
"size": 5
},
"line": {
"width": 1
}
}
]
}
Layout Options:
-
Box Mode (group, stack, overlay)
{
"plotlyOptions": {
"layout": {
"boxmode": "group"
}
}
}
Histogram
Plotly Histograms documentation.
-
Name
-
Marker (color, opacity line(color, opacity, width))
-
Auto Bin x
-
Auto Bin y
{
"data": [
{
"type": "histogram",
"y": [
20,
21,
23,
21,
22,
28,
29,
30,
19,
33
],
"marker": {
"color": "blue",
"opacity": 0.2
}
},
{
"type": "histogram",
"y": [
25,
26,
28,
20,
21,
23,
21,
22,
28,
29
],
"marker": {
"color": "red",
"opacity": 0.2
}
}
]
}
Layout Options:
-
Bar Mode (group, stack, overlay)
-
Bar Gap
-
Bar Group Gap
{
"plotlyOptions": {
"layout": {
"paper_bgcolor": "white",
"barmode": "overlay",
"bargap": 0.05,
"bargroupgap": 0.2
}
}
}