The pamphlet of the gulik

Note

This documentation is still a work in progress and as such subject to sudden changes, cataclysms and various other FNORDs. The software it describes is still in alpha and may cause undue frustration if not taken in moderation.

_images/gulik.png
This is ST. GULIK. He is the Messenger of the Goddess.
A different age from ours called him Hermes.
Many people called him by many names.
He is a Roach.

Quickstart

Install!

[pkg|apt|dnf|fnord] install gtk3
pip[-3.6] install --user https://rnd.phryk.net/phryk-evil-mad-sciences-llc/gulik

Run!

gulik

Done!

That’s literally everything needed to get gulik to run. If you want to go deeper, you can…

Configure!

$EDITOR ~/.config/gulik/config.py

See also: Configuration file.

Definitional bullshit

gulik is a highly configurable graphical system monitor.

gulik is a framework for custom graphical system monitors.

Both of these statements are true in some sense, false in some sense, meaningless in some sense, true and false in some sense, true and meaningless in some sense, false and meaningless in some sense and true and false and meaningless in some sense.

This incarnation of our most holy saint gulik is software licensed under the GPLv3 license, see COPYING for more details.

The official git repository for gulik can be found at:

The PNG gulik logo is based on a nice public domain trace of the sacred roach crafted by toa267 who is definitely not a cabbage.

Compatibility and dependencies

gulik should skitter just fine on FreeBSD and the Linuxoids. It will probably™ crawl into problems on OSX and other BSDs, but give us a holler if it doesn’t run on your *nix flavor of choice and you’re willing to do some testing.

All bets are off on Windows®™ʷᵗᶠ unless someone else is willing to do a PR, which we expect will be a long march through the valley of pain that we do not wish upon anyone.

gulik runs only on python 3.6 or newer. All python dependencies are noted in setup.py, ready for use in pip.

The only other dependency is gtk3. It does run with X11 and should run with wayland, but the latter hasn’t been tested.

To get partial transparency working (on X11) you need to have a compositing manager like xcompmgr running.

Installation

You can use pip to install gulik and all python dependencies in one go:
pip install --user git+https://rnd.phryk.net/phryk-evil-mad-sciences-llc/gulik/

If you insist on manual installation, just clone the repository and copy the gulik subdirectory into your site-packages directory and bin/gulik to a directory in your $PATH.

The master branch of the repository always holds the most current release.

Running

You run gulik simply by running the gulik executable that comes with the installation.

Configuration and Customization

Default behavior

By default, gulik will occupy a 200 pixel wide area over the full height of the screen, placed at the left border of it and fill it with a few visualizers to grant you a good overview of what’s happening on your system.

It will use a black/white/green color scheme with a hue-rotation palette ranging from lime green to magenta-ish pink and try to use the League of Movable Type font Orbitron which we very much recommend you install to get the right dystopian vibe.

Configuration file

You can modify the settings for gulik by creating a configuration file at ~/.config/gulik/config.py. This file, as it’s name suggests, is a python code file. gulik will import and exec() it, loading all UPPERCASE variables into its configuration.

Lock and reload

When gulik is running, you can send SIGUSR1 to its main process at any time to tell it to reload the configuration file and apply its settings. If your configuration file is broken, gulik will keep running with the previous settings.

Sending the signal is currently a bit clunky, as you’ll have to do something like: kill -s SIGUSR1 `pgrep -f 'python3.6.*gulik$'` since python applications always have the process name of the python interpreter.

