Skip to content

Custom plotting

During a BLISS session, users may create data (other than scan data) that needs to be displayed graphically. Flint offers a collection of different type of plots (curve, scatter, image…) so user can select the one that fit the with the data to be displayed.

Basic plot display

A generic display is provided through the BLISS plot() command.

It checks the data dimensionality to select the kind of charts.

This can be convenient for basic display.

Screenshot

# Display a list (as a single curve using index as x-axis)
plot([1, 2, 3, 1, 2, 3])

import numpy

# Display a 1D data (as a single curve using index as x-axis)
array = numpy.array([1, 2, 3, 1, 2, 3])
plot(array)

# Display a 2D data (as an image)
image = numpy.array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])
plot(image)

# Display a 3D data (as a stack of images)
cube = numpy.arange(1000)
cube.shape = 10, 10, 10
plot(cube)

Create a plot

To use more features another way is provided.

First a plot has to be created from Flint.

The first argument (here curve) is used to select the kind of expected plot. See the following documentation for example of each kind.

f = flint()
p = f.get_plot("curve")

Other arguments are available to edit some behavior of this plot.

A title can be specified, a unique name can be set to reuse plots instead of creating a new one. The plot can be closeable (default is true) or selected by default at the creation (default is false).

p = f.get_plot("curve",
               name="My plot title",
               unique_name="myplot42",
               closeable=True,
               selected=True)

1D plot / curve plot

The main plot is a curve plot.

It can be used to display several 1D data as curves.

import numpy

# Create the plot
f = flint()
p = f.get_plot("curve", name="My plot")

# Create data
t = numpy.linspace(0, 10 * numpy.pi, 100)
s = numpy.sin(t)
c = numpy.cos(t)

# Update the plot
p.add_curve(t, c, legend="aaa")  # the legend have to be unique
p.add_curve(t, s, legend="bbb")

# Clean up the plot
p.clean_data()

This also can be used to display parametric functions

import numpy

t = numpy.linspace(-3, 3, 50)
x = 16 * numpy.sin(t)**3
y = 13 * numpy.cos(t) - 5 * numpy.cos(2*t) - 2 * numpy.cos(3*t) - numpy.cos(4*t)

f = flint()
p = f.get_plot("curve", name="My heart")
p.add_curve(x, y, legend="heart")

Few functions are available to tune the axes

p.xlabel = "It's the time"
p.yscale = "log"
p.xscale = "linear"

Descriptive 1D plot

The 1D plot also provides a descriptive mode. In this mode, there is a split between the data and the way it is rendered.

The description of the rendering is done by a layer of items. First this description have to be provided, then the data can be set.

When data for axis are shared, it’s also a convenient way to only transfer data once.

import numpy

# Create the plot
f = flint()
p = f.get_plot("curve", name="My plot")

# Create the data
t = numpy.linspace(0, 10 * numpy.pi, 100)
s1 = numpy.sin(t)
s2 = numpy.sin(t + numpy.pi * 0.5)
s3 = numpy.sin(t + numpy.pi * 1.0)
s4 = numpy.sin(t + numpy.pi * 1.5)

# Describe the plot
p.add_curve_item("t", "s1")
p.add_curve_item("t", "s2")
p.add_curve_item("t", "s3")
p.add_curve_item("t", "s4")

# Transfer the data / and update the plot
p.set_data(t=t, s1=s1, s2=s2, s3=s3, s4=s4)

# As the plot description is already known
# The plot can be updated the same way again
p.set_data(t=t+1, s1=s1+1, s2=s2+1, s3=s3+1, s4=s4+1)

# Clean up the plot
p.clean_data()

For complex plot, if you want to handle properly the refresh of the plot a transaction can be used. It will enforce a signle update of the plot at the end of the transaction.

with p.transaction():
    p.clear_items()
    p.add_curve_item("x", "y", legend="item1")
    p.add_curve_item("x", "w", legend="item2")
    p.remove_item(legend="item2")
    p.set_data(x=[1])
    p.append_data(x=[2, 3, 4, 5])
    p.set_data(y=[6, 5, 6, 5, 6])

Plot3D

A 3D plot is provided.

For now it supports scatters and meshes.

# create the plot
f = flint()
p = f.get_plot("plot3d", name="My plot")

# describe the items to display
p.add_scatter_item("x", "y", "z", "value", legend="item1",
                   symbol="o", symbol_size=50, lut="viridis")
p.add_mesh_item("vertexes", "faces", legend="item2")

# update the data
p.set_data(
    x=[0, 1, 2], y=[0, 1, 0], z=[0, 0, 1], value=[0, 1, 2],
    vertexes=[[0, 0, 0], [1, 1, 0], [2, 0, 1]],
    faces=[[0, 1, 2]],
)

Scatter plot

A 2D scatter plot is provided.

A scatter is a group of of three 1D data of the same length. Each of them respectively contains x-locations, y-locations and values.

The widget provides different visualization mode to display the data as points, or with a solid rendering, including 2D histogram rendering.

import numpy

# Create the plot
f = flint()
p = f.get_plot("scatter", name="My plot")

# Create the data and setup the plot
y, x = numpy.ogrid[:10, :10]
x, y = numpy.zeros_like(y) + x, numpy.zeros_like(x) + y
x, y = x.flatten(), y.flatten()
v = numpy.sin(numpy.sqrt((x-5)**2 + (y-5)**2))
p.set_data(x, y, v)

