plot

package
v0.1.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 23, 2025 License: MIT Imports: 16 Imported by: 2

Documentation

Overview

Package plot provides live plotting drawers for window.Window, using the gonum/plot package or direct OpenGL drawing.

For the window, see package github.com/mlange-42/ark-pixel/window.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Bars

type Bars struct {
	Observer observer.Row // Observer providing a data series for bars.
	Columns  []string     // Columns to show, by name. Optional, default all.
	YLim     [2]float64   // Y axis limits. Optional, default auto.
	Labels   Labels       // Labels for plot and axes. Optional.
	// contains filtered or unexported fields
}

Bars plot drawer.

Creates a bar per column of the observer.

Example
// Create a new model.
app := app.New()

// Limit the the simulation speed.
app.TPS = 30

// Create a time series plot.
app.AddUISystem((&window.Window{}).
	With(&plot.Bars{
		Observer: &RowObserver{},
		YLim:     [...]float64{0, 4}, // Optional Y axis limits.
	}))

// Add a termination system that ends the simulation.
app.AddSystem(&system.FixedTermination{
	Steps: 100,
})

app.Run()

// Run the simulation.
// Due to the use of the OpenGL UI system, the model must be run via [window.Run].
// Comment out the code line above, and uncomment the next line to run this example stand-alone.

// window.Run(app)

func (*Bars) Draw

func (b *Bars) Draw(w *ecs.World, win *opengl.Window)

Draw the drawer.

func (*Bars) Initialize

func (b *Bars) Initialize(w *ecs.World, _ *opengl.Window)

Initialize the drawer.

func (*Bars) Update

func (b *Bars) Update(w *ecs.World)

Update the drawer.

func (*Bars) UpdateInputs

func (b *Bars) UpdateInputs(_ *ecs.World, _ *opengl.Window)

UpdateInputs handles input events of the previous frame update.

type Contour

type Contour struct {
	Observer   observer.Grid   // Observers providing a Grid for contours.
	Levels     []float64       // Levels for iso lines. Optional.
	Palette    palette.Palette // Color palette. Optional.
	Labels     Labels          // Labels for plot and axes. Optional.
	HideLegend bool            // Hides the legend.
	// contains filtered or unexported fields
}

Contour plot drawer.

Plots a grid as a contours. For large grids, this is relatively slow. Consider using Image instead.

Example
// Create a new model.
app := app.New()

// Limit the the simulation speed.
app.TPS = 30
app.FPS = 0

// Create a contour plot.
app.AddUISystem(
	(&window.Window{}).
		With(&plot.Contour{
			Observer: observer.MatrixToGrid(&MatrixObserver{}, nil, nil),
			Palette:  palette.Heat(16, 1),
			Levels:   []float64{-2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2},
		}))

// Add a termination system that ends the simulation.
app.AddSystem(&system.FixedTermination{
	Steps: 100,
})

app.Run()

// Run the simulation.
// Due to the use of the OpenGL UI system, the model must be run via [window.Run].
// Comment out the code line above, and uncomment the next line to run this example stand-alone.

// window.Run(app)

func (*Contour) Draw

func (c *Contour) Draw(w *ecs.World, win *opengl.Window)

Draw the drawer.

func (*Contour) Initialize

func (c *Contour) Initialize(w *ecs.World, _ *opengl.Window)

Initialize the drawer.

func (*Contour) Update

func (c *Contour) Update(w *ecs.World)

Update the drawer.

func (*Contour) UpdateInputs

func (c *Contour) UpdateInputs(_ *ecs.World, _ *opengl.Window)

UpdateInputs handles input events of the previous frame update.

type Field

type Field struct {
	Observer observer.GridLayers // Observers providing field component grids.
	Labels   Labels              // Labels for plot and axes. Optional.
	Layers   []int               // Layer indices. Optional, defaults to (0, 1).
	// contains filtered or unexported fields
}

Field plot drawer.

Plots a vector field from a GridLayers observer. For large grids, this is relatively slow. Consider using ImageRGB instead.

Example
package main

import (
	"math"

	"github.com/mlange-42/ark-pixel/plot"
	"github.com/mlange-42/ark-pixel/window"
	"github.com/mlange-42/ark-tools/app"
	"github.com/mlange-42/ark-tools/observer"
	"github.com/mlange-42/ark-tools/system"
	"github.com/mlange-42/ark/ecs"
)

