Skip to main content

Chart

Struct Chart 

Source
pub struct Chart { /* private fields */ }
Expand description

Datasets on two axes, laid out as ratatui’s Chart, so a ratatui app ports with the same look.

  • The x axis’s labels take the bottom row and its line (─) the row above; the y axis’s labels take the left (at most a third of the width) and its line (│) the column after, meeting at └. An axis draws its line only when it has Labels.
  • The datasets are drawn in order on a Canvas filling the rest, each with its marker. Datasets with the same marker share the dots of a cell, which takes the later one’s style; Layering::PerDataset draws each over the ones before. A line leaving the bounds is clipped at them (OutOfBounds).
  • The y axis’s title sits on the plot’s top row, from its left; the x axis’s at the right end of the plot’s bottom row.
  • The legend is a box listing the named datasets, each in its style, in a corner of the plot (LegendPosition::TopRight by default). It hides itself when it would take more than a share of the plot: a quarter of the width and a quarter of the height by default. Its box is in the chart’s style, or else the x axis’s, unless legend_style says otherwise, and it clears the plot under it unless legend_clear is false.
  • It fills the height it is given, as ratatui’s fills its area: a Layout region, a Panel with a height, an intuiTUIve node through renderable(..). height fixes it instead; given no height, it is 15 rows. It is as wide as the width it is given (or width). As in ratatui, a short chart gives up the x axis line, then the x labels; a narrow one cuts the y labels to a third of the width; the titles and the legend show only when the plot has room for them.
use rich::Console;
use rich_ext::chart::{Axis, Chart, Dataset, GraphType, Labels, Marker};

let console = Console::builder().width(24).color_system(None).build();
let cpu = Dataset::new([(0.0, 0.0), (5.0, 4.0), (10.0, 1.0)])
    .name("cpu")
    .graph_type(GraphType::Line)
    .marker(Marker::Ascii('*'));
let chart = Chart::new(vec![cpu])
    .x_axis(Axis::default().bounds(0.0, 10.0).title("t").labels(Labels::Auto(3)))
    .y_axis(Axis::default().bounds(0.0, 4.0).title("%").labels(Labels::Auto(3)))
    .hidden_legend_fraction(0.5, 0.5)
    .height(8);
assert_eq!(
    console.render_export(&chart),
    concat!(
        "4│%        ***     ┌───┐\n",
        " │       **   **** │cpu│\n",
        " │     **         *└───┘\n",
        "2│   **               **\n",
        " │ **                   \n",
        "0│*                    t\n",
        " └──────────────────────\n",
        "  0         5         10\n",
    )
);

Implementations§

Source§

impl Chart

Source

pub fn stacked(self, stacked: bool) -> Self

Stack the GraphType::Area datasets (default off): each area’s values are drawn on top of the areas before it, so the top edge is their running total and each band is one dataset’s share. The axes fit the totals (a linear y axis without bounds runs from the fill level), and every stacked area fills down to the first one’s fill_to level (0 by default), the top layer drawn first, so each band shows in its own style. Datasets that share x values stack exactly; between another area’s points the area below is interpolated along its line. Other datasets are drawn as they are, over the areas. The legend and the accessible text keep each dataset’s own values.

use rich::Console;
use rich_ext::chart::{Axis, Chart, Dataset, GraphType, LegendPosition, Marker};

let console = Console::builder().width(8).color_system(None).build();
let area = |points: [(f64, f64); 2], c: char| {
    Dataset::new(points).graph_type(GraphType::Area).marker(Marker::Ascii(c))
};
let chart = Chart::new(vec![
    area([(0.0, 1.0), (7.0, 1.0)], '#'),
    area([(0.0, 1.0), (7.0, 2.0)], '+'),
])
.x_axis(Axis::default().bounds(0.0, 7.0))
.y_axis(Axis::default().bounds(0.0, 3.0))
.legend(LegendPosition::None)
.stacked(true)
.width(8)
.height(4);
assert_eq!(
    console.render_export(&chart),
    concat!(
        "    ++++\n",
        "++++++++\n",
        "########\n",
        "########\n",
    )
);
Source§

impl Chart

