Code Monkey home page Code Monkey logo

plotille's Introduction

Hero Plotille

Plotille

CI codecov Tested CPython Versions Tested PyPy Versions PyPi version Downloads PyPi license

Plots, scatter plots, histograms and heatmaps in the terminal using braille dots, and foreground and background colors - with no dependancies. Make complex figures using the Figure class or make fast and simple plots using graphing function - similar to a very small sibling to matplotlib. Or use the canvas to plot dots, lines and images yourself.

Install:

pip install plotille

Similar to other libraries:

  • like drawille, but focused on graphing – plus X/Y-axis.
  • like termplot, but with braille (finer dots), left to right histogram and linear interpolation for plotting function.
  • like termgraph (not on pypi), but very different style.
  • like terminalplot, but with braille, X/Y-axis, histogram, linear interpolation.

Basic support for timeseries plotting is provided with release 3.2: for any X or Y values you can also add datetime.datetime, pendulum.datetime or numpy.datetime64 values. Labels are generated respecting the difference of x_limits and y_limits.

Support for heatmaps using background colors for figures and displaying images binary with braille, or in color with background colors using the canvas - provided with release 4.0

If you are still using python 2.7, please use plotille v4 or before. With v5 I am dropping support for python 2.7, as the effort to maintain the discontinued version is too much.

Documentation

In [1]: import plotille
In [2]: import numpy as np
In [3]: X = np.sort(np.random.normal(size=1000))

Figure

To construct plots the recomended way is to use a Figure:

In [12]: plotille.Figure?
Init signature: plotille.Figure()
Docstring:
Figure class to compose multiple plots.

Within a Figure you can easily compose many plots, assign labels to plots
and define the properties of the underlying Canvas. Possible properties that
can be defined are:

    width, height: int    Define the number of characters in X / Y direction
                          which are used for plotting.
    x_limits: float       Define the X limits of the reference coordinate system,
                          that will be plottered.
    y_limits: float       Define the Y limits of the reference coordinate system,
                          that will be plottered.
    color_mode: str       Define the used color mode. See `plotille.color()`.
    with_colors: bool     Define, whether to use colors at all.
    background: multiple  Define the background color.
    x_label, y_label: str Define the X / Y axis label.

Basically, you create a Figure, define the properties and add your plots. Using the show() function, the Figure generates the plot using a new canvas:

In [13] fig = plotille.Figure()
In [14] fig.width = 60
In [15] fig.height = 30
In [16] fig.set_x_limits(min_=-3, max_=3)
In [17] fig.set_y_limits(min_=-1, max_=1)
In [18] fig.color_mode = 'byte'
In [19] fig.plot([-0.5, 1], [-1, 1], lc=25, label='First line')
In [20] fig.scatter(X, np.sin(X), lc=100, label='sin')
In [21] fig.plot(X, (X+2)**2 , lc=200, label='square')
In [22] print(fig.show(legend=True))

Example figure

The available plotting functions are:

# create a plot with linear interpolation between points
Figure.plot(self, X, Y, lc=None, interp='linear', label=None, marker=None)
# create a scatter plot with no interpolation between points
Figure.scatter(self, X, Y, lc=None, label=None, marker=None)
# create a histogram over X
Figure.histogram(self, X, bins=160, lc=None)
# print texts at coordinates X, Y
Figure.text(self, X, Y, texts, lc=None)

# The following functions use relative coordinates on the canvas
# i.e. all coordinates are \in [0, 1]
# plot a vertical line at x
Figure.axvline(self, x, ymin=0, ymax=1, lc=None)
# plot a vertical rectangle from (xmin,ymin) to (xmax, ymax).
Figure.axvspan(self, xmin, xmax, ymin=0, ymax=1, lc=None)
# plot a horizontal line at y
Figure.axhline(self, y, xmin=0, xmax=1, lc=None)
# plot a horizontal rectangle from (xmin,ymin) to (xmax, ymax).
Figure.axhspan(self, ymin, ymax, xmin=0, xmax=1, lc=None)

# Display data as an image, i.e. on a 2D regular raster.
Figure.imgshow(self, X, cmap=None)

Other interesting functions are:

# remove all plots, texts, spans and images from the figure
Figure.clear(self)
# Create a canvas, plot the registered plots and return the string for displaying the plot
Figure.show(self, legend=False)

Please have a look at the examples/ folder.

Graphing

There are some utility functions for fast graphing of single plots.

Plot

In [4]: plotille.plot?
Signature:
plotille.plot(
    X,
    Y,
    width=80,
    height=40,
    X_label='X',
    Y_label='Y',
    linesep=os.linesep,
    interp='linear',
    x_min=None,
    x_max=None,
    y_min=None,
    y_max=None,
    lc=None,
    bg=None,
    color_mode='names',
    origin=True,
    marker=None,
)
Docstring:
Create plot with X , Y values and linear interpolation between points

