Easily create a bar chart with kwbar
; pass keyword arguments that can be converted to float.
I made this for fun, but then I thought other people might actually find it useful.
kwbar
several useful features:
- Plots bars showing the relative magnitide (absolute value) of kwargs.
- Prints the values of the passed keyword arguments in scientific notation.
- Pure Python and zero dependencies.
- Minimal implementation (<100 lines total) which can be audited in a few minutes.
- Prints the names of the passed keyword arguments.
- Plots any object that can be converted to float (SupportsFloat).
- Customizable width, the entire terminal width is used by default.
- Customizable significant figures, 3 by default.
- Shows value labels inside bars, making the output width predictable. If the bars are too small, the value labels appear outside of them.
- Handles inf and NaN values.
- Negative values are (ANSI) colored red and can be customized.
- Respects the
NO_COLOR
environment variable. - Has an ASCII mode, enabled on import when stdout is not TTY.
- Warns on stderr (can be disabled) if the output will have to overrun the configured width. Overflow can generally be avoided by configuting options such as
BEFORE=True
. - Fixed output width. This can be done by either:
- Setting
BEFORE = True
, or - setting
TRUNCATE
andWIDTH
to satisfy:WIDTH
-TRUNCATE
-SF
- 17 >= 0.
- Setting
kwbar
supports the following options, which are set by modifying module variables:
import kwbar
kwbar.WIDTH = -1 # Set the output width, -1 = use the terminal width.
kwbar.SF = 2 # The number of sig figs to show.
kwbar.SHOW_VAL = True # Show values inside the bars
kwbar.TRUNCATE = 0.25 # Truncate long keys (<=1 = % of WIDTH, >1 = columns).
kwbar.BAR_CHARS = " ▏▎▍▌▋▊▉█" # Characters to use for the bars.
kwbar.POS = "" # ANSI escape code for positive values.
kwbar.NEG = "\x1b[31m" # ANSI escape code for negative values.
kwbar.WARN = True # Show a warning if the output will overrun the configured width.
kwbar.PAD = " " # Padding characters shown before finite and non-finite values.
kwbar.BEFORE = False # Show the value labels before the bar instead of inside.
There are also a couple of functions to set multiple options at once:
Sets BAR_CHARS
and PAD
to ASCII characters. Also disables all ANSI escape codes and sets BEFORE
true.
import kwbar
kwbar.WIDTH = 50
kwbar.ascii()
kwbar.kwbar(one=1, two=2, three=3, four=4)
one +1.00e+00 XXXXXXXX
two +2.00e+00 XXXXXXXXXXXXXXXXX
three +3.00e+00 XXXXXXXXXXXXXXXXXXXXXXXXX
four +4.00e+00 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
import kwbar
kwbar.WIDTH = 33
kwbar.hotdog()
kwbar.kwbar(one=1, two=2, three=3, four=4)
one 🌭🌭🌭🌭🌭🌭¾
two 🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭½
three 🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭¼
four 🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭
import kwbar
kwbar.ascii()
# Reset to defaults.
import importlib
importlib.reload(kwbar)
import kwbar
kwbar.ascii()
kwbar.kwbar(**{"one": 1, "-2": -2, "pi": 3.14})
one +1.00e+00 XXXXXX
-2 -2.00e+00 XXXXXXXXXXXX
pi +3.14e+00 XXXXXXXXXXXXXXXXXXX
import kwbar
kwbar.hotdog()
kwbar.BAR_CHARS = kwbar.BAR_CHARS[:-1] + "🐶" # Replace the last character.
kwbar.kwbar(one=1, two=2, pi=3.14)
one 🐶🐶🐶🐶🐶🐶🐶🐶🐶¼
two 🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶½
pi 🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶🐶
Just some ideas for how you could customize the output.
import kwbar
kwbar.hotdog()
kwbar.BAR_CHARS = "╸━"
import kwbar
kwbar.hotdog()
kwbar.BAR_CHARS = "╸━"
kwbar.POS = "\x1b[34m"
kwbar.NEG = "\x1b[31m"
import kwbar
kwbar.hotdog()
kwbar.BAR_CHARS = "◔◑◕●"
import kwbar
kwbar.hotdog()
kwbar.BAR_CHARS = " ¼½¾1"
kwbar.hotdog()
kwbar.BAR_CHARS = " ⅛¼⅜½⅝¾⅞1"
kwbar.hotdog()
kwbar.BAR_CHARS = "🥚🐣🐥"
These are questions that I frequently asked myself while making this.
For fun!
Because I could and it made me happy.
Because it kept the implementation simple/minimal. This also means that if you import kwbar in multiple places within a script, it will have a consistent style and does not need to be configured multiple times.
The configuration for kwbar affects all calls to kwbar.kwbar
, becuase it is a static
function using module variables for configuration.
If you really want to do this, you can, but it feels like a hideous hack:
import sys
import importlib
SPEC_KWBAR = importlib.util.find_spec('kwbar')
kwbar2 = importlib.util.module_from_spec(SPEC_KWBAR)
SPEC_KWBAR.loader.exec_module(kwbar2)
sys.modules['kwbar2'] = kwbar2
Now you have another kwbar called kwbar2 with a completely seperate configuration.
>>> kwbar.WIDTH = 40
>>> kwbar2.WIDTH = 50
>>> print(kwbar.WIDTH)
40
>>> print(kwbar2.WIDTH)
50
Becuase that was less fun that using only kwargs.