Source

pub fn new(datasets: impl IntoIterator<Item = Dataset>) -> Self

A chart of datasets, drawn in order.

Source

pub fn dataset(self, dataset: Dataset) -> Self

Add a dataset, drawn after the others.

Source

pub fn datasets(&self) -> &[Dataset]

The datasets, in drawing order.

Source

pub fn x_axis(self, axis: Axis) -> Self

The x axis.

Source

pub fn y_axis(self, axis: Axis) -> Self

The y axis.

Source

pub fn legend(self, position: LegendPosition) -> Self

Where the legend goes (default LegendPosition::TopRight).

Source

pub fn hidden_legend_fraction(self, width: f64, height: f64) -> Self

The largest share of the plot’s width and height the legend may take before it hides (default a quarter of each). Each is clamped to 0..=1; NaN keeps the default.

Source

pub fn style(self, style: impl Into<String>) -> Self

The chart’s own style, as ratatui’s Chart::style: a theme key or a definition put under every cell of the chart (a background fills it), and the style of the legend’s box unless legend_style gives one. Without it the chart has no style of its own and the legend’s box takes the x axis’s. "none" is the terminal’s own colours, so the legend’s box is unstyled too: legend_unstyled says the same by name.

use rich::Console;
use rich_ext::chart::{Axis, Chart, Dataset, Marker};

let console = Console::builder().width(6).force_terminal(true).build();
let chart = Chart::new(vec![Dataset::new([]).name("a")])
    .x_axis(Axis::default().bounds(0.0, 1.0))
    .y_axis(Axis::default().bounds(0.0, 1.0))
    .hidden_legend_fraction(1.0, 1.0)
    .style("on blue")
    .width(6)
    .height(3);
let out = console.render_export(&chart);
// Every cell on blue, the legend's box too.
assert!(out.starts_with("\u{1b}[44m"));
Source

pub fn legend_style(self, style: impl Into<String>) -> Self

The style of the legend’s box: a theme key or a definition (default: the chart’s style when it has one, else the x axis’s style). The names keep their datasets’ styles.

use rich_ext::chart::{Chart, Dataset};

let chart = Chart::new(vec![Dataset::new([(0.0, 1.0)]).name("left")])
    .legend_style("dim");
Source

pub fn legend_unstyled(self) -> Self

The legend’s box in the terminal’s own colours, not the x axis’s style: a ratatui chart whose legend style is the default (scope-tui sets legend_style(Style::default())). The same as legend_style("none"), by name; the names keep their datasets’ styles.

use rich::Console;
use rich_ext::chart::{Axis, Chart, Dataset};

let console = Console::builder().width(6).force_terminal(true).build();
let chart = Chart::new(vec![Dataset::new([]).name("a").style("none")])
    .x_axis(Axis::default().bounds(0.0, 1.0).style("red"))
    .y_axis(Axis::default().bounds(0.0, 1.0))
    .hidden_legend_fraction(1.0, 1.0)
    .width(6)
    .height(3);
// The box in the x axis's red, then in no colour at all.
assert!(console.render_export(&chart).contains("\u{1b}[31m┌"));
assert!(!console.render_export(&chart.legend_unstyled()).contains('\u{1b}'));
Source

pub fn legend_clear(self, clear: bool) -> Self

Whether the legend clears the plot under it (default true). When false, as in ratatui, what the datasets drew inside the box stays, unstyled, around the names.

use rich::Console;
use rich_ext::chart::{Axis, Chart, Dataset, Marker};

let console = Console::builder().width(8).color_system(None).build();
let wall = (0..8).flat_map(|x| (0..4).map(move |y| (f64::from(x), f64::from(y))));
let dots = Dataset::new(wall).name("a").marker(Marker::Ascii('.'));
let chart = Chart::new(vec![dots, Dataset::new([]).name("bb")])
    .x_axis(Axis::default().bounds(0.0, 7.0))
    .y_axis(Axis::default().bounds(0.0, 3.0))
    .hidden_legend_fraction(1.0, 1.0)
    .width(8)
    .height(4);
assert_eq!(
    console.render_export(&chart),
    "....┌──┐\n....│a │\n....│bb│\n....└──┘\n"
);
assert_eq!(
    console.render_export(&chart.legend_clear(false)),
    "....┌──┐\n....│a.│\n....│bb│\n....└──┘\n"
);
Source

pub fn out_of_bounds(self, out_of_bounds: OutOfBounds) -> Self

What to do with a segment that has an end outside the bounds (default OutOfBounds::Clip).

Source

pub fn layering(self, layering: Layering) -> Self

How datasets that share a cell are put together (default Layering::Merge).

Source

pub fn marker(self, marker: Marker) -> Self

The marker the axes’ grid lines are drawn with when an axis gives none (Axis::grid_marker). Without it, the first dataset’s marker, or Marker::Braille when there is no dataset, so a chart’s grid looks the same before its first data as after.

use rich::Console;
use rich_ext::chart::{Axis, Chart, Dataset, Marker};

let console = Console::builder().width(4).color_system(None).build();
let empty = Chart::new(Vec::<Dataset>::new())
    .x_axis(Axis::default().bounds(0.0, 1.0))
    .y_axis(Axis::default().bounds(-1.0, 1.0).grid([0.0]))
    .width(4)
    .height(1);
// Braille with no datasets, not dots.
assert_eq!(console.render_export(&empty), "⠒⠒⠒⠒\n");
let ascii = empty.marker(Marker::Ascii('-'));
assert_eq!(console.render_export(&ascii), "----\n");
Source

pub fn width(self, width: usize) -> Self

Width in cells (default: the width it is given).

Source

pub fn height(self, rows: usize) -> Self

Height in rows, axes and labels included (at most 65535), whatever height it is given. Without it, the chart fills the height it is given, or takes 15 rows.

Trait Implementations§

Source§

impl AccessibleText for Chart

Chart, 2 datasets, x (t) from 0 to 10, y (%) from 0 to 4, then a line per dataset: its name (dataset 2 without one), how it is drawn, and its facts (3 points, min 0, max 4, last 1, trend up).

Source§

fn accessible_text(&self, _width: usize) -> String

The content as plain lines, laid out for width where layout matters.
Source§

impl Clone for Chart

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Chart

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Chart

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Draw for Chart

Source§

fn draw( &self, console: &Console, options: &ConsoleOptions, screen: &mut Screen, rect: Rect, )

Draw into rect of screen, rendered with options (its width and height are the rectangle’s): the cells screen.write_lines(rect, &console.render_lines(self, options, false)) would give.
Source§

impl From<Chart> for Facet

Source§

fn from(chart: Chart) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for Chart

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Renderable for Chart

Source§

fn rich_render( &self, console: &Console, options: &ConsoleOptions, ) -> Vec<Segment>

Source§

fn measure(&self, _console: &Console, options: &ConsoleOptions) -> Measurement

The (minimum, maximum) cell width this renderable wants. Port of __rich_measure__. The default is what upstream’s Measurement.get returns for a renderable without one: anything from nothing to the whole width, (0, max_width).
Source§

fn fit_to_measurement(&self) -> bool

Whether a top-level Console::print shrinks this renderable to its measured width. Upstream renders every top-level renderable at the full console width, so the default is false; an extension may opt in.
Source§

fn vertical(&self) -> Option<VerticalAlign>

The vertical alignment a Table cell holding this renderable uses in place of its column’s. Upstream reads getattr(renderable, "vertical", None); Align sets it.
Source§

fn print_end_line(&self, _options: &ConsoleOptions) -> bool

Whether a top-level print ends this renderable’s last line. This port’s renderables separate lines, where upstream’s end each line with "\n", so a print adds the final line break. A renderable whose upstream output stops without one (Screen, LiveRender, a Rule whose end has no newline) returns false, and the next output continues its last line. options are the print’s options.
Source§

impl StructuralPartialEq for Chart

Auto Trait Implementations§

§

impl Freeze for Chart

§

impl RefUnwindSafe for Chart

§

impl Send for Chart

§

impl Sync for Chart

§

impl Unpin for Chart

§

impl UnsafeUnpin for Chart

§

impl UnwindSafe for Chart

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more