Parameters:
    X: List[float]         X values.
    Y: List[float]         Y values. X and Y must have the same number of entries.
    width: int             The number of characters for the width (columns) of the canvas.
    hight: int             The number of characters for the hight (rows) of the canvas.
    X_label: str           Label for X-axis.
    Y_label: str           Label for Y-axis. max 8 characters.
    linesep: str           The requested line seperator. default: os.linesep
    interp: Optional[str]  Specify interpolation; values None, 'linear'
    x_min, x_max: float    Limits for the displayed X values.
    y_min, y_max: float    Limits for the displayed Y values.
    lc: multiple           Give the line color.
    bg: multiple           Give the background color.
    color_mode: str        Specify color input mode; 'names' (default), 'byte' or 'rgb'
                           see plotille.color.__docs__
    origin: bool           Whether to print the origin. default: True
    marker: str            Instead of braille dots set a marker char for actual values.

Returns:
    str: plot over `X`, `Y`.

In [5]: print(plotille.plot(X, np.sin(X), height=30, width=60))

Example plot

Scatter

In [6]: plotille.scatter?
Signature:
plotille.scatter(
    X,
    Y,
    width=80,
    height=40,
    X_label='X',
    Y_label='Y',
    linesep='\n',
    x_min=None,
    x_max=None,
    y_min=None,
    y_max=None,
    lc=None,
    bg=None,
    color_mode='names',
    origin=True,
    marker=None,
)
Docstring:
Create scatter plot with X , Y values

Basically plotting without interpolation:
    `plot(X, Y, ... , interp=None)`

Parameters:
    X: List[float]       X values.
    Y: List[float]       Y values. X and Y must have the same number of entries.
    width: int           The number of characters for the width (columns) of the canvas.
    hight: int           The number of characters for the hight (rows) of the canvas.
    X_label: str         Label for X-axis.
    Y_label: str         Label for Y-axis. max 8 characters.
    linesep: str         The requested line seperator. default: os.linesep
    x_min, x_max: float  Limits for the displayed X values.
    y_min, y_max: float  Limits for the displayed Y values.
    lc: multiple         Give the line color.
    bg: multiple         Give the background color.
    color_mode: str      Specify color input mode; 'names' (default), 'byte' or 'rgb'
                         see plotille.color.__docs__
    origin: bool         Whether to print the origin. default: True
    marker: str          Instead of braille dots set a marker char.

Returns:
    str: scatter plot over `X`, `Y`.

In [7]: print(plotille.scatter(X, np.sin(X), height=30, width=60))

Example scatter

Hist

Inspired by crappyhist (link is gone, but I made a gist).

In [8]: plotille.hist?
Signature:
plotille.hist(
    X,
    bins=40,
    width=80,
    log_scale=False,
    linesep='\n',
    lc=None,
    bg=None,
    color_mode='names',
)
Docstring:
Create histogram over `X` from left to right

The values on the left are the center of the bucket, i.e. `(bin[i] + bin[i+1]) / 2`.
The values on the right are the total counts of this bucket.

Parameters:
    X: List[float]       The items to count over.
    bins: int            The number of bins to put X entries in (rows).
    width: int           The number of characters for the width (columns).
    log_scale: bool      Scale the histogram with `log` function.
    linesep: str         The requested line seperator. default: os.linesep
    lc: multiple         Give the line color.
    bg: multiple         Give the background color.
    color_mode: str      Specify color input mode; 'names' (default), 'byte' or 'rgb'
                         see plotille.color.__docs__

Returns:
    str: histogram over `X` from left to right.

In [9]: print(plotille.hist(np.random.normal(size=10000)))

Example hist

Hist (aggregated)