func main() {
	// Create a new model.
	app := app.New()

	// Limit the the simulation speed.
	app.TPS = 30
	app.FPS = 0

	// Create a contour plot.
	app.AddUISystem(
		(&window.Window{}).
			With(&plot.Field{
				Observer: observer.LayersToLayers(&FieldObserver{}, nil, nil),
			}))

	// Add a termination system that ends the simulation.
	app.AddSystem(&system.FixedTermination{
		Steps: 100,
	})

	app.Run()

	// Run the simulation.
	// Due to the use of the OpenGL UI system, the model must be run via [window.Run].
	// Comment out the code line above, and uncomment the next line to run this example stand-alone.

	// window.Run(app)

}

type FieldObserver struct {
	cols   int
	rows   int
	values [][]float64
}

func (o *FieldObserver) Initialize(w *ecs.World) {
	o.cols = 60
	o.rows = 40
	o.values = make([][]float64, 2)
	for i := 0; i < len(o.values); i++ {
		o.values[i] = make([]float64, o.cols*o.rows)
	}
}

func (o *FieldObserver) Update(w *ecs.World) {}

func (o *FieldObserver) Dims() (int, int) {
	return o.cols, o.rows
}

func (o *FieldObserver) Layers() int {
	return 2
}

func (o *FieldObserver) Values(w *ecs.World) [][]float64 {
	ln := len(o.values[0])
	for idx := range ln {
		i := idx % o.cols
		j := idx / o.cols
		o.values[0][idx] = math.Sin(float64(i))
		o.values[1][idx] = -math.Sin(float64(j))
	}
	return o.values
}

func (*Field) Draw

func (f *Field) Draw(w *ecs.World, win *opengl.Window)

Draw the drawer.

func (*Field) Initialize

func (f *Field) Initialize(w *ecs.World, _ *opengl.Window)

Initialize the drawer.

func (*Field) Update

func (f *Field) Update(w *ecs.World)

Update the drawer.

func (*Field) UpdateInputs

func (f *Field) UpdateInputs(_ *ecs.World, _ *opengl.Window)

UpdateInputs handles input events of the previous frame update.

type HeatMap

type HeatMap struct {
	Observer observer.Grid   // Observers providing a Grid for contours.
	Palette  palette.Palette // Color palette. Optional.
	Min      float64         // Minimum value for color mapping. Optional.
	Max      float64         // Maximum value for color mapping. Optional. Is set to 1.0 if both Min and Max are zero.
	Labels   Labels          // Labels for plot and axes. Optional.
	// contains filtered or unexported fields
}

HeatMap plot drawer.

Plots a grid as a heatmap image. For large grids, this is relatively slow. Consider using Image instead.

Example
// Create a new model.
app := app.New()

// Limit the the simulation speed.
app.TPS = 30
app.FPS = 0

// Create a contour plot.
app.AddUISystem(
	(&window.Window{}).
		With(&plot.HeatMap{
			Observer: observer.MatrixToGrid(&MatrixObserver{}, nil, nil),
			Palette:  palette.Heat(16, 1),
			Min:      -2,
			Max:      2,
		}))

// Add a termination system that ends the simulation.
app.AddSystem(&system.FixedTermination{
	Steps: 100,
})

app.Run()

// Run the simulation.
// Due to the use of the OpenGL UI system, the model must be run via [window.Run].
// Comment out the code line above, and uncomment the next line to run this example stand-alone.

// window.Run(app)

func (*HeatMap) Draw

func (h *HeatMap) Draw(w *ecs.World, win *opengl.Window)

Draw the drawer.

func (*HeatMap) Initialize

func (h *HeatMap) Initialize(w *ecs.World, _ *opengl.Window)

Initialize the drawer.

func (*HeatMap) Update

func (h *HeatMap) Update(w *ecs.World)

Update the drawer.

func (*HeatMap) UpdateInputs

func (h *HeatMap) UpdateInputs(_ *ecs.World, _ *opengl.Window)

UpdateInputs handles input events of the previous frame update.

type Image

type Image struct {
	Scale    float64            // Spatial scaling: cell size in screen pixels. Optional, default auto.
	Observer observer.Matrix    // Observer providing 2D matrix or grid data.
	Colors   colorgrad.Gradient // Colors for mapping values.
	Min      float64            // Minimum value for color mapping. Optional.
	Max      float64            // Maximum value for color mapping. Optional. Is set to 1.0 if both Min and Max are zero.
	// contains filtered or unexported fields
}

Image drawer.

Draws an image from a Matrix observer. The image is scaled to the canvas extent, with preserved aspect ratio. Does not add plot axes etc.