# The colormap can be updated
p.set_colormap(lut="red")

Screenshot

Image plot

A plot is provided to display a specific image.

It provides a dedicated view to display a single image, with tools to provides vertical and horizontal histograms.

import numpy

# Create the plot
f = flint()
p = f.get_plot("image", name="My plot")

# Create the data and setup the plot
y, x = numpy.ogrid[:10, :10]
image = numpy.sin(numpy.sqrt((x-5)**2 + (y-5)**2))
p.set_data(image)

# The colormap can be updated
p.set_colormap(lut="red")

# The direction of the y-axis can be specified
p.yaxis_direction = "down"

Screenshot

In case the side histograms are not needed and take space for nothing, this can be hidden the following way.

p.side_histogram_displayed = False

2D plot

Another 2D plot is provided to allow to compose a view with many images. It provides less tools than the dedicated image plot.

import numpy

# Create the plot
f = flint()
p = f.get_plot("plot2d", name="My plot")

# Create the data and setup the plot
y, x = numpy.ogrid[:10, :10]
image1 = numpy.sin(numpy.sqrt((x-5)**2 + (y-5)**2))
image2 = numpy.cos(numpy.sqrt((x-5)**2 + (y-5)**2))
p.add_image(image1, origin=(0, 0), scale=(0.5, 0.5), legend="img1")  # legend have to be unique
p.add_image(image2, origin=(5, 0), scale=(0.5, 0.5), legend="img2")

# Clean up the plot
p.clean_data()

Screenshot

Curve stack

This plot displays a single curve from a selectable list of curves.

The data have to be provided as a 2D array. The slow axis is used as the axis of the curve.

The selection is done with a slider.

import numpy

# Create the plot
f = flint()
p = f.get_plot(plot_class="curvestack", name="My curve stack")

# Create the data and setup the plot
curves = numpy.empty((10, 100))
for i in range(10):
    curves[i] = numpy.sin(numpy.arange(100) / 30 + i * 6)
x = numpy.arange(100) * 10
p.set_data(curves=curves, x=x)

Screenshot

Image stack

This plot displays a single image from a stack of image.

The data have to be provided as a 3D array. The 2 first slow axis are used as the image axes.

A slider is provided to browse the images.

import numpy

# Create the plot
f = flint()
p = f.get_plot(plot_class="stackview", name="My image stack")

# Create the data and setup the plot
cube = numpy.arange(10 * 10 * 10)
cube.shape = 10, 10, 10
cube = numpy.sin(cube)
p.set_data(cube)

# The colormap can be updated
p.set_colormap(lut="red")

Screenshot

Time curve plot

Screenshot

A dedicated plot is provided to display curve data with time as x-axis.

It’s the plot used by the regulation framework.

This is useful to simplify the display of a fixed period of time (the last x seconds), and to update the data using the new known data only.

The GUI allow the user to change the last displayed period of time displayed.

# Create the plot
f = flint()
p = f.get_plot(plot_class="timecurveplot", name="My plot")

# Setup the plot to display a dedicated data name
# The data will be provided later
# the `time` data name is used as x-axis
p.add_time_curve_item("diode1")
# The curve style can be specified
p.add_time_curve_item("diode2", color="red")

# The data can be set
# The time have to be provided in epoch second UTC (see python API `time.time()`)
p.set_data(time=[0, 1, 2], diode1=[0, 1, 1], diode2=[1, 5, 1])

# The data also can be appended
p.append_data(time=[3], diode1=[2], diode2=[6])

# Old data is dropped automatically
# This can be setup programatically
p.select_x_duration(second=5)

# And data can be cleared
p.clear_data()

Grid container

A grid container can be created to structure multiple data plots inside.

Screenshot

The container provides a get_plot method. Extra argument can be passed like row, col, row_span, col_span in order to localize the plot to the grid.

# Create the container
f = flint()
container = f.get_plot("grid", name="Grid", selected=True)

# Create the sub plots
p1 = container.get_plot("curve", row=0, col=0)
p2 = container.get_plot("curve", row=0, col=1)
p3 = container.get_plot("curve", row=1, col=0)
p4 = container.get_plot("curve", row=1, col=1)

# Now you can add data to each plots
p1.add_curve([0, 1, 2, 3], [1, 2, 1, 2])
p2.add_curve([0, 1, 2, 3], [2, 1, 2, 1])
p3.add_curve([0, 1, 2, 3], [3, 2, 1, 0])
p4.add_curve([0, 1, 2, 3], [0, 1, 2, 3])

Extra commands

Plots provide few extra commands.

# Create a plot
f = flint()
p = f.get_plot(plot_class="plot1d", name="My plot")

The plot life cycle can be checked and changed with this commands:

if p.is_open():
    p.close()

Set the focus on a specific plot can be set the following way:

p.focus()

A plot can be exported to the logbook this way:

p.export_to_logbook()

From scripts

From a scripts Flint also can be used to display plot.

The plot() command can be imported the following way:

from bliss.common.plot import plot

plot([1, 2, 3, 4, 5, 6])

Flint and it’s plot API can be imported the following way:

from bliss.common.plot import get_flint

f = get_flint()
p = f.get_plot("plot1d", name="My plot")

Custom plot class

If none of this charts fit your needs there is still a way to write your own plot embedded inside Flint.

See the custom plot class documentation.