This function allows you to create a histogram when your data is already aggregated (aka you don't have access to raw values, but you have access to bins and counts for each bin).

This comes handy when working with APIs such as OpenTelemetry Metrics API where views such as ExplicitBucketHistogramAggregation only expose access to aggregated values (counts for each bin / bucket).

In [8]: plotille.hist_aggregated?
Signature:
plotille.hist_aggregated(
    counts,
    bins,
    width=80,
    log_scale=False,
    linesep='\n',
    lc=None,
    bg=None,
    color_mode='names',
)
Docstring:
Create histogram for aggregated data.

Parameters:
    counts: List[int]    Counts for each bucket.
    bins: List[float]    Limits for the bins for the provided counts: limits for
                         bin `i` are `[bins[i], bins[i+1])`.
                         Hence, `len(bins) == len(counts) + 1`.
    width: int           The number of characters for the width (columns).
    log_scale: bool      Scale the histogram with `log` function.
    linesep: str         The requested line seperator. default: os.linesep
    lc: multiple         Give the line color.
    bg: multiple         Give the background color.
    color_mode: str      Specify color input mode; 'names' (default), 'byte' or 'rgb'
                         see plotille.color.__docs__
Returns:
    str: histogram over `X` from left to right.

In [9]: counts = [1945, 0, 0, 0, 0, 0, 10555, 798, 0, 28351, 0]
In [10]: bins = [float('-inf'), 10, 50, 100, 200, 300, 500, 800, 1000, 2000, 10000, float('+inf')]
In [11]: print(plotille.hist_aggregated(counts, bins))

Keep in mind that there must always be n+1 bins (n is a total number of count values, 11 in the example above).

In this example the first bin is from [-inf, 10) with a count of 1945 and the last bin is from [10000, +inf] with a count of 0.

Example hist

Histogram

There is also another more 'usual' histogram function available:

In [10]: plotille.histogram?
Signature:
plotille.histogram(
    X,
    bins=160,
    width=80,
    height=40,
    X_label='X',
    Y_label='Counts',
    linesep='\n',
    x_min=None,
    x_max=None,
    y_min=None,
    y_max=None,
    lc=None,
    bg=None,
    color_mode='names',
)
Docstring:
Create histogram over `X`

In contrast to `hist`, this is the more `usual` histogram from bottom
to up. The X-axis represents the values in `X` and the Y-axis is the
corresponding frequency.

Parameters:
    X: List[float]       The items to count over.
    bins: int            The number of bins to put X entries in (columns).
    height: int          The number of characters for the height (rows).
    X_label: str         Label for X-axis.
    Y_label: str         Label for Y-axis. max 8 characters.
    linesep: str         The requested line seperator. default: os.linesep
    x_min, x_max: float  Limits for the displayed X values.
    y_min, y_max: float  Limits for the displayed Y values.
    lc: multiple         Give the line color.
    bg: multiple         Give the background color.
    color_mode: str      Specify color input mode; 'names' (default), 'byte' or 'rgb'
                         see plotille.color.__docs__

Returns:
    str: histogram over `X`.

In [11]: print(plotille.histogram(np.random.normal(size=10000)))

Example histogram

Canvas

The underlying plotting area is modeled as the Canvas class:

In [12]:  plotille.Canvas?
Init signature:
plotille.Canvas(
    width,
    height,
    xmin=0,
    ymin=0,
    xmax=1,
    ymax=1,
    background=None,
    **color_kwargs,
)
Docstring:
A canvas object for plotting braille dots

A Canvas object has a `width` x `height` characters large canvas, in which it
can plot indivitual braille point, lines out of braille points, rectangles,...
Since a full braille character has 2 x 4 dots (⣿), the canvas has `width` * 2, `height` * 4
dots to plot into in total.

It maintains two coordinate systems: a reference system with the limits (xmin, ymin)
in the lower left corner to (xmax, ymax) in the upper right corner is transformed
into the canvas discrete, i.e. dots, coordinate system (0, 0) to (`width` * 2, `height` * 4).
It does so transparently to clients of the Canvas, i.e. all plotting functions
only accept coordinates in the reference system. If the coordinates are outside
the reference system, they are not plotted.
Init docstring:
Initiate a Canvas object

Parameters:
    width: int            The number of characters for the width (columns) of the canvas.
    hight: int            The number of characters for the hight (rows) of the canvas.
    xmin, ymin: float     Lower left corner of reference system.
    xmax, ymax: float     Upper right corner of reference system.
    background: multiple  Background color of the canvas.
    **color_kwargs:       More arguments to the color-function. See `plotille.color()`.

Returns:
    Canvas object

The most interesting functions are:

point:

In [11]: plotille.Canvas.point?
Signature: plotille.Canvas.point(self, x, y, set_=True, color=None, marker=None)
Docstring:
Put a point into the canvas at (x, y) [reference coordinate system]

Parameters:
    x: float         x-coordinate on reference system.
    y: float         y-coordinate on reference system.
    set_: bool       Whether to plot or remove the point.
    color: multiple  Color of the point.
    marker: str      Instead of braille dots set a marker char.

line:

In [14]: plotille.Canvas.line?
Signature: plotille.Canvas.line(self, x0, y0, x1, y1, set_=True, color=None)
Docstring:
Plot line between point (x0, y0) and (x1, y1) [reference coordinate system].

Parameters:
    x0, y0: float    Point 0
    x1, y1: float    Point 1
    set_: bool       Whether to plot or remove the line.
    color: multiple  Color of the line.

rect:

In [15]: plotille.Canvas.rect?
Signature: plotille.Canvas.rect(self, xmin, ymin, xmax, ymax, set_=True, color=None)
Docstring:
Plot rectangle with bbox (xmin, ymin) and (xmax, ymax) [reference coordinate system].

Parameters:
    xmin, ymin: float  Lower left corner of rectangle.
    xmax, ymax: float  Upper right corner of rectangle.
    set_: bool         Whether to plot or remove the rect.
    color: multiple    Color of the rect.

text:

In [16]: plotille.Canvas.text?
Signature: plotille.Canvas.text(self, x, y, text, set_=True, color=None)
Docstring:
Put some text into the canvas at (x, y) [reference coordinate system]

Parameters:
    x: float         x-coordinate on reference system.
    y: float         y-coordinate on reference system.
    set_: bool       Whether to set the text or clear the characters.
    text: str        The text to add.
    color: multiple  Color of the point.

braille_image:

In [17]: plotille.Canvas.braille_image?
Signature:
plotille.Canvas.braille_image(
    self,
    pixels,
    threshold=127,
    inverse=False,
    set_=True,
)
Docstring:
Print an image using braille dots into the canvas.

The pixels and braille dots in the canvas are a 1-to-1 mapping, hence
a 80 x 80 pixel image will need a 40 x 20 canvas.

Example:
    from PIL import Image
    import plotille as plt

    img = Image.open("/path/to/image")
    img = img.convert('L')
    img = img.resize((80, 80))
    cvs = plt.Canvas(40, 20)
    cvs.braille_image(img.getdata(), 125)
    print(cvs.plot())

Parameters:
    pixels: list[number]  All pixels of the image in one list.
    threshold: float      All pixels above this threshold will be
                          drawn.
    inverse: bool         Whether to invert the image.
    set_: bool            Whether to plot or remove the dots.

image:

In [18]: plotille.Canvas.image?
Signature: plotille.Canvas.image(self, pixels, set_=True)
Docstring:
Print an image using background colors into the canvas.

The pixels of the image and the characters in the canvas are a
1-to-1 mapping, hence a 80 x 80 image will need a 80 x 80 canvas.

Example:
    from PIL import Image
    import plotille as plt

    img = Image.open("/path/to/image")
    img = img.convert('RGB')
    img = img.resize((40, 40))
    cvs = plt.Canvas(40, 40, mode='rgb')
    cvs.image(img.getdata())
    print(cvs.plot())

Parameters:
    pixels: list[(R,G,B)]  All pixels of the image in one list.
    set_: bool             Whether to plot or remove the background
                           colors.

plot:

In [16]: plotille.Canvas.plot?
Signature: plotille.Canvas.plot(self, linesep='\n')
Docstring:
Transform canvas into `print`-able string

Parameters:
    linesep: str  The requested line seperator. default: os.linesep

Returns:
    unicode: The canvas as a string.

You can use it for example to plot a house in the terminal:

In [17]: c = Canvas(width=40, height=20)
In [18]: c.rect(0.1, 0.1, 0.6, 0.6)
In [19]: c.line(0.1, 0.1, 0.6, 0.6)
In [20]: c.line(0.1, 0.6, 0.6, 0.1)
In [21]: c.line(0.1, 0.6, 0.35, 0.8)
In [22]: c.line(0.35, 0.8, 0.6, 0.6)
In [23]: print(c.plot())

House

Or you could render images with braille dots:

In [24]: img = Image.open('https://github.com/tammoippen/plotille/raw/master/imgs/ich.jpg')
In [25]: img = img.convert('L')
In [26]: img = img.resize((80, 80))
In [27]: cvs = Canvas(40, 20)
In [28]: cvs.braille_image(img.getdata())
In [29]: print(cvs.plot())

Me with dots

Or you could render images with the background color of characters:

In [24]: img = Image.open('https://github.com/tammoippen/plotille/raw/master/imgs/ich.jpg')
In [25]: img = img.convert('RGB')
In [25]: img = img.resize((80, 40))
In [27]: cvs = Canvas(80, 40, mode="rgb")
In [28]: cvs.image(img.getdata())
In [29]: print(cvs.plot())

Me with chars

Stargazers over time

Stargazers over time

plotille's People

Contributors

kami avatar tammoippen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

plotille's Issues

[Feature request] support arrow

Would you consider to support basic arrow as a start/end point of line just for convenience?
Or can we draw " -----------> " easily?

Two plots side-by-side

Hi! I found this package very useful, thank you!

There is one thing I actually try to figure out without any success.
How do I print two plots side-by-side, I mean like 🖼️ 🖼️

Here is my code, but I have no success in making all lines same length:(

import os, sys

import plotille
import numpy as np

x = np.linspace(0, 1, 100)

y = 2*x
plot1 = plotille.plot(x, y,
    lc='red', height=5, width=40, X_label='x', Y_label='T',
    x_min=0, x_max=1, y_min=np.min(y), y_max=np.max(y))

y = np.exp(-x)
plot2 = plotille.plot(x, y,
    lc='green', height=5, width=40, X_label='t', Y_label='T',
    x_min=0, x_max=1, y_min=np.min(y), y_max=np.max(y))

print(plot1)
print(plot2)

plot = (os.linesep).join(l1.ljust(60) + l2.ljust(60) for (l1, l2) in zip(plot1.split(os.linesep), plot2.split(os.linesep)))

print(plot)

and here is what I get
изображение

Allow users to provide label transformation functions

Imagine we have a plot and have x values that look like this: 100000000011000013551 or like this 130141414.0001401212401. We don't want to print them like this but we do want to provide these values to our graph. It would be cool to be able to pass in a transformation function that would be executed for each label to transform these values to, for instance, 1E20 + 13551 or maybe even more human readable formats such as "2h ago", "1h ago".

Currently, graphing big values with plotille will lead to completely unreadable labels next to the plot.

[Feature Request] Treemaps

I suggest adding treemap as a type of graph that plotille can draw with a single utility function, akin to scatter and hist.
If this sounds like something that would suit the project, I'd gladly work on this, so feel free to assign the issue to me.

Four quandrant scatter plot misalignment

Versions:
plotille 3.6
Python 3.6.4 :: Anaconda custom (64-bit)
Windows 10 Version 1809

Environment:
Jupyter Lab Version 0.35.3

When plotting many points axes separators tend to become misaligned. Below is an example running a provided example script. This looks like a fantastic tool, would appreciate any help. Thank you.

image

Log scale for plot()

As far as I can see, there is no option to use a log scale in graphs using plot(). Is there a workaround for this? Best

install failed: AttributeError: module 'enum' has no attribute 'IntFlag'

$ python --version
Python 3.7.3
$ pip --version
pip 19.1.1 from /Users/acarlson/anaconda3/envs/colab/lib/python3.7/site-packages/pip (python 3.7)
$ pip install plotille

Collecting plotille
  Downloading https://files.pythonhosted.org/packages/22/16/219daf27f7af6bec6b8f6dd1fe928e2723e4f9def04139aa5be8adea1800/plotille-3.7.tar.gz
  Installing build dependencies ... error
  ERROR: Complete output from command /Users/acarlson/anaconda3/envs/colab/bin/python /Users/acarlson/anaconda3/envs/colab/lib/python3.7/site-packages/pip install --ignore-installed --no-user --prefix /private/var/folders/36/xqbmrgy53cb46vvzvrln93tccvpxfl/T/pip-build-env-swclygl1/overlay --no-warn-script-location --no-binary :none: --only-binary :none: -i https://pypi.org/simple -- 'setuptools>=40.8.0' wheel:
  ERROR: Traceback (most recent call last):
    File "/Users/acarlson/anaconda3/envs/colab/lib/python3.7/runpy.py", line 193, in _run_module_as_main
      "__main__", mod_spec)
    File "/Users/acarlson/anaconda3/envs/colab/lib/python3.7/runpy.py", line 85, in _run_code
      exec(code, run_globals)
    File "/Users/acarlson/anaconda3/envs/colab/lib/python3.7/site-packages/pip/__main__.py", line 16, in <module>
      from pip._internal import main as _main  # isort:skip # noqa
    File "/Users/acarlson/anaconda3/envs/colab/lib/python3.7/site-packages/pip/_internal/__init__.py", line 4, in <module>
      import locale
    File "/Users/acarlson/anaconda3/envs/colab/lib/python3.7/locale.py", line 16, in <module>
      import re
    File "/Users/acarlson/anaconda3/envs/colab/lib/python3.7/re.py", line 143, in <module>
      class RegexFlag(enum.IntFlag):
  AttributeError: module 'enum' has no attribute 'IntFlag'
  ----------------------------------------
ERROR: Command "/Users/acarlson/anaconda3/envs/colab/bin/python /Users/acarlson/anaconda3/envs/colab/lib/python3.7/site-packages/pip install --ignore-installed --no-user --prefix /private/var/folders/36/xqbmrgy53cb46vvzvrln93tccvpxfl/T/pip-build-env-swclygl1/overlay --no-warn-script-location --no-binary :none: --only-binary :none: -i https://pypi.org/simple -- 'setuptools>=40.8.0' wheel" failed with error code 1 in None

I'm on MacOS Mojave v 10.14.6

Not getting the graph as required

Sir, I am searching for a library to draw graph in terminal and I found this library and used this, but the output is not getting as required. Please help out.

The code I used (which is given in readme of your library)

import  plotille
import numpy as np 
X = np.sort(np.random.normal(size=1000))
fig = plotille.Figure() 
fig.width = 60 
fig.height = 30 
fig.set_x_limits(min_=-3, max_=3)
fig.set_y_limits(min_=-1, max_=1) 
fig.color_mode = 'byte' 
fig.plot([-0.5, 1], [-1, 1], lc=25, label='First line')
fig.scatter(X, np.sin(X), lc=100, label='sin')  
fig.plot(X, (X+2)**2 , lc=200, label='square')
print(fig.show(legend=True))

The output what I got

The actual output (shown in read me)

Why I am getting the extra braille dots? Please help me. Waiting for your replay.

Thank you.

Time series plotting

I would like to plot a list of datetimes but the problem is that I currently have to convert them to unix timestamps because this library does not support straight printing of datetimes. Now the problem with that is that timestamps tend to become quite large (and are also hard to read for humans). Can you implement time series plotting of lists of datetimes?

Some ideas for optimization.

Well, I've made a small library for resampling data to use on functions plot and scatter of plotille.
https://github.com/carlosplanchon/plotilleresample
"""
Rationale:

  • I want to optimize plot and scatter function of plotille.
    """
    I came up with two ideas for you and plotille.
    1 - Make optimizations before rendering to avoid useless computations.
    2 - Separate Canvas module so it can be used as a dependency on plotille, maybe drawille, and potentially on other projects.

Histogram Y axis integer values

y

AFAIK it doesn't make sense to print the decimal part of the Y axis values when drawing a histogram.

Also, when printing some of these graphs the Y axis is not a straight line.

Integer values for X axis

First of all let me thank you for this tool. I've been using it to graph a lot of things lately, and it rocks!

Something that I've noticed in many of my graphs is that the X axis values quickly become unreadable. An example of a graph I'm seeing now:

0.00000   178.77778 357.55556 536.33333 715.11111 893.88889 1072.666671251.444441430.222221609.00000

x

I was wondering if it would be possible to tell plotille to just print the integer values for the X axis (without the decimal part) and set a min spacing (2 spaces maybe?) between the values.

Index out of bounds for hist() on negative values

Negative values in histogram sometimes seem to lead to negative bin indices that can underflow (and shouldnt be there in the first place).

I believe the fix is in plotille/_util in hist() around line 85
to change the computation of x_idx to

        x_idx = max(min(bins - 1, int(delta // xwidth)), 0)

(the max is new). Alas I don't have time to thoroughly test and/or create a PR right now, maybe someone else can pick it up

weird spike at zero

Cool library! I'm trying to plot some simple data, but the result has an odd spike at 0 on the x-axis:
sys.stderr.write(plotille.plot(np.arange(len(diff)).tolist(), diff.tolist(), x_min=0, height=20, X_label="Frame #", Y_label='Lag-Time (ms)'))

(Lag-Time (ms)) ^
180.205040 |
172.148096 | ⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
164.091152 | ⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
156.034208 | ⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
147.977264 | ⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
139.920320 | ⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
131.863376 | ⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
123.806432 | ⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
115.749488 | ⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
107.692544 | ⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
99.6356000 | ⡇⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⡀⠀⠀⡀⡀⠀⠀⠀⢸⢀⠀⡀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⠀⠀⡀⠀⠀⣀⠀⣀⢀⣀⣀⠀⡀⠀⢀⢀⠀⠀⢀⣀⡀⠀⡀⠀⠀⠀⠀⠀⠀⠀
91.5786560 | ⡇⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⡇⠀⠀⡇⡇⠀⠀⠀⢸⣿⠀⡇⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⠀⠀⡇⠀⠀⣿⠀⣿⢸⣿⣿⠀⡇⠀⢸⢸⠀⠀⢸⣿⡇⠀⡇⠀⠀⠀⠀⠀⠀⠀
83.5217120 | ⡇⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⡇⠀⠀⡇⡇⠀⠀⠀⢸⣿⠀⡇⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⠀⠀⡇⠀⠀⣿⠀⣿⢸⣿⣿⠀⡇⠀⢸⢸⠀⠀⢸⣿⡇⠀⡇⠀⠀⠀⠀⠀⠀⠀
75.4647680 | ⡇⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⡇⠀⠀⡇⡇⠀⠀⠀⢸⣿⠀⡇⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⠀⠀⡇⠀⠀⣿⠀⣿⢸⣿⣿⠀⡇⠀⢸⢸⠀⠀⢸⣿⡇⠀⡇⠀⠀⠀⠀⠀⠀⠀
67.4078240 | ⡇⢀⡀⢀⢸⠀⣀⠀⢀⠀⠀⡀⢀⠀⣀⠀⡀⣀⣀⢀⣸⣀⣀⣇⣀⣀⣇⣇⣀⣀⣀⣸⣿⣀⡇⣀⢀⢀⣇⣀⣀⣀⣀⣀⣀⣀⣀⣀⣿⣿⣀⣀⣇⣀⣀⣿⡀⣿⣸⣿⣿⡀⣇⣀⣸⣸⣀⣀⣸⣿⡇⣀⣇⠀⠀⠀⠀⠀⠀⠀
59.3508800 | ⡇⢸⡇⢸⢸⠀⣿⠀⢸⠀⠀⣿⣿⡇⣿⢸⡇⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣿⢸⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣿⣿⠀⠀⠀⠀⠀⠀⠀
51.2939360 | ⡇⢸⡇⢸⢸⠀⣿⠀⢸⠀⠀⣿⣿⡇⣿⢸⡇⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣿⢸⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣿⣿⠀⠀⠀⠀⠀⠀⠀
43.2369920 | ⡇⢸⡇⢸⢸⠀⣿⠀⢸⠀⠀⣿⣿⡇⣿⢸⡇⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣿⢸⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣿⣿⠀⠀⠀⠀⠀⠀⠀
35.1800480 | ⡇⢸⣇⢸⢸⠀⣿⢀⢸⠀⣀⣿⣿⡇⣿⣸⡇⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣿⣸⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣿⣿⠀⠀⠀⠀⠀⠀⠀
27.1231040 | ⡏⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀
19.0661600 | ⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
-----------|-|---------|---------|---------|---------|---------|---------|---------|---------|-> (Frame #)
           | 0         869.96250 1739.9250 2609.8875 3479.8500 4349.8125 5219.7750 6089.7375 6959.7000

Compared to matplotlib:
plt.plot(np.arange(len(diff)).tolist(), diff.tolist())

Figure_1

Accept `datetime.date` as X input

For time series plotting, python's built in datetime.datetime class is much appreciated! However, sometimes datetime.date is more convenient. Could these be accepted as input as well?

Feature request: Are Candlestick and Indicators are supported

I am looking at plotting some OHLC data as candlestick. i have done some work with matplotlib and streaming data (live quotes from stock broker) .. wondering if i would be able to do this on terminal. Reason is i dont want any graphical overload on the server.
thanks for your support.

`Figure.axvline(x) coordinates are wrong`

Figure.axvline(x, ...) requires 0 <= x <= 1, and it seems reasonable to assume that if the x_limits of the figure are x1, x2 the reference coordinate x is mapped to x1 + (x2 - x1) * x. In this setting x=0 corresponds to x1 and x=1 corresponds to x2.

In reality it seems that x=0 corresponds to the middle vertical (x1 + x2) / 2. So -1 would correspond to the left boundary, but negative reference coordinates are forbidden!

f = plotille.Figure()
f.width = 20
f.height = 20
f.set_x_limits(-1, 1)
f.axvline(0)  # would expect this to be at left boundary
print(f.show())
   (Y)     ^
         1 |
0.95000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.90000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.85000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.80000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.75000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.70000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.65000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.60000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.55000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.50000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.45000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.40000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.35000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.30000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.25000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.20000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.15000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.10000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
0.05000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
         0 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
-----------|-|---------|---------|-> (X)
           | -1        0         1

And likewise

In [90]: f = plotille.Figure()
    ...: f.width = 20
    ...: f.height = 20
    ...: f.set_x_limits(-2, 2)
    ...: f.axvline(0.5)  # would expect this to be in center
    ...: print(f.show())
   (Y)     ^
         1 |
0.95000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.90000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.85000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.80000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.75000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.70000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.65000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.60000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.55000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.50000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.45000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.40000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.35000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.30000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.25000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.20000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.15000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.10000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
0.05000000 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
         0 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀
-----------|-|---------|---------|-> (X)
           | -2        0         2

hex colors not showing up when parsing terminal results

Hi, we are trying to figure out why we are not getting hex values for the plotille results when parsing the output with hd on a terminal, do you know why this might happen ?

example :

I plot, setting all lines to 4bit "names" / "bright-green" the output on the terminal is correct, with all lines in green.

But when I parse it with hd I get no color code in hex :

echo ⢀⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⢰⠃⡎⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ | hd
00000000  e2 a2 80 e2 a1 8f e2 a0  80 e2 a0 80 e2 a0 80 e2  |................|
00000010  a0 80 e2 a0 80 e2 a0 80  e2 a0 80 e2 a0 80 e2 a0  |................|
00000020  80 e2 a0 80 e2 a0 80 e2  a0 80 e2 a0 80 e2 a1 87  |................|
00000030  e2 a0 80 e2 a0 80 e2 a2  b0 e2 a0 83 e2 a1 8e e2  |................|
00000040  a0 80 e2 a0 80 e2 a0 80  e2 a0 80 e2 a0 80 e2 a0  |................|
00000050  80 e2 a0 80 e2 a0 80 e2  a0 80 e2 a0 80 0a        |..............|
0000005e

do you know why this happens ?

using plotille for stock market charts

def tick(min, max, axis=None):
    """
    trying to mimic a stock market ticker
    """
    if axis == "X":
        return datetime.datetime.now().strftime("%H:%M:%S")
    else:
        min = int(min)
        max = 100
        return randint(min, max)


def main():
    X = []
    Y = []
    fig = plt.Figure()
    fig.plot(X, Y)
    fig.set_x_limits(min_=0)
    fig.set_y_limits(min_=0, max_=100)

    while True:
        fig.x_ticks_fkt = partial(tick, axis="X")
        fig.y_ticks_fkt = partial(tick)
        __import__('time').sleep(1)
        print(fig.show())


if __name__ == '__main__':
    main()

outputs
plotille

honestly i was surprised by the end result. i just a have an incoming ticker which has a changing price and datetime.seconds. i want just to append it to the x axis and show the new y value (price of the stock). can you please help me.

Make y-values exakt or approximate values of the data inputs

I have the Issue, that the y-values spread unevenly, so that I have no clue what the actual values are. Here is the output

 (Usage)   ^
      1042 |
       975 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
       908 | ⠀⡖⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠁⠀⠀⠀⠀
       840 | ⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
       773 | ⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
       706 | ⢀⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
       639 | ⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
       571 | ⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
       504 | ⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
       437 | ⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
       370 | ⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
       302 | ⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
       235 | ⡜⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
       168 | ⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
       101 | ⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
        34 | ⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
-----------|-|---------|---------|---------|---------|---------|-> (Time)
           | 20:37:58  21:41:04  22:44:11  23:47:17  00:50:24  01:53:30 

In my case I have values in Megabytes and I want to spread them over datetime objects, which works perfectly fine, but as you see, it looks like the usage in MB stagnates at 908, which is not true, because it stagnates at 945 MB.

It would be nice to have an option which makes the y-ticks around those values in a certain range.
My attempt would be to check which values appear more often and then to adjust a y-value at that point which should be something like the average of all points 5-10% of the total range .

for example [0, 10, 20, 20, 21, 25, 30, 32, 40, 44, 50]

the range is 50-0 = 50
10% of 50 is 5

for 0 and 10 nothing needs to be changed
(20+20+21+25)/4 = 21.5 , now remove those four values
(30+32)/2 = 31, same here
(40+44)/2 = 42, same here
50 stays like it is

the y-values should look like [0, 10, 21.5 , 21, 42, 50]

I think an option for this would smoothen a lot of plots

Histogram breaks when all values are the same

>>> import plotille
>>> print(plotille.histogram([0,0,0]))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/isak/.local/share/virtualenvs/mxaimbot_trainer-A7Up_mVO/lib/python3.7/site-packages/plotille/_graphs.py", line 126, in histogram
    fig.histogram(X, bins, lc)
  File "/home/isak/.local/share/virtualenvs/mxaimbot_trainer-A7Up_mVO/lib/python3.7/site-packages/plotille/_figure.py", line 257, in histogram
    self._plots += [Histogram.create(X, bins, lc)]
  File "/home/isak/.local/share/virtualenvs/mxaimbot_trainer-A7Up_mVO/lib/python3.7/site-packages/plotille/_figure.py", line 347, in create
    frequencies, buckets = hist(X, bins)
  File "/home/isak/.local/share/virtualenvs/mxaimbot_trainer-A7Up_mVO/lib/python3.7/site-packages/plotille/_util.py", line 82, in hist
    x_idx = min(bins - 1, int(delta // xwidth))
ZeroDivisionError: float divmod()

using plotille version 3.7

[feature request] Provide a CLI

Could you please provide a command-line entry point ?

Other similar libs (termgraph, bashplotlib, diagram) provide one, and it is very handy to draw a scatterplot / histogram in terminal from comma or space separated data in stdin.

using plotille for a real time chart

Hey everyone!

first of all, thank you all for working on plotille, that is a very nice library!

I am trying to have a real time chart, but I am having some hard time trying to figure out how to have the time in the x axis.

This is my initial code: https://github.com/osl-incubator/sugar/blob/main/src/sugar/plugins/stats.py#L94

but now I am trying to have the x axis with the time. and it seems it is not working properly.
as I saw in the source code it uses some math to calculate the ticks, so maybe it is breaking my code.

locally, in a wip, I tried x_ticks_fkt and register_label_formatter .. but it seems it is not working as I expected.

could you point me to any example that uses x axis for time? that I could use it for a real time chart?

another extra question, still about real time chart, do I need to create the figure for every iteration?
because if I use plot every time, it add more lines to the chart. so for now I am recreating the chart figure every time, but it would be nice to just update the data there.

thanks!

pendulum >= 1.5 seems to break plotille

    def convert(self, val):
        for t, f in reversed(self.converters.items()):
>           if isinstance(val, t):
E           TypeError: isinstance() arg 2 must be a type or tuple of types

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.