Example
package main

import (
	"math"

	"github.com/mazznoer/colorgrad"
	"github.com/mlange-42/ark-pixel/plot"
	"github.com/mlange-42/ark-pixel/window"
	"github.com/mlange-42/ark-tools/app"
	"github.com/mlange-42/ark-tools/system"
	"github.com/mlange-42/ark/ecs"
)

func main() {

	// Create a new model.
	app := app.New()

	// Limit the the simulation speed.
	app.TPS = 30
	app.FPS = 0

	// Create an image plot.
	// See below for the implementation of the MatrixObserver.
	app.AddUISystem(
		(&window.Window{}).
			With(&plot.Image{
				Scale:    4,
				Observer: &MatrixObserver{},
				Colors:   colorgrad.Inferno(),
				Min:      -2,
				Max:      2,
			}))

	// Add a termination system that ends the simulation.
	app.AddSystem(&system.FixedTermination{
		Steps: 100,
	})

	app.Run()

	// Run the simulation.
	// Due to the use of the OpenGL UI system, the model must be run via [window.Run].
	// Comment out the code line above, and uncomment the next line to run this example stand-alone.

	// window.Run(app)

}

// Example observer, reporting a matrix with z = sin(0.1*i) + sin(0.2*j).
type MatrixObserver struct {
	cols   int
	rows   int
	values []float64
}

func (o *MatrixObserver) Initialize(w *ecs.World) {
	o.cols = 160
	o.rows = 120
	o.values = make([]float64, o.cols*o.rows)
}

func (o *MatrixObserver) Update(w *ecs.World) {}

func (o *MatrixObserver) Dims() (int, int) {
	return o.cols, o.rows
}

func (o *MatrixObserver) Values(w *ecs.World) []float64 {
	for idx := 0; idx < len(o.values); idx++ {
		i := idx % o.cols
		j := idx / o.cols
		o.values[idx] = math.Sin(0.1*float64(i)) + math.Sin(0.2*float64(j))
	}
	return o.values
}

func (*Image) Draw

func (i *Image) Draw(w *ecs.World, win *opengl.Window)

Draw the system

func (*Image) Initialize

func (i *Image) Initialize(w *ecs.World, _ *opengl.Window)

Initialize the system

func (*Image) Update

func (i *Image) Update(w *ecs.World)

Update the drawer.

func (*Image) UpdateInputs

func (i *Image) UpdateInputs(_ *ecs.World, _ *opengl.Window)

UpdateInputs handles input events of the previous frame update.

type ImageRGB

type ImageRGB struct {
	Scale    float64               // Spatial scaling: cell size in screen pixels. Optional, default auto.
	Observer observer.MatrixLayers // Observer providing data for color channels.
	Layers   []int                 // Layer indices. Optional, defaults to [0, 1, 2]. Use -1 to ignore a channel.
	Min      []float64             // Minimum value for channel color mapping. Optional, default [0, 0, 0].
	Max      []float64             // Maximum value for channel color mapping. Optional, default [1, 1, 1].
	// contains filtered or unexported fields
}

ImageRGB drawer.

Draws an image from a Matrix observer per RGB color channel. The image is scaled to the canvas extent, with preserved aspect ratio. Does not add plot axes etc.

Example
package main

import (
	"math"

	"github.com/mlange-42/ark-pixel/plot"
	"github.com/mlange-42/ark-pixel/window"
	"github.com/mlange-42/ark-tools/app"
	"github.com/mlange-42/ark-tools/observer"
	"github.com/mlange-42/ark-tools/system"
	"github.com/mlange-42/ark/ecs"
)

func main() {

	// Create a new model.
	app := app.New()

	// Limit the the simulation speed.
	app.TPS = 30

	// Create an RGB image plot.
	// See below for the implementation of the CallbackMatrixObserver.
	app.AddUISystem((&window.Window{}).
		With(&plot.ImageRGB{
			Observer: observer.MatrixToLayers(
				&CallbackMatrixObserver{Callback: func(i, j int) float64 { return float64(i) / 240 }},
				&CallbackMatrixObserver{Callback: func(i, j int) float64 { return math.Sin(0.1 * float64(i)) }},
				&CallbackMatrixObserver{Callback: func(i, j int) float64 { return float64(j) / 160 }},
			),
			Min: []float64{0, 0, 0},
			Max: []float64{1, 1, 1},
		}))

	// Add a termination system that ends the simulation.
	app.AddSystem(&system.FixedTermination{
		Steps: 100,
	})

	app.Run()

	// Run the simulation.
	// Due to the use of the OpenGL UI system, the model must be run via [window.Run].
	// Comment out the code line above, and uncomment the next line to run this example stand-alone.

	// window.Run(app)

}

