Graphics#

A Graphic is something that can be added to a PlotArea (described in detail in the layouts section). All the various fastplotlib graphics, such as ImageGraphic, ScatterGraphic, etc. inherit from the Graphic base class in fastplotlib/graphics/_base.py. It has a few properties that mostly wrap pygfx WorldObject properties and transforms.

Inheritance Diagram#

Graphic
│
├─ ImageGraphic
│
├─ TextGraphic
│
├─ PositionsGraphic
│   │
│   ├─ LineGraphic
│   │
│   └─ ScatterGraphic
│
└─ GraphicCollection
    │
    └─ LineCollection
        │
        └─ LineStack

All graphics can be given a string name for the user’s convenience. This allows graphics to be easily accessed from plots, ex: subplot["some_image"].

All graphics contain a world_object property which is just the pygfx.WorldObject that this graphic uses. Fastplotlib keeps a private global dictionary of all WorldObject instances and users are only given a weakref proxy to this world object. This is due to garbage collection. This may be quite complicated for beginners, for more details see this PR: fastplotlib/fastplotlib#160 . Furthermore, garbage collection is even more complicated in ipython and jupyter (see fastplotlib/fastplotlib#546 ). If you are curious or have more questions on garbage collection in fastplotlib you’re welcome to post an issue :D.

Graphic collections are collections of graphics. For now, we have a LineCollection which is a collection of LineGraphic objects. We also have a LineStack which inherits from LineCollection and gives some fixed offset between LineGraphic objects in the collection. A graphic collection behaves like an array of graphics.

Graphic Properties#

Graphic properties are all evented, and internally we call these “graphic features”. They are the various aspects of a graphic that the user can change. The “graphic features” subpackage can be found at fastplotlib/graphics/_features. As we can see this is a private subpackage and never meant to be accessible to users.

For example let’s look at LineGraphic in fastplotlib/graphics/line.py. Every graphic has a class variable called _features which is a set of all graphic properties that are evented. It has the following evented properties: "data", "colors", "cmap", "thickness" in addition to properties common to all graphics, such as "name", "offset", "rotation", and "visible"

Now look at the constructor for the LineGraphic base class PositionsGraphic, it first creates an instance of VertexPositions. This is a class that manages vertex positions buffer. For the user, it defines the line data, and provides additional useful functionality. It defines the line, and provides additional useful functionality. For example, every time that the data is changed, the new data will be marked for upload to the GPU before the next draw. In addition, event handlers will be called if any event handlers are registered.

VertexColors behaves similarly, but it can perform additional parsing that can create the colors buffer from different forms of user input. For example if a user runs: line_graphic.colors = "blue", then VertexColors.__setitem__() will create a buffer that corresponds to what pygfx.Color thinks is “blue”. Users can also take advantage of fancy indexing, ex: line_graphics.colors[bool_array] = "red" 😊

LineGraphic also has a VertexCmap, this manages the line VertexColors instance to parse colormaps, for example: line_graphic.cmap = "jet" or even line_graphic.cmap[50:] = "viridis".

LineGraphic also has a thickness property which is pretty simple, and DeletedFeature which is useful if you need callbacks to indicate that the graphic has been deleted (for example, removing references to a graphic from a legend).

Other graphics have properties that are relevant to them, for example ImageGraphic has cmap, vmin, vmax, properties unique to images.