TTY Toolkit logo

TTY::Sparkline

Gem Version Actions CI Build status Maintainability Coverage Status Inline docs

Sparkline charts for terminal applications.

TTY::Sparkline provides sparkline drawing component for TTY toolkit.

tty-sparkline

Installation

Add this line to your application's Gemfile:

gem "tty-sparkline"

And then execute:

$ bundle install

Or install it yourself as:

$ gem install tty-sparkline

Contents

1. Usage

To display a sparkline chart, first, create an instance with some data:

sparkline = TTY::Sparkline.new(1..8)

Then invoke render to generate the chart:

sparkline.render
# => "▁▂▃▄▅▆▇█"

To display the sparkline in the terminal, print it like so:

print sparkline.render

This will result in the following output:

▁▂▃▄▅▆▇█

A sparkline can be positioned anywhere within the terminal screen using :top and :left keywords:

sparkline = TTY::Sparkline.new(1..8, top: 10, left: 50)

A sparkline can have custom size given by the :height and :width keywords:

sparkline = TTY::Sparkline.new(1..8, height: 5, width: 100)

To restrict data values use :min and :max:

sparkline = TTY::Sparkline.new(1..8, min: 0, max: 5)

2. Interface

2.1 new

To render a new sparkline chart, first, create an instance:

sparkline = TTY::Sparkline.new

If you have a static set of data items you can provide them during initialisation with the :data keyword that accepts both Array and Range types:

sparkline = TTY::Sparkline.new(1..8)
sparkline = TTY::Sparkline.new([1, 2, 3, 4, 5, 6, 7, 8])

However, if you don't know data upfront you can append it after instantiation:

sparkline << 1 << 2 << 3 << 4

2.2 append

After a sparkline is created, you can further add more data items using the push method:

sparkline.push(1).push(2)
sparkline.push(3, 4)

The push is also aliased as append and << operator:

sparkline.append(5).append(6)
sparkline << 7 << 8

Then calling render will result in the following:

sparkline.render
# => "▁▂▃▄▅▆▇█"

This method is particularly useful if you intend to stream data. When streaming it's advisable to specify the maximum width and position that the chart is going to span:

sparkline = TTY::Sparkline.new(left: 0, top: 0, width: 50)

And then you can stream data, for example, from some service like so:

loop do
  # fetch next value(s) from another service etc.

  sparkline << value      # send value(s) to the chart
  print sparkline.render  # render the chart out to the console
end

2.3 render

Once you have a sparkline instance with some data:

sparkline = TTY::Sparkline.new(1..8)

To show the sparkline chart use the render method like so:

sparkline.render
# => "▁▂▃▄▅▆▇█"

To display the chart in the terminal, you need to print it:

print sparkline.render

This will result in the following output:

▁▂▃▄▅▆▇█

The render method also accepts a block that provides access to the current value, bar character, column and row.

For example, to insert a space between each bar, we could do the following:

sparkline.render do |val, bar, col, row|
  col == 7 ? bar : "#{bar} "
end

That would result in:

# => "▁ ▂ ▃ ▄ ▅ ▆ ▇ █"

The block form is useful for applying colours, for example, to mark the lowest or the highest value.

For instance, you can use pastel to colour the maximum cyan, minimum red and all the other bars green:

pastel = Pastel.new

sparkline.render do |val, bar, col, row|
  if val == 8
    pastel.cyan(bar)
  elsif val == 1
    pastel.red(bar)
  else
    pastel.green(bar)
  end
end

3. Configuration

3.1 :top

By default, a sparkline will not be positioned. To position it against the top of the terminal screen use :top keyword. For example, to place a sparkline 10 lines down from the top of the screen do:

TTY::Sparkline.new(top: 10)

Add :left to position against the left of the terminal screen.

To dynamically position a sparkline within a terminal window consider using tty-screen for gathering screen size. For example, to centre align against the vertical axis do:

TTY::Sparkline.new(top: TTY::Screen.height / 2)

3.2 :left

By default, a sparkline will not be positioned. To position it against the left side of the terminal screen use :left keyword. For example, to place a sparkline 50 columns away from the left side of the terminal window do:

TTY::Sparkline.new(left: 50)

Add :top to position against the top of the terminal screen.

To dynamically position a sparkline within a terminal window consider using tty-screen for gathering screen size. For example, to centre align against horizontal axis do:

TTY::Sparkline.new(left: TTY::Screen.width / 2)

3.3 :height

By default, a sparkline will be rendered within a single terminal line. To change a chart to span more than one line use :height keyword. For example to display a sparkline on 3 lines do:

TTY::Sparkline.new(1..8, height: 3)

Then rendering the sparkline in the console:

print sparkline.render

We would get the following output:

      ▃▆
   ▂▅███
▁▄▇█████

3.4 :width

By default, a sparkline will be rendered in as many terminal columns as there are data items. To restrict the chart to a limited number of columns use the :width keyword. For example, to display a sparkline up to a maximum of 5 columns do:

TTY::Sparkline.new(1..8, width: 5)

Then by rendering the sparkline in the console:

print sparkline.render

We would generate the following limited output:

▄▅▆▇█

This option can be combined with the :height:

TTY::Sparkline.new(1..8, height: 3, width: 5)

The result of rendering the above sparkline would be as follows:

   ▃▆
▂▅███
█████

3.5 :min

By default, the minimum value will be calculated from the entire data set. For example, given the following data:

sparkline = TTY::Sparkline.new([100, 75, 100, 50, 80])

When displayed in the console, you will see the following:

█▄█▁▅

You will notice that the value of 50 looks like it's almost zero. This is because the sparkline automatically scales bars against the minimum value to make the differences between values more visible.

To change this, you can provide a custom minimum value using the :min keyword:

sparkline = TTY::Sparkline.new([100, 75, 100, 50, 80], min: 0)

This time the display will show 50 as a more prominent value at the cost of making the difference between other values less striking:

█▆█▄▆

3.6 :max

By default, the maximum value will be calculated from the entire data set. For example, given the following data:

sparkline = TTY::Sparkline.new([100, 75, 300, 50, 80])

When displayed in the console, you will see the following:

▂▁█▁▁

You will notice that the value of 300 makes all the remaining numbers look like insignificant zeros. This is because the sparkline automatically scales bars against the maximum value to make the differences between values more prominent.

To change this, you can provide a custom maximum value using the :max keyword:

sparkline = TTY::Sparkline.new([100, 75, 300, 50, 80], max: 100)

This time the display will limit values and reduce 300 to the height of 100 making all the remaining values more visible.

█▄█▁▅

3.7 :bars

There are eight bar types used to display values in a sparkline chart. These can be changed with the :bars keyword to a different set of characters:

sparkline = TTY::Sparkline.new(1..8, bars: %w[_ - = ^])

Then rendering the chart will output:

sparkline.render
# => "___--==^"

3.8 :buffer_size

By default, the amount of data values that can be appended to a sparkline is limited to 16K. This helps to keep the memory size down when streaming data. You can change it with the :buffer_size keyword.

For example, to keep the last 5 data values do:

sparkline = TTY::Sparkline.new(buffer_size: 5, min: 0)

Then exceeding the number of values:

sparkline.push(1, 2, 3, 4, 5, 6, 7, 8)

Will cause the render to truncate the output:

sparkline.render
# => "▄▅▆▇█"

3.9 :non_numeric

To instruct a sparkline on how to deal with non-numeric data use the :non_numeric keyword.

Below are the possible values:

  • :empty - shows empty spaces (default)
  • :ignore - skips displaying anything
  • :minimum - shows the smallest bar

Given data with some non-numeric values like "foo", nil and "":

data = [1, 2, "foo", 4, nil, 6, "", 8]

When you don't specify the :non_numeric keyword, it will be set to :empty by default:

sparkline = TTY::Sparkline.new(data)

This will then display any non-numeric values as empty spaces:

sparkline.render
# => "▁▂ ▄ ▆ █"

If you want to ignore displaying any non-numeric values use :ignore:

sparkline = TTY::Sparkline.new(data, non_numeric: :ignore)

When rendered, this will result in:

sparkline.render
# => "▁▂▄▆█"

You can also convert any non-numeric values to the smallest bar with :minimum:

sparkline = TTY::Sparkline.new(data, non_numeric: :minimum)

This will render the following:

sparkline.render
# => "▁▂▁▄▁▆▁█"

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/piotrmurach/tty-sparkline. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the TTY::Sparkline project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

Copyright (c) 2021 Piotr Murach. See LICENSE for further details.