// Example observer, reporting a matrix filled with a callback(i, j).
type CallbackMatrixObserver struct {
	Callback func(i, j int) float64
	cols     int
	rows     int
	values   []float64
}

func (o *CallbackMatrixObserver) Initialize(w *ecs.World) {
	o.cols = 240
	o.rows = 160
	o.values = make([]float64, o.cols*o.rows)
}

func (o *CallbackMatrixObserver) Update(w *ecs.World) {}

func (o *CallbackMatrixObserver) Dims() (int, int) {
	return o.cols, o.rows
}

func (o *CallbackMatrixObserver) Values(w *ecs.World) []float64 {
	for idx := 0; idx < len(o.values); idx++ {
		i := idx % o.cols
		j := idx / o.cols
		o.values[idx] = o.Callback(i, j)
	}
	return o.values
}

func (*ImageRGB) Draw

func (i *ImageRGB) Draw(w *ecs.World, win *opengl.Window)

Draw the drawer.

func (*ImageRGB) Initialize

func (i *ImageRGB) Initialize(w *ecs.World, _ *opengl.Window)

Initialize the drawer.

func (*ImageRGB) Update

func (i *ImageRGB) Update(w *ecs.World)

Update the drawer.

func (*ImageRGB) UpdateInputs

func (i *ImageRGB) UpdateInputs(_ *ecs.World, _ *opengl.Window)

UpdateInputs handles input events of the previous frame update.

type Labels

type Labels struct {
	Title string // Plot title
	X     string // X axis label
	Y     string // Y axis label
}

Labels for plots.

Example
// Create a new model.
app := app.New()

// Limit the the simulation speed.
app.TPS = 30

// Create a time series plot, wit labels.
app.AddUISystem((&window.Window{}).
	With(&plot.TimeSeries{
		Observer: &RowObserver{},
		Labels: plot.Labels{
			Title: "Plot example",
			X:     "X axis label",
			Y:     "Y axis label",
		},
	}))

// Add a termination system that ends the simulation.
app.AddSystem(&system.FixedTermination{
	Steps: 100,
})

app.Run()

// Run the simulation.
// Due to the use of the OpenGL UI system, the model must be run via [window.Run].
// Comment out the code line above, and uncomment the next line to run this example stand-alone.

// window.Run(app)

type Lines

type Lines struct {
	Observer observer.Table // Observer providing a data series for lines.
	X        string         // X column name. Optional. Defaults to row index.
	Y        []string       // Y column names. Optional. Defaults to all but X column.
	XLim     [2]float64     // X axis limits. Optional, default auto.
	YLim     [2]float64     // Y axis limits. Optional, default auto.
	Labels   Labels         // Labels for plot and axes. Optional.
	// contains filtered or unexported fields
}

Lines plot drawer.

Creates a line series per column of the observer. Replaces the complete data by the table provided by the observer on every update. Particularly useful for live histograms.

Example
// Create a new model.
app := app.New()

// Limit the the simulation speed.
app.TPS = 30

// Create a line plot.
// See below for the implementation of the TableObserver.
app.AddUISystem((&window.Window{}).
	With(&plot.Lines{
		Observer: &TableObserver{},
		X:        "X",                     // Optional, defaults to row index
		Y:        []string{"A", "B", "C"}, // Optional, defaults to all but X
	}))

// Add a termination system that ends the simulation.
app.AddSystem(&system.FixedTermination{
	Steps: 100,
})

app.Run()

// Run the simulation.
// Due to the use of the OpenGL UI system, the model must be run via [window.Run].
// Comment out the code line above, and uncomment the next line to run this example stand-alone.

// window.Run(app)

func (*Lines) Draw

func (l *Lines) Draw(w *ecs.World, win *opengl.Window)

Draw the drawer.

func (*Lines) Initialize

func (l *Lines) Initialize(w *ecs.World, _ *opengl.Window)

Initialize the drawer.

func (*Lines) Update

func (l *Lines) Update(w *ecs.World)

Update the drawer.

func (*Lines) UpdateInputs

func (l *Lines) UpdateInputs(_ *ecs.World, _ *opengl.Window)

UpdateInputs handles input events of the previous frame update.

type Scatter

