Plotille: braille-dot plots in the terminal with no dependencies
Plot in the terminal using braille dots.
At a glance
- What is it?
- Plotille renders scatter plots, histograms, heatmaps and images into a terminal using braille dots and ANSI colours, with a Figure class for composed multi-panel figures, a one-call graphing helper, and no runtime dependencies. It suits a script that has to show a plot where there is no browser and no display, and it is not a replacement for a real plotting library.
- Who is it for?
- Plotille fits a script or CLI tool that has to present a distribution, a time series or a heatmap where only a terminal is available, since it produces a real string you can print, log or pipe, and since the Figure class supports several panels with labels and a legend in one canvas. It is the wrong choice if you need publication-quality output, since a braille cell gives you two columns and four rows of dots per character and the result is text.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 46 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Two dots wide, four dots tall
Plotille is described as plots, scatter plots, histograms and heatmaps in the terminal using braille dots, and foreground and background colours, with no dependencies. The project description puts it as a very small sibling to matplotlib: use the Figure class for complex figures, use the graphing function for fast and simple plots, or use the canvas to plot dots, lines and images yourself.
The braille trick is what makes the resolution work. A Unicode braille pattern cell encodes eight dots, two columns by four rows, so a character cell of the terminal gives you a small raster rather than a single point. A 60 by 30 character figure is therefore roughly 120 by 120 addressable dots, and lines drawn between data points land between the dot positions rather than on them. That is why the readme notes that the library is like drawille but focused on graphing, plus X and Y axes.
The no-dependency claim is literal. The project metadata declares no runtime requirements at all: the package lists only itself under keywords and has no dependencies array in the pyproject. Everything from the colour handling to the interpolation is implemented in the package. That is the sharpest contrast with a typical plotting library, and it is what makes plotille usable in a constrained environment.
The package is plotille on PyPI at version 6.0.5, requiring Python 3.10 or newer, and the classifiers cover CPython 3.10 through 3.14 and PyPy 3.11. The topics list covers braille, heatmap, histogram, images, plot, plotting, python, scatter-plot, terminal, timeseries, unicode and visualization.
The MIT licence is what the package metadata declares. The repository's own licence field, however, is recorded as unknown, so the LICENSE file is the authority if you need one for a compliance check.
The Figure class, and what you can put in it
The recommended way to construct plots is the Figure class, which is described as the class to compose multiple plots.
You create a Figure, define its properties and add your plots. The properties are width and height, which define the number of characters in the X and Y direction used for plotting, x_limits and y_limits for the reference coordinate system, color_mode as a string, with_colors as a boolean for whether to use colours at all, background for the background colour, and x_label and y_label for the axis labels.
The plotting methods cover more than lines. Figure.plot creates a plot with linear interpolation between points, Figure.scatter creates a scatter plot with no interpolation, Figure.histogram creates a histogram over X with a default of 160 bins, and Figure.text prints texts at coordinates.
Then there are the annotation methods, which use relative coordinates on the canvas with all coordinates in the range 0 to 1. Figure.axvline plots a vertical line at x, Figure.axvspan a vertical rectangle from xmin and ymin to xmax and ymax, Figure.axhline a horizontal line, and Figure.axhspan a horizontal rectangle. Figure.imgshow displays data as an image on a 2D regular raster.
Two lifecycle methods matter. Figure.clear removes all plots, texts, spans and images from the figure, and Figure.show creates a canvas, plots the registered plots and returns the string for displaying the plot, with a legend argument.
The shape of the API is worth noticing: show returns a string rather than printing it. That means a figure is a value, and you decide whether it goes to stdout, a log file or a web page. The readme's example composes several plots with different colours and labels and then prints fig.show(legend=True).
The one-call path, and the canvas underneath
The Figure is the recommended path, but the readme also describes utility functions for fast graphing of single plots, with plot as the entry point.
The signature shows the shape of it: X and Y take sequences of float or int, or sequences of datetime.datetime, with width defaulting to 80 and height to 40, X_label and Y_label defaulting to 'X' and 'Y', linesep defaulting to a newline, interp as an optional linear interpolation, and x_min, x_max, y_min and y_max as optional overrides of the data range.
The datetime support is the feature that makes this usable for operational data. The readme states that basic support for timeseries plotting was provided with release 3.2, so for any X or Y values you can also add datetime.datetime or numpy.datetime64 values, and labels are generated respecting the difference of x_limits and y_limits.
That last point is the subtle one. If you plot a year of hourly data without datetime support, the axis labels have to come from somewhere else and you end up formatting ticks yourself. With datetime values in the data, the library derives the tick labels from the limits, so a daily or monthly cadence appears on the axis rather than a raw float.
The canvas is the third level of the API, the layer where you plot dots, lines and images yourself. It is also where the colour and background machinery lives, and the readme points at plotille.color() as the reference for the available colour modes.
Heatmap and image support arrived with release 4.0, described as support for heatmaps using background colours for figures and displaying images binary with braille, or in colour with background colours using the canvas.
One constraint from the older releases still matters for anyone on a legacy runtime: if you are still using Python 2.7, use plotille v4 or before, since with v5 the author dropped support for Python 2.7 because maintaining the discontinued version was too much effort.
Working with the project
Installation is a single pip command:
pip install plotilleThe project layout is small and conventional: a plotille/ package, an examples/ directory, a tests/ directory, imgs/ for the documentation images, a Makefile, pyproject.toml and uv.lock.
The examples folder is unusually good and is the fastest way to see what the library can do. It holds color_example.py, custom_ticks_example.py, ellipse_example.py, histograms_example.py, house_example.py, images_example.py, logo_example.py, markers_and_labels_example.py, network.py, olympic_rings_example.py, performance_example.py, plot_example.py, scatter_cats_example.py, scatter_example.py, side_by_side_example.py, span_example.py, stock_example.py and wetterdienst_example.py, along with a compressed weather dataset, wetter-data.json.gz. The presence of side_by_side, custom_ticks and the house and olympic rings examples tells you the range: multiple panels, custom axis ticks, and shapes rather than only data.
The build tooling is modern. The Makefile wraps uv: fmt runs ruff format and ruff check with fix, check runs both in check mode, typing runs mypy over the package with the ty check commented out, tests runs pytest with -s -vvv, and install runs uv install. Every command uses uv run --locked, so the toolchain is pinned to the lockfile rather than to whatever is installed.
Testing is configured with pytest and coverage, with the addopts enabling coverage of the plotille package with branch coverage and three report formats. The linting configuration is ruff with a broad rule selection, and the dependency group for development includes mypy, numpy, Pillow, pytest, pytest-cov, pytest-mock, ruff and ty.
The CI badge covers Python 3.10 to 3.14 and PyPy 3.11, and there is a separate badge for the ruff version and one for uv, which is the tool the Makefile is built around.
Where Plotille is the wrong choice
The first limitation is resolution and precision. A braille cell gives you two columns and four rows of dots, and the dots are on a fixed lattice. A line between two data points is drawn to the lattice, so a very small feature in a large dataset may occupy no dot at all, and the shape you see is a rendering of the data at roughly the character resolution rather than the data itself. For a diagnostic plot that is usually fine, and for anything where a reader needs to judge a value precisely it is not.
The second is that the output is text. There is no vector output, no PDF, no SVG and no interactive anything. A plot in a terminal cannot be zoomed, cannot be annotated by a reader, and degrades when the font does not support the braille block or when the terminal is narrow. That is the whole point of the library, but it does mean it cannot be the final artefact in a report.
The third is that colour output depends on the terminal, not on the library. The colour_mode setting selects between the library's own modes, and with_colors is a boolean to turn colours off entirely, but if the destination does not support 24-bit colour the rendering degrades. A pipeline that pipes output to a file will produce escape sequences in that file unless you disable colours.
The fourth is the dependency-free trade-off. No dependencies means no numpy requirement, which is genuinely valuable, but it also means the library does the arithmetic itself in pure Python. For a very large dataset that is slow, and the readme's own answer is an external project, plotilleresample by Carlos A. Planchón, which downsamples large datasets with stride, min/max or LTTB to the canvas resolution before plotting so that 100k or more points render fast without losing peaks. That is the pattern: plotille does not scale, you downsample first.
The fifth is the version state. The package is at 6.0.5, released on 2026-02-17 after 6.0.4 and 6.0.3 days earlier, and the last push to the repository was on 2026-09-08, so the tree is ahead of the last release. A 6.x version also means the API has had six major revisions, so an example you find from an older blog post may not match what is on PyPI now.
Editorial conclusion
Plotille fits a script or CLI tool that has to present a distribution, a time series or a heatmap where only a terminal is available, since it produces a real string you can print, log or pipe, and since the Figure class supports several panels with labels and a legend in one canvas. It is the wrong choice if you need publication-quality output, since a braille cell gives you two columns and four rows of dots per character and the result is text. Before adopting it, note that the library is at version 6.0.5 and requires Python 3.10 or newer, that the package metadata declares MIT while the repository licence field is left unrecorded, and that the last push was on 2026-09-08 with v6.0.5 published on 2026-02-17.
Frequently asked questions
How do I install Plotille?
Run pip install plotille. The library has no runtime dependencies, so nothing else is pulled in, and it requires Python 3.10 or newer with classifiers for CPython 3.10 through 3.14 and PyPy 3.11.
How does Plotille draw in the terminal?
It uses Unicode braille dots, where a character cell encodes a two-by-four dot grid, and adds foreground and background colours for heatmaps and images. The project describes itself as like drawille but focused on graphing, with X and Y axes.
Does Plotille support time series data?
Yes, since release 3.2. For any X or Y values you can also pass datetime.datetime or numpy.datetime64 values, and the axis labels are generated respecting the difference between x_limits and y_limits.
What can the Plotille Figure class draw?
Lines with linear interpolation, scatter plots, histograms, text at coordinates, vertical and horizontal lines and spans using relative canvas coordinates, and images via imgshow. A Figure holds several plots with labels and can show them with a legend, and clear resets it.
How do I plot a very large dataset quickly with Plotille?
Downsample before plotting. The readme points to plotilleresample by Carlos A. Planchón, which reduces a large dataset using stride, min/max or LTTB to the canvas resolution so that 100k or more points render fast without losing peaks, and it also has no dependencies.
What licence is Plotille released under?
The package metadata declares MIT, with license = "MIT" in the pyproject.toml, although the repository's own licence field is left unrecorded. The last push was on 2026-09-08 and the newest release is v6.0.5 from 2026-02-17.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tammoippen-plotille)Was this useful?