Writing Artists¶
In Steamshovel, an Artist is a class that defines how to generate a visualization from input data. This document is a guide to creating your own Artists, and thus your own customized Steamshovel visualizations. It is intended as a companion to the detailed shovelart documentation.
This guide focuses on writing artists in Python using the icecube.shovelart
module. Unless otherwise specified, all types named in this guide are part
of shovelart
. It is common to import * from this module at the head of an
artist file.
The easiest way to learn how to write artists is to study the examples in
steamshovel/python/artists
.
What’s in an Artist¶
Most artists accept keys. A key is the name of an a FrameObject in an I3Frame, e.g I3Geometry
. Artists must define how many keys they require, as well as a way of evaluating whether a given key is valid for the current frame. In simple cases, it is enough to provide a list of FrameObject types – e.g. an artist that requires an I3Geometry
and an I3Particle
, just needs this member field requiredTypes = [I3Geometry, I3Particle]
.
The second way (now more common) is to overwrite the member function isValidKey
and set numRequiredKeys
, as explained below. Artists that don’t require any frame objects as input may use numRequiredKeys = 0. Such Artists can be used even if no file is loaded.
Artists may accept settings to define their visual style. Settings can be of various types, such as numbers or ranges or colors. They can be set by the user through the Steamshovel GUI, or through the python scripting layer. Settings can determine e.g. the width of a line or the size of a sphere in the visualization.
Artists can be written in either Python or C++, but writing in Python is highly recommended, and this guide focuses on that approach.
Artists, SceneObjects, and SceneVariants¶
Steamshovel has an abstraction layer that was not present in glshovel: unlike glshovel’s Renderer classes, Artists do not draw anything on the screen directly. Instead, Artists read their inputs and create a set of SceneObjects. SceneObjects are primitive visible objects like spheres, cylinders, text, or image overlays. SceneObjects are generally written in C++ and contain relatively low-level OpenGL code.
SceneObject properties, such as size and location, are controlled by SceneVariants, which are objects that implement time-valued functions of various types. Artists create animated visual output by creating appropriate SceneObjects, and applying appropriate SceneVariants to them.
Defining an Artist in Python¶
An artist must inherit the icecube.shovelart.PyArtist
type. The required methods and properties are:
- method
create(self, frame, output)
: Method to be called when the artist can generate visible SceneObjects. The
frame
argument is the current I3Frame, and will never beNone
unless the artist specified that it does not use keys. Theoutput
argument is ashovelart.SceneGroup
object, which can create SceneObjects as described below.
Keys¶
To specify keys, an artist can either provide a property requiredTypes
that is a list of required key types, e.g. requiredTypes = [ dataclasses.I3Geometry, dataclasses.I3Particle ]
, or else provide a number of keys and a method to evaluate whether they are valid.:
numRequiredKeys = 2
def isValidKey( self, frame, key_idx, key ):
'''Return true if frame[key] is a valid key for the key_idx'th key of this Artist'''
Defining an isValidKey
method allows an artist to accept multiple types for a key index. This technique is used by most Python artists. If an artist class requires no keys at all, it can simply set its numRequiredKeys
property to 0.
Note that it is possible, but not recommended, for an artist to define both requiredTypes
and isValidKey
. In that case, isValidKey
will have final say in whether a key is valid.
Settings¶
If an artist defines settings, they should be set up in its constructor with a call to self.defineSettings
.
Such constructors look like this::
def __init__(self):
PyArtist.__init__(self)
self.defineSettings((
"size", RangeSetting(0.0, 100.0, 100, 90.0),
"color", PyQColor.fromRgb(255, 0, 255)
))
The defineSettings
method takes alternating sequence of setting names and setting objects. This method may not be called outside a constructor. Setting names are always strings. Setting objects may be a number of types, a detailed list is given below.
Settings may be accessed from within a create
method by calling self.setting(name)
, where name
is the string that was given in the constructor. The return type from this method will depend on what the setting was defined as. Artists cannot change the value of their settings, and they should not change the number of keys they require, as this will cause problems with the Steamshovel GUI.
Available Setting types¶
Booleans: Defining a setting as either True or False will present it as a checkbox in the GUI.
Integers: Defining a setting as an integer will allow it to be set to any integer in the GUI.
Strings: A setting can be an ascii string, settable in the GUI.
Floating point ranges: A setting of type RangeSetting
defines a range of floating point numbers with mimimum and maximum values, and a step size. When defined, they must also be set to a particular step. Ranges appear in the GUI as a slider.
Colors: A setting of type PyQColor
will allow the user to access a color picker in the GUI.
Colormaps: A setting of type I3TimeColorMap
will allow the user to choose among the color maps provided by the Steamshovel application.
Fonts: A setting of type PyQFont
will allow the user to choose a system font; this is useful for creating textual overlays.
Choice: A setting of type ChoiceSetting
offers a choice from a predefined list of strings. It is set in the GUI through a combo box.
Optional Frame Key: A setting of type KeySetting
defines one or several types of I3FrameObjects that may be optionally used by the Artist and a default key. The setting appears in the GUI as a choice of keys from the current frame that have a matching types.
Artists that respond to selected DOMS: If your artist needs to respond to the user’s mouse selection of DOMs, it should have a setting of type OMKeySet
. See the Waveform artist for an example of how to use this type of setting.
Available SceneObject types¶
In a PyArtist, SceneObjects are created by calling the add functions of the output
parameter that is passed to the create()
method. The output
parameter has type SceneGroup
, and its members are documented in the shovelart docs
Available SceneVariant types¶
Variants are objects that define a value that changes over time. The default types of variant are VariantFloat
, VariantVec3d
, and VariantQColor
. Their named subtypes follow a consistent pattern, e.g. ConstantFloat
and StepFunctionVec3d
.
Constants¶
The simplest form of variant is a constant. Most SceneObjects accept constants in their constructors and automatically convert them to constant variants under the hood, so it is rarely necessary to create a constant variant directly.
Step functions¶
The most common form of variant is a step function, which undergoes one or more instantaneous value changes over time. The constructor of a step function specifies its initial value. The add(value, time)
method specifies a new value that applies after the given time. Value/time pairs should be added in order by time.
A common use of a step function is to create a sphere whose radius is initially zero, but which becomes nonzero (thus making the sphere visible) at a particular time. The following code snippet accomplishes this::
# The initial radius of the sphere will be ignored after the call to setSize() below
sphere = output.addSphere( 10., position )
sizefunc = StepFunctionFloat(0)
# Set the sphere radius to 10 units after 400 ns
sizefunc.add( 10, 400 )
s.setSize( sizefunc )
Linear interpolation functions¶
LinterpFunction variants work the same as StepFunctions, but perform linear interpolation between points, allowing gradual changes of value.
Custom Python variants¶
It is possible to write a custom subclass of shovelart.VariantFloat
, etc. This involves
creating a subclass of shovelart.PyVariant*
, where * is the type of your choice, and providing
a value(self, time)
method that returns the variant’s value at the specified time. An example
of a PyVariantVec3d
can be found in the python/resources/test/shovelscripts/Tank.py
artist.
PyVariants are a great deal slower than the built-in variant types. If your artist generates many customized python variant artists, program performance will suffer. In such a case it may be desirable to create a new type of variant in C++ and export it via the pybindings.
Matplotlib artists (MPLArtists)¶
Artists that generate plots using matplotlib work similarly to basic PyArtists, but there are several
differences. Such artists should subclass the steamshovel.artists.MPLArtist.MPLArtist
class.
Instead of a create
method, they define a method create_plot(self, frame, fig)
. As with create
,
the frame
argument is the current I3Frame. The fig
argument is a Matplotlib figure to which
the artist should draw its output.
Matplotlib artists may be animated so that they change as the currently displayed time changes.
An animated matplotlib artist defines an additional method update_plot(self, time)
, where the
time
argument is the currently displayed time. This method is called whenever the time
changes, and can be used to update values in the plot. See the DOMLaunchHist.py artist for an
example. Animated plots will be given a boolean Animated
setting to allow users to enable
or disable the animation. Animated plots are, in general, very slow, and may be of more use in
movies than in interactive Steamshovel use.
Adding a new Artist to your Steamshovel session¶
To add an Artist to your current steamshovel session, pass the artist type to a Scenario’s
registerArtist
method. (See also scripting.rst).
For example, say you have a module CoolArtist.py within a package called myartists. Within CoolArtist.py, the CoolArtist class subclasses PyArtist. You can add this artist to the steamshovel scenario as follows::
from myartists import CoolArtist
window.gl.scenario.registerArtist( CoolArtist.CoolArtist )
Your artist will now appear in the list of available artists. Instances of this artist can be added to the Scenario in the GUI, or from the python prompt as follows::
window.gl.scenario.add( "CoolArtist" )
Adding a new Artist to everyone’s Steamshovel sessions¶
To permanently install a Python artist in Steamshovel, add it to the package
icecube.steamshovel.artists
. The artist’s module and class names must match (i.e.,
define an artist MyArtist within MyArtist.py). Be sure to svn add
your artist file!
Artist FAQ¶
Question: Can keys be optional? I have an artist that requires one key and could usefully accept two or three other keys as options.
Answer: Optional keys can be implemented with the KeySetting
described above.
Artists in C++¶
Python artists are easier to write and maintain, and are suitable for most new graphics in Steamshovel. However, in some cases it makes more sense to write an artist in C++.
The same basic rules for Artists apply: they must have a set of required keys, and a set of settings. Access to keys and settings is more complex in C++ due to its type system. The examples in steamshovel/private/shovelart/artists
are the best guides for writing C++ artists. Check out the Artist.h
header as well.
New C++ artists cannot be added to steamshovel at runtime. To add a new artist at compile time, add its header file and its implementation file to directory steamshovel/private/shovelart/artists
. Make sure that the file name matches the class name, and that you use the two ARTIST_REQUIRED_TYPES(...)
and REGISTER_ARTIST(...)
in the header file.