type Scatter struct {
	Observers []observer.Table // Observers providing XY data series.
	X         []string         // X column name per observer. Optional. Defaults to first column. Empty strings also falls back to the default.
	Y         [][]string       // Y column names per observer. Optional. Defaults to second column. Empty strings also falls back to the default.
	XLim      [2]float64       // X axis limits. Optional, default auto.
	YLim      [2]float64       // Y axis limits. Optional, default auto.
	Labels    Labels           // Labels for plot and axes. Optional.
	// contains filtered or unexported fields
}

Scatter plot drawer.

Creates a scatter plot from multiple observers. Supports multiple series per observer. The series in a particular observer must share a common X column.

Example
// Create a new model.
app := app.New()

// Limit the the simulation speed.
app.TPS = 30

// Create a scatter plot.
app.AddUISystem((&window.Window{}).
	With(&plot.Scatter{
		Observers: []observer.Table{
			&TableObserver{}, // One or more observers.
		},
		X: []string{
			"X", // One X column per observer.
		},
		Y: [][]string{
			{"A", "B", "C"}, // One or more Y columns per observer.
		},
	}))

// Add a termination system that ends the simulation.
app.AddSystem(&system.FixedTermination{
	Steps: 100,
})

app.Run()

// Run the simulation.
// Due to the use of the OpenGL UI system, the model must be run via [window.Run].
// Comment out the code line above, and uncomment the next line to run this example stand-alone.

//window.Run(app)

func (*Scatter) Draw

func (s *Scatter) Draw(w *ecs.World, win *opengl.Window)

Draw the drawer.

func (*Scatter) Initialize

func (s *Scatter) Initialize(w *ecs.World, _ *opengl.Window)

Initialize the drawer.

func (*Scatter) Update

func (s *Scatter) Update(w *ecs.World)

Update the drawer.

func (*Scatter) UpdateInputs

func (s *Scatter) UpdateInputs(_ *ecs.World, _ *opengl.Window)

UpdateInputs handles input events of the previous frame update.

type TimeSeries

type TimeSeries struct {
	Observer       observer.Row // Observer providing a data row per update.
	Columns        []string     // Columns to show, by name. Optional, default all.
	UpdateInterval int          // Interval for getting data from the the observer, in model ticks. Optional.
	Labels         Labels       // Labels for plot and axes. Optional.
	MaxRows        int          // Maximum number of rows to keep. Zero means unlimited. Optional.
	// contains filtered or unexported fields
}

TimeSeries plot drawer.

Creates a line series per column of the observer. Adds one row to the data per update.

Example
package main

import (
	"math/rand"

	"github.com/mlange-42/ark-pixel/plot"
	"github.com/mlange-42/ark-pixel/window"
	"github.com/mlange-42/ark-tools/app"
	"github.com/mlange-42/ark-tools/system"
	"github.com/mlange-42/ark/ecs"
)

func main() {

	// Create a new model.
	app := app.New()

	// Limit the the simulation speed.
	app.TPS = 30

	// Create a time series plot.
	// See below for the implementation of the RowObserver.
	app.AddUISystem((&window.Window{}).
		With(&plot.TimeSeries{
			Observer: &RowObserver{},
		}))

	// Add a termination system that ends the simulation.
	app.AddSystem(&system.FixedTermination{
		Steps: 100,
	})

	app.Run()

	// Run the simulation.
	// Due to the use of the OpenGL UI system, the model must be run via [window.Run].
	// Uncomment the next line to run this example stand-alone.

	//window.Run(app)

}

// RowObserver to generate random time series.
type RowObserver struct{}

func (o *RowObserver) Initialize(w *ecs.World) {}
func (o *RowObserver) Update(w *ecs.World)     {}
func (o *RowObserver) Header() []string {
	return []string{"A", "B", "C"}
}
func (o *RowObserver) Values(w *ecs.World) []float64 {
	return []float64{rand.Float64(), rand.Float64() + 1, rand.Float64() + 2}
}

func (*TimeSeries) Draw

func (t *TimeSeries) Draw(_ *ecs.World, win *opengl.Window)

Draw the drawer.

func (*TimeSeries) Initialize

func (t *TimeSeries) Initialize(w *ecs.World, _ *opengl.Window)

Initialize the drawer.

func (*TimeSeries) Update

func (t *TimeSeries) Update(w *ecs.World)

Update the drawer.

func (*TimeSeries) UpdateInputs

func (t *TimeSeries) UpdateInputs(_ *ecs.World, _ *opengl.Window)

UpdateInputs handles input events of the previous frame update.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL