Textplot DuckDB Extension

The Textplot extension, brings text-based data visualization directly to your SQL queries in DuckDB. Create stunning ASCII/Unicode charts, bar graphs, and density plots without leaving your database environment.

Use Cases

The Textplot extension is perfect for:

  • Quick data exploration: Visualize distributions and trends directly in your terminal
  • Dashboard creation: Add visual elements to text-based reports and dashboards
  • Monitoring and alerting: Create visual indicators for system metrics and KPIs
  • Data quality checks: Spot outliers and patterns in your data instantly
  • Command-line analytics: Build beautiful charts for CLI tools and scripts
  • Documentation: Include visual data summaries in README files and documentation
  • Embedded analytics: Add lightweight visualizations to applications without heavy charting libraries

Installation

textplot is a DuckDB Community Extension.

You can now use this by using this SQL:

install textplot from community;
load textplot

Functions

tp_bar(value, ...options)

Creates horizontal bar charts with customizable styling and colors.

Basic Usage:

-- Simple progress bar (50% filled)
SELECT tp_bar(0.5);
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚     tp_bar(0.5)      β”‚
β”‚       varchar        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯⬜⬜⬜⬜⬜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

-- Custom width and range
SELECT tp_bar(75, min := 0, max := 100, width := 20);
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ tp_bar(75, min := 0, max := 100, width := 20) β”‚
β”‚                    varchar                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯πŸŸ₯⬜⬜⬜⬜⬜      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Advanced Options:

-- Custom colors and shapes
SELECT tp_bar(0.8, shape := 'circle', on_color := 'green', off_color := 'white') as bar;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         bar          β”‚
β”‚       varchar        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 🟒🟒🟒🟒🟒🟒🟒🟒βšͺβšͺ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

-- Threshold-based coloring
SELECT tp_bar(85,
    min := 0, max := 100,
    thresholds := [
        {'threshold': 90, 'color': 'red'},
        {'threshold': 70, 'color': 'yellow'},
        {'threshold': 0, 'color': 'green'}
    ]
) as bar;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         bar          β”‚
β”‚       varchar        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 🟨🟨🟨🟨🟨🟨🟨🟨🟨⬜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

-- Custom characters
SELECT tp_bar(0.7, on := 'β–ˆ', off := 'β–‘', width := 15) as bar;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚       bar       β”‚
β”‚     varchar     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

SELECT round(n,4),
tp_bar(n,
width := 14,
shape := 'circle',
off_color :='black',
filled := false,
thresholds := [
  (0.8, 'red'),
  (0.7, 'orange'),
  (0.6, 'yellow'),
  (0.0, 'green')
]) as bar
FROM (select random() as n from generate_series(10));
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ round(n, 4) β”‚             bar              β”‚
β”‚   double    β”‚           varchar            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚      0.9889 β”‚ βš«βš«βš«βš«βš«βš«βš«βš«βš«βš«βš«βš«βš«πŸ”΄ β”‚
β”‚      0.6242 β”‚ ⚫⚫⚫⚫⚫⚫⚫⚫🟑⚫⚫⚫⚫⚫ β”‚
β”‚      0.6013 β”‚ ⚫⚫⚫⚫⚫⚫⚫🟑⚫⚫⚫⚫⚫⚫ β”‚
β”‚       0.669 β”‚ ⚫⚫⚫⚫⚫⚫⚫⚫🟑⚫⚫⚫⚫⚫ β”‚
β”‚      0.8363 β”‚ βš«βš«βš«βš«βš«βš«βš«βš«βš«βš«βš«πŸ”΄βš«βš« β”‚
β”‚      0.9193 β”‚ βš«βš«βš«βš«βš«βš«βš«βš«βš«βš«βš«βš«πŸ”΄βš« β”‚
β”‚      0.8629 β”‚ βš«βš«βš«βš«βš«βš«βš«βš«βš«βš«βš«πŸ”΄βš«βš« β”‚
β”‚      0.8296 β”‚ βš«βš«βš«βš«βš«βš«βš«βš«βš«βš«βš«πŸ”΄βš«βš« β”‚
β”‚      0.0824 β”‚ 🟒⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫ β”‚
β”‚      0.0281 β”‚ ⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫ β”‚
β”‚      0.2682 β”‚ ⚫⚫⚫🟒⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 11 rows                          2 columns β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