Explaining ALL THE CONFIGURATION OPTIONS (not really, tho)

  • FPS (int or float): Frames Per Second; How often to redraw the window (and update system data). Default value: 1
  • WIDTH (int): The width of the window in pixels. Default value: 200
  • HEIGHT (int): The height of the window in pixels. Default value: Gdk.Screen().get_default().get_height()
  • X (int): X coordinate of the windows top left corner. Default value: 0
  • Y (int): Y coordinate of the windows top left corner. Default value: 0
  • NETDATA_HOSTS (list): netdata hosts to connect to. Hosts as hostnames or (host, port) tuples. Default value: []
  • NETDATA_RETRY (int or float): How long a defective NetdataMonitor will wait before retrying to contact the netdata server, in seconds. Default value: 5
  • BSD_ACCURATE_MEMORY (bool): Use accurate but expensive memory data collection on BSD. Default value: False
  • MARGIN (int or float): Margin around all Visualizers. Default value: 5
  • PADDING (int or float): Padding around all Visualizers. Default value: 5
  • FONT (str): Font family to use in captions, legends and the like. Default value: "Orbitron"
  • FONT_WEIGHT (str): Font weight. Default value: "Light"
  • FONT_SIZE (int or float): Font size in pixels. Default value: 10
  • COLOR_WINDOW_BACKGROUND (Color): Background color of the window. Default value: Color(0.05, 0.05, 0.05, 0.8)
  • COLOR_BACKGROUND (Color): Background color for Visualizers. Default value: Color(1,1,1, 0.1)
  • COLOR_FOREGROUND (Color): Foreground color. This is used as base color for most palettes. Default value: Color(0.5, 1, 0, 0.6)
  • COLOR_CAPTION (Color): Text color for captions. Default value: Color(1,1,1, 0.6)
  • PALETTE (function): The default palette generator. Default value: functools.partial( palette_hue() , distance=-120)
  • PATTERN (function): The default pattern generator. Default value: stripe45
  • CAPTION_PLACEMENT (str): "padding" to have captions placed in the paddings of Visualizers, "inner" to place them within the drawing region of the Visualizer. Default value: "inner"
  • LEGEND (bool): Whether Visualizers should attempt automatically creating a legend for themselves in their bottom padding. Default value: True
  • LEGEND_ORDER (str): Whether to reverse the legend order. Can be "normal" or "reverse". Default value: "normal"
  • LEGEND_SIZE (int or float): Pixel height of one legend cell, including its own margin and padding. Legend font size is inferred from this. Default value: 20
  • LEGEND_PLACEMENT (str): Where to place legends within the Visualizers drawing region. Can be "inner" or "padding". Default value: "padding"
  • LEGEND_MARGIN (int or float): Margin around legends. Default value: 2.5
  • LEGEND_PADDING: Padding around legends. Default value: 0
  • OPERATOR: The blending operator used by Visualizers. Default value: Operator.OVER

Explaining ALL THE ᴀʟʟ ᴛʜᴇ ᴄᴏɴꜰɪɢᴜʀᴀᴛɪᴏɴ ᴏᴘᴛɪᴏɴꜱ (ya rly)

The above list doesn’t really cover all the possible configuration variables you can set, as gulik features a perversion of cascading styles.

Every single option except for FPS, X, Y, NETDATA_HOSTS, NETDATA_RETRY and BSD_ACCURATE_MEMORY can be overriden on a per-class basis by appending an underscore and the class name in uppercase to the variable name. To disable legends on all Plots for example, you would use LEGEND_PLOT = False.

Additionally, MARGIN and PADDING can be set for each side by appending an underscore and one of LEFT, RIGHT, TOP or BOTTOM.

If you want to mix both of these things, the resulting string follows the pattern <name>_<class>_<subname>, for example PADDING_PLOT_RIGHT or LEGEND_MARGIN_ARC_BOTTOM.

Custom setups

By default, gulik will run Gulik.autosetup() to set up a reasonable collection of Visualizers that gives you a good overview of your system – but you can add your own setup function to the configuration file that will be used in stead of the autosetup.

import gulik

def setup(app):

    box = app.box()

    box.place(
        'cpu',
        gulik.Plot,
        elements=['core_0', 'core_1'],
        width=box.width,
        height=box.width + 40
    )

Let’s look at the code, line by line:

def setup(app)
The name of the setup function must be setup, otherwise gulik won’t recognize it. The passed app parameter is a Gulik object.
box = app.box()
Gulik.box() creates a Box, a little helper to make layouting easier. You can limit its size via width and height keyword parameters. If these aren’t supplied, the box will fill the whole window.
box.place(
Box.place() places a new visualizer. Box orders visualizers from left to right and top to bottom.
'cpu'
This is the monitored component we want to visualize elements of. It is needed to look up the right Monitor object for Visualizer instantiation.
gulik.Plot
The visualizer class to be instantiated. A subclass of Visualizer.

All keyword arguments below this are just passed on to the visualizer class, so in this case, Plot. Here, these are:

elements=['core_0', 'core_1'],
Defines the elements to be visualized. These two values refer to the first and second CPU cores.
width=box.width,
Defines the width of the visualizer.
height=box.width + 40
Defines the height of the visualizer. Has 40 pixel added to it, because by default, gulik adds 40 pixel bottom padding to every visualizer to allow 2 lines of legend.

Box.place() uses the width and height keyword parameters (if passed) to make its layouting decisions. If they aren’t passed, all remaining space is used.

And with that, you hopefully know enough to get started with your custom setup. You can consult Monitor and its subclasses to find out what you can visualize and Visualizer and its subclasses to find out how you can visualize that data.

If you want to extend the original setup instead of doing a completely custom one, you can call Gulik.autosetup() from your custom setup function and limit its area by using width and height as well as x and y keyword parameters.

Module reference

Architecture

+-----------------------------------------+
|                                         |
|  gulik process                          |       collector processes
|                                         |
|  (main thread)    (monitor threads)     |
|   Gulik----------- CPUMonitor     <-----ø-----> CPUCollector
|     |         | `- MemoryMonitor  <-----ø-----> MemoryCollector
|     |         |`-- NetworkMonitor <-----ø-----> NetworkCollector
|     |         `--- …              <-----ø-----> …
|     |                   |               |
|     |                   |               |
|     `-- visualizers     |  (visualizers |
|           | `- Arc      |   access      |
|           |`-- Plot   <´    monitors)   |
|           `--- …                        |
|                                         |
+-----------------------------------------+

In gulik, there is one central Gulik object. It manages Monitors and Visualizers.

Visualizers use the Monitor.normalize() and Monitor.caption() functions to utilize the collected data.

Communication between the Monitors within the gulik process and Collector processes is done via queues. Every monitor/collector pair shares two queues. One “update queue” that monitors use to send update requests to collectors and one “data queue” that collectors use to send the next datapoint to their respective monitor.

Box model

+-----------------------------------------------------------+   ↑
|                                                           |   |
|                       margin                              |   |
|                                                           |   |
|   +---------------------------------------------------+   |   |
|   |                                                   |   |
|   |                   padding                         |   |   h
|   |                                                   |   |   e
|   |   +-----------------------------------+  ↑        |   |   i
|   |   |                                   |  | inner  |   |   g
|   |   |       inner drawing region        |  | height |   |   h
|   |   |                                   |  |        |   |   t
|   |   +-----------------------------------+  ↓        |   |
|   |                                                   |   |   |
|   |   ←------------ inner width ----------→           |   |   |
|   |                                                   |   |   |
|   +---------------------------------------------------+   |   |
|                                                           |   |
+-----------------------------------------------------------+   ↓

←--------------------------- width -------------------------→

guliks box model is pretty similar to the one CSS has, with one important distinction: margins and paddings are included in width and height in order to make layouting easier.

Concepts

visualizer

Visualizers are instances of any subclass of Visualizer.

A visualizer is assigned a Monitor and a list of elements.

Gulik will periodically call all visualizers update methods (see source of Visualizer.update()).

What exactly happens in the update function of a visualizer differs between the different classes, but usually it queries the instance-assigned monitor for the most recent data about its elements by calling Monitor.normalize() and then does some drawing on the passed cairo.Context to visualize the data in some manner.

Currently, there are 7 built-in visualizers:

You are, however, welcome to implement your own visualizers by subclassing Visualizer and overriding Visualizer.draw().

monitor

Monitors are instances of any subclass of Monitor, which itself is a subclass of multithreading.Thread.

Every monitor acts as one half of a monitor-collector pair, each of which collects and transforms data on a specific component.

The monitors responsibility in this pair is to take data from the collector and offer it in a form that is usable by visualizers. This is mainly done through the functions Monitor.normalize() and Monitor.caption().

Currently, there are 6 built-in monitors:

collector

Collectors are instances of any subclass of Collector, which itself is a subclass of multiprocessing.Process.

Every collector acts as one half of a monitor-collector pair.

The collectors responsibility in this pair is to collect system usage data and send them to its associated monitor.

component

A string identifying a data source.

Valid values are:
  • 'cpu'
  • 'memory'
  • 'network'
  • 'battery'
  • 'disk'

Besides that, 'netdata-<hostname>' is valid, but only if <hostname> exists in the NETDATA_HOSTS configuration option.

element

A string identifying a (sub) element of a data source. Valid values are defined within the respective Monitors.

alignment

A string in the shape of <x-align>_<y-align>, where:
  • <x-align> can be any of left, center, right
  • <y-align> can be any of top, center, bottom

alignments are used both for text positioning relative to its respective allowed borders as well as positioning captions within Visualizers.

caption description

A dictionary describing a caption to be rendered by a Visualizer.

Required items:
  • text: The text to be rendered
Optional items:
  • position: Either an (x,y) coordinate tuple or an alignment
  • align: An alignment
  • font_size: A number (int or float) denoting vertical font size in pixels
  • font_weight: A string. Normal, Bold, Light, etc.
  • operator: One of cairos blending operators (See cairo.Operator)

pattern

A function taking one Color as parameter returning a cairo surface for use as fill. See stripe45() for an example.

palette

A function taking one Color and one int parameter returning a list of Color objects with its length being equal to the passed int parameter.

Note

palette_hue() and palette_value() have extra parameters you won’t be able to use without wrapping them in functools.partial() first!

combination

A string denoting how multiple elements are displayed within a Visualizer.

Valid values are:
  • separate: separate elements visually
  • cumulative: show values cumulatively, assume data is normalized for that (i.e. all values added max out at 1.0)
  • cumulative_force: like cumulative, but assumes every single value can go up to 1.0
class gulik.Color(red=None, green=None, blue=None, alpha=None, hue=None, saturation=None, value=None)[source]

Magic color class implementing and supplying on-the-fly manipulation of RGB and HSV (and alpha) attributes.

tuple_rgb()[source]

return color (without alpha) as tuple, channels being float 0.0-1.0

tuple_rgba()[source]

return color (with alpha) as tuple, channels being float 0.0-1.0

class gulik.DotDict[source]

A dictionary with its data being readable through faked attributes. Used to avoid [[[][][][][]] in caption formatting.

gulik.palette_hue(base, count, distance=180)[source]

Creates a hue-rotation palette.

Parameters:
  • base (Color) – Color on which the palette will be based (i.e. the starting point of the hue-rotation).
  • count (int) – number of colors the palette should hold.
  • distance (int or float) – angular distance on a 360° hue circle thingamabob.
Returns:

A list of length count of Color objects.

Return type:

list

gulik.palette_value(base, count, min=None, max=None)[source]

Creates a value-stepped palette

Parameters:
  • base (Color) – Color on which the palette will be based (i.e. source of hue and saturation)
  • count (int) – number of colors the palette should hold
  • min (float >= 0 and <= 1) – minimum value (the v in hsv)
  • max (float >= 0 and <= 1) – maximum value
Returns:

A list of length count of Color objects.

Return type:

list

gulik.pretty_si(number)[source]

Return a SI-postfixed string representation of a number (int or float).

gulik.pretty_bytes(bytecount)[source]

Return a human-readable representation given a size in bytes.

gulik.pretty_bits(bytecount)[source]

Return a human-readable representation in bits given a size in bytes.

gulik.ignore_none(*args)[source]

Return the first passed value that isn’t None.

class gulik.Monitor(app, component)[source]

The base class for all monitors.

class gulik.CPUMonitor(app, component)[source]

Memory for CPU usage.

normalize(element)[source]
Elements exposed:
  • aggregate: average cpu use, sum of all core loads divided by number of cores
  • core_<n>: load of core <n>, with possible values of <n> being 0 to number of cores - 1
caption(fmt)[source]
Exposed keys:
  • aggregate: average cpu use, sum of all core loads divided by number of cores
  • core_<n>: load of core <n>, with possible values of <n> being 0 to number of cores - 1
  • count: number of cores
class gulik.MemoryMonitor(app, component)[source]

Monitor for memory usage

normalize(element)[source]
Elements exposed:
  • percent: memory use of all processes.
  • top_<n>: memory use of the <n> h-biggest process. Valid values of <n> are 1-3.
  • other: memory use of all processes except the top 3
caption(fmt)[source]
Exposed keys:
  • total: how much memory this machine has in total,
  • percent: total memory usage in percent.
  • available: how much memory can be malloc’d without going into swap (roughly).
  • top_<n>: access information about the 3 “biggest” processes. possible subkeys are name, size and percent.
  • other: aggregate information for all processes except the top 3. Same subkeys as those, plus 'count.
class gulik.NetworkMonitor(app, component)[source]

Monitor for network interfaces.

count_sec(interface, key)[source]

get a specified count for a given interface as calculated for the last second.

EXAMPLE: self.count_sec('eth0', 'bytes_sent') (will return count of bytes sent in the last second)

normalize(element)[source]
Exposed elements:
  • <if>.bytes_sent: upload of network interface <if>.
  • <if>.bytes_recv: download of network interface <if>.

<if> can be any local network interface as well as ‘aggregate’.

caption(fmt)[source]
Exposed keys:
  • <if>.bytes_sent: upload of network interface <if>.
  • <if>.bytes_recv: download of network interface <if>.
  • <if>.if_up: Boolean, whether the interface is up.
  • <if>.speed: interface speed in Mbit/s
  • <if>.counters: supplies access to interface counters. Possible sub-elements are:
    • bytes_sent
    • bytes_recv
    • packets_sent
    • packets_recv
    • errin
    • errout
    • dropin
    • dropout

<if> can be any local network interface as well as 'aggregate'.

Additionally, the 'aggregate' interface exposes the total count of network interfaces as if_count.

class gulik.BatteryMonitor(app, component)[source]

Monitor laptop batteries.

normalize(element)[source]

This function exposes no explicit elements, but always just returns the current fill of the battery.

caption(fmt)[source]
Exposed keys:
  • power_plugged: Boolean, whether the AC cable is connected.
  • percent: current fill of the battery in percent.
  • secsleft: seconds left till battery is completely drained.
  • state: Current state of the battery, one of 'full', 'charging' or 'draining'.
class gulik.DiskMonitor(*args, **kwargs)[source]

Monitors disk I/O and partitions.

normalize(element)[source]
Elements exposed:
  • io
    • Valid subelements are disk device file names as found in /dev. Examples: ada0, sda.

      Valid subsubelements are as follows:
      • read_bytes
      • write_bytes
      • read_time
      • write_time
      • busy_time
  • partitions
    • Valid subelements are partition device file names as found in /dev, with dots (.) being replaced with dashes (-). Examples: root-eli, sda1.
caption(fmt)[source]

Exposed keys are the same as for DiskMonitor.normalize().

class gulik.NetdataMonitor(app, component, host, port)[source]

Monitor that interfaces with (remote) netdata instances.

normalize(element)[source]

Exposed elements correspond to chart names and their datapoint *dimension*s. For a list of valid chart and dimensions names, consult /api/v1/charts of the netdata instance in question.

Examples

  • system.cpu.nice
  • disk.ada0.writes
caption(fmt)[source]

Exposed keys are the same as for NetdataMonitor.normalize().

class gulik.Visualizer(app, monitor, x=0, y=0, width=None, height=None, margin=None, margin_left=None, margin_right=None, margin_top=None, margin_bottom=None, padding=None, padding_left=None, padding_right=None, padding_top=None, padding_bottom=None, elements=None, captions=None, caption_placement=None, legend=None, legend_order=None, legend_format=None, legend_size=None, legend_placement=None, legend_margin=None, legend_margin_left=None, legend_margin_right=None, legend_margin_top=None, legend_margin_bottom=None, legend_padding=None, legend_padding_left=None, legend_padding_right=None, legend_padding_top=None, legend_padding_bottom=None, foreground=None, background=None, pattern=None, palette=None, combination=None, operator=None)[source]

The base class for all visualizers. Not called widget to avoid naming confusion with gtk widgets (which aren’t even used in gulik).

Usually you won’t instantiate this by yourself but use Box.place().

Parameters:
  • app (Gulik) – The app managing visualizers and monitors
  • monitor (Monitor) – The monitor managing data collection for this visualizer
  • x (int) – leftmost coordinate on the x-axis
  • y (int) – topmost coordinate on the y-axis
  • width (int) – overall width (including margin and padding)
  • height (int) – overall height (including margin and padding)
  • margin (int, optional) – margin applied around all sides
  • margin_left (int, optional) – margin applied to the left side
  • margin_right (int, optional) – margin applied to the right side
  • margin_top (int, optional) – margin applied to the top side
  • margin_bottom (int, optional) – margin applied to the bottom side
  • padding (int, optional) – padding applied around all sides
  • padding_left (int, optional) – padding applied to the left side
  • padding_right (int, optional) – padding applied to the right side
  • padding_top (int, optional) – padding applied to the top side
  • padding_bottom (int, optional) – padding applied to the bottom side
  • elements (list of str) – A list of elements to visualize
  • captions (list of dict, optional) – A list of caption descriptions
  • legend (bool) – Whether to try to automatically create a legend of elements
  • legend_order ('normal' or 'reverse', optional) – Whether to reverse the legend order
  • legend_format (str) – A format string, can contain {element} to refer to the element legend items refer to.
  • legend_size (int, optional) – height of a single legend item
  • legend_placement ('padding' or 'inner') – Where to place the legend
  • legend_margin (int, optional) – margin applied around all sides of the legend
  • legend_margin_left (int, optional) – margin applied to the left side of the legend
  • legend_margin_right (int, optional) – margin applied to the right side of the legend
  • legend_margin_top (int, optional) – margin applied to the top side of the legend
  • legend_margin_bottom (int, optional) – margin applied to the bottom side of the legend
  • legend_padding (int, optional) – padding applied around all sides of the legend
  • legend_padding_left (int, optional) – padding applied to the left side of the legend
  • legend_padding_right (int, optional) – padding applied to the right side of the legend
  • legend_padding_top (int, optional) – padding applied to the top side of the legend
  • legend_padding_bottom (int, optional) – padding applied to the bottom side of the legend
  • foreground (Color, optional) – The foreground color, base-color for generated palettes
  • background (Color, optional) – The background color
  • pattern (function, optional) – An executable pattern
  • palette (function, optional) – An executable palette
  • combination (str, optional) – The combination mode used when displaying multiple elements
get_style(name, subname=None)[source]

load the most specific style setting available given a name and optional subname. usage examples: self.get_style(‘margin’, ‘left’),

legend_info()[source]

defines colors for legend elements

update(context)[source]
Parameters:context (cairo.Context) – cairo context of the window
class gulik.Text(app, monitor, text, speed=25, align=None, **kwargs)[source]

Scrollable text using monitors’ caption function to give textual representations of values, prettified where necessary.

class gulik.Rect(app, monitor, x=0, y=0, width=None, height=None, margin=None, margin_left=None, margin_right=None, margin_top=None, margin_bottom=None, padding=None, padding_left=None, padding_right=None, padding_top=None, padding_bottom=None, elements=None, captions=None, caption_placement=None, legend=None, legend_order=None, legend_format=None, legend_size=None, legend_placement=None, legend_margin=None, legend_margin_left=None, legend_margin_right=None, legend_margin_top=None, legend_margin_bottom=None, legend_padding=None, legend_padding_left=None, legend_padding_right=None, legend_padding_top=None, legend_padding_bottom=None, foreground=None, background=None, pattern=None, palette=None, combination=None, operator=None)[source]
_images/rect.png
class gulik.MirrorRect(app, monitor, **kwargs)[source]

Mirrored variant of Rect.

legend_info()[source]

defines colors for legend elements

class gulik.Arc(app, monitor, stroke_width=5, **kwargs)[source]
_images/arc.png
Parameters:stroke_width (int) – width of the arc in pixels.
class gulik.MirrorArc(app, monitor, **kwargs)[source]

Mirrored variant of Arc.

class gulik.Plot(app, monitor, num_points=None, autoscale=None, markers=None, line=None, grid=None, **kwargs)[source]
_images/plot.png
Parameters:
  • num_points (int, optional) – The number of datapoints to show.
  • autoscale (bool, optional) – Whether to automatically “zoom” into the data.
  • markers (bool, optional) – Whether tho render markers at data point coordinates.
  • line (bool, optional) – Whether to draw a line.
  • grid (bool, optional) – Whether to draw a grid. The grid automatically adapts if autoscale is True.
  • **kwargs – passed on to Visualizer.
class gulik.MirrorPlot(app, monitor, scale_lock=True, **kwargs)[source]

Mirrored variant of Plot.

class gulik.Box(app, x, y, width, height)[source]

Can wrap multiple Visualizers, used for layouting. Orders added visualizers from left to right and top to bottom.

This is basically a smart helper for Gulik.add_visualizer().

place(component, cls, **kwargs)[source]

place a new Visualizer.

Parameters:
  • component (str) – The component string identifying the data source.
  • cls (type, child of Visualizer) – The visualizer class to instantiate.
  • **kwargs – passed on to cls’ constructor. width and height defined in here are honored.
class gulik.Gulik(configpath)[source]

The main object thingamabob.

Indices and tables