SELECT round(n,4),
tp_bar(n,
width := 14,
shape := 'circle',
off_color :='black',
filled := true,
thresholds := [
  (0.8, 'red'),
  (0.7, 'orange'),
  (0.6, 'yellow'),
  (0.0, 'green')
]) as bar
FROM (select random() as n from generate_series(10));
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ round(n, 4) β”‚             bar              β”‚
β”‚   double    β”‚           varchar            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚      0.3818 β”‚ 🟒🟒🟒🟒🟒⚫⚫⚫⚫⚫⚫⚫⚫⚫ β”‚
β”‚      0.1919 β”‚ 🟒🟒🟒⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫ β”‚
β”‚      0.5885 β”‚ 🟒🟒🟒🟒🟒🟒🟒🟒⚫⚫⚫⚫⚫⚫ β”‚
β”‚      0.9558 β”‚ πŸ”΄πŸ”΄πŸ”΄πŸ”΄πŸ”΄πŸ”΄πŸ”΄πŸ”΄πŸ”΄πŸ”΄πŸ”΄πŸ”΄πŸ”΄βš« β”‚
β”‚      0.4463 β”‚ 🟒🟒🟒🟒🟒🟒⚫⚫⚫⚫⚫⚫⚫⚫ β”‚
β”‚      0.6024 β”‚ 🟑🟑🟑🟑🟑🟑🟑🟑⚫⚫⚫⚫⚫⚫ β”‚
β”‚      0.0114 β”‚ ⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫⚫ β”‚
β”‚      0.4993 β”‚ 🟒🟒🟒🟒🟒🟒🟒⚫⚫⚫⚫⚫⚫⚫ β”‚
β”‚      0.6884 β”‚ 🟑🟑🟑🟑🟑🟑🟑🟑🟑🟑⚫⚫⚫⚫ β”‚
β”‚      0.7929 β”‚ 🟠🟠🟠🟠🟠🟠🟠🟠🟠🟠🟠⚫⚫⚫ β”‚
β”‚      0.3507 β”‚ 🟒🟒🟒🟒🟒⚫⚫⚫⚫⚫⚫⚫⚫⚫ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 11 rows                          2 columns β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Parameters:

  • value: Numeric value to visualize
  • min: Minimum value (default: 0)
  • max: Maximum value (default: 1.0)
  • width: Bar width in characters (default: 10)
  • shape: β€˜square’, β€˜circle’, or β€˜heart’ (default: β€˜square’)
  • on_color/off_color: Color names (red, green, blue, yellow, etc.)
  • on/off: Custom characters for filled/empty portions
  • filled: Boolean, fill all blocks or just the endpoint (default: true)
  • thresholds: List of threshold objects for conditional coloring

tp_density(values, ...options)

Creates density plots and histograms from arrays of numeric data.

Basic Usage:

-- Simple density plot
SELECT tp_density([1, 2, 3, 4, 5, 4, 3, 2, 1]) as density;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚       density        β”‚
β”‚       varchar        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β–ˆ    β–ˆ    β–ˆ    β–ˆ   β–’ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

-- Custom width and style
SELECT tp_density([1, 2, 3, 2, 1], width := 30, style := 'height') as density;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            density             β”‚
β”‚            varchar             β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β–ˆ              β–ˆ             β–„ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Style Options:

-- ASCII style for compatibility
SELECT tp_density([1, 5, 3, 8, 2], style := 'ascii') as density;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚       density        β”‚
β”‚       varchar        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ @ @  @     @       @ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

-- Dot style for subtle visualization
SELECT tp_density([1, 5, 3, 8, 2], style := 'dots') as density;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚       density        β”‚
β”‚       varchar        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ ● ●  ●     ●       ● β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

-- Colorful emoji styles
SELECT tp_density([1, 5, 3, 8, 2], style := 'rainbow_circle') as density;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 density                  β”‚
β”‚                 varchar                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ βšͺ⚫βšͺ⚫⚫βšͺ⚫⚫⚫⚫⚫βšͺ⚫⚫⚫⚫⚫⚫⚫βšͺ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Parameters:

  • values: Array of numeric values
  • width: Plot width in characters (default: 20)
  • style: Character set style (β€˜shaded’, β€˜ascii’, β€˜dots’, β€˜height’, β€˜circles’, β€˜safety’, β€˜rainbow_circle’, β€˜rainbow_square’, β€˜moon’, β€˜sparse’, β€˜white’)
  • graph_chars: Custom array of characters for density levels
  • marker: Character to highlight specific values

Available Styles:

  • shaded: β–‘β–’β–“β–ˆ (default)
  • ascii: .:+#@
  • dots: .‒●
  • height: β–β–‚β–ƒβ–„β–…β–†β–‡β–ˆ
  • circles: ⚫βšͺπŸŸ‘πŸŸ πŸ”΄
  • rainbow_circle: βš«πŸŸ€πŸŸ£πŸ”΅πŸŸ’πŸŸ‘πŸŸ πŸ”΄βšͺ

tp_sparkline(values, ...options)

Creates compact sparkline charts perfect for showing trends in time series data and small multiples.

Basic Usage:

-- Simple absolute value sparkline
SELECT tp_sparkline([1, 3, 2, 5, 4, 6, 2, 1]) as sparkline;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      sparkline       β”‚
β”‚       varchar        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚    ==---##***@@---   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

-- Delta mode showing change direction
SELECT tp_sparkline([100, 105, 102, 108, 95], mode := 'delta') as sparkline;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      sparkline       β”‚
β”‚       varchar        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ ↑↑↑↑↑↓↓↓↓↓↑↑↑↑↑↓↓↓↓↓ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

-- Trend mode with magnitude
SELECT tp_sparkline([10, 12, 11, 15, 8], mode := 'trend', theme := 'slopes') as sparkline;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         sparkline         β”‚
β”‚          varchar          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ /////\\\\\/////\\\\\\\\\\ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Visualization Modes:

1. Absolute Mode (default) - Shows actual values as heights:

-- Stock prices over time
SELECT tp_sparkline([45.2, 47.1, 46.8, 49.3, 52.1, 48.7], width := 20, theme := 'utf8_blocks') as sparkline;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      sparkline       β”‚
β”‚       varchar        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚     β–‚β–‚β–‚β–‚β–‚β–‚β–…β–…β–…β–…β–ˆβ–ˆβ–ˆβ–„β–„β–„ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

-- System CPU usage
SELECT tp_sparkline([25, 45, 78, 92, 67, 34], theme := 'ascii_basic', width := 15) as sparkline;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    sparkline    β”‚
β”‚     varchar     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚    --###@@***.. β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Delta Mode - Shows direction of change (up/same/down):

-- Sales trend directions
SELECT tp_sparkline([1000, 1200, 1150, 1300, 980], mode := 'delta', theme := 'arrows') as sparkline;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      sparkline       β”‚
β”‚       varchar        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ ↑↑↑↑↑↓↓↓↓↓↑↑↑↑↑↓↓↓↓↓ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

-- Temperature changes
SELECT tp_sparkline([72, 75, 75, 78, 71], mode := 'delta', theme := 'faces') as sparkline;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                sparkline                 β”‚
β”‚                 varchar                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 😊😊😊😊😊😐😐😐😐😐😊😊😊😊😊😞😞😞😞😞 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

3. Trend Mode - Shows change direction with magnitude:

-- Market volatility
SELECT tp_sparkline([100, 110, 105, 125, 90], mode := 'trend', theme := 'intensity') as sparkline;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         sparkline         β”‚
β”‚          varchar          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ +++++-----+++++---------- β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

-- Server response times
SELECT tp_sparkline([150, 145, 147, 180, 120], mode := 'trend', theme := 'arrows') as sparkline;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      sparkline       β”‚
β”‚       varchar        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ ↓↓↓↓↓↑↑↑↑↑↑↑↑↑↑⇩⇩⇩⇩⇩ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Available Themes by Mode:

Absolute Mode Themes:

  • utf8_blocks: β–β–‚β–ƒβ–„β–…β–†β–‡β–ˆ (default)
  • ascii_basic: .-=+*#%@
  • hearts: πŸ€πŸ€Žβ€οΈπŸ’›πŸ’šπŸ’™πŸ’œπŸ–€
  • faces: πŸ˜πŸ™‚πŸ˜ŠπŸ˜ƒπŸ˜„πŸ˜πŸ€©πŸ€―

Delta Mode Themes:

  • arrows: ↓→↑ (default)
  • triangles: β–Όβ—†β–²
  • ascii_arrows: v-^
  • math: -=+
  • faces: 😞😐😊
  • thumbs: πŸ‘ŽπŸ‘πŸ‘
  • trends: πŸ“‰βž‘οΈπŸ“ˆ
  • simple: \\_/

Trend Mode Themes:

  • arrows: ⇩↓→↑⇧ (default)
  • ascii: Vv-^A
  • slopes: \\\\ \\ _ / //
  • intensity: -- - = + ++
  • faces: 😭😞😐😊🀩
  • chart: πŸ“‰πŸ“Šβž‘οΈπŸ“ŠπŸ“ˆ

Parameters:

  • values: Array of numeric values
  • mode: β€˜absolute’, β€˜delta’, or β€˜trend’ (default: β€˜absolute’)
  • theme: Theme name (varies by mode, see lists above)
  • width: Sparkline width in characters (default: 20)

Tips and Best Practices

  1. Choose appropriate widths: Longer bars (width 20-30) work well for dashboards, shorter bars (width 10-15) for compact reports
  2. Use thresholds for status indicators: Perfect for showing health, performance, or risk levels
  3. Combine with regular metrics: Text plots complement, don’t replace, numeric values
  4. Consider your audience: ASCII styles work everywhere, emoji styles are more visually appealing but require Unicode support
  5. Leverage density plots for distributions: Great for showing data patterns, outliers, and distributions

Contributing

The Textplot extension is open source and developed by Query.Farm. Contributions are welcome!

License

MIT License

Love ❀️ this DuckDB extension? You’ll Love This.

Get the best from Query.Farm β€” smart tips, powerful tools, and project updates sent directly to your inbox, but only when we’ve got something great to share.