p9-cli
lets you draw graphs from the command line, building them up piece-by-piece.
It's a command line interface to plotnine, which is a Python adaptation of ggplot2. It won't let you do anything that you couldn't do with a simple python script. But it might be more convenient than writing one of those.
usage: p9 [-h]
[--debug]
[--dataset DATASET | --input FILE]
[--csv ARG=VAL [ARG=VAL ...]]
[--output FILE [ARG=VAL ...]]
[--geom GEOM [ARG=VAL ...]]
[--stat STAT [ARG=VAL ...]]
[--ann GEOM [ARG=VAL ...]]
[--scale SCALE [ARG=VAL ...]]
[--facet TYPE [ARG=VAL ...]]
[--theme [NAME] [ARG=VAL ...]]
[--xlab XLAB]
[--ylab YLAB]
[--title TITLE]
[mapping ...]
optional arguments:
-h, --help show this help message and exit
--debug Try to print python code to build plot
--dataset DATASET Use a built-in plotnine dataset
--input FILE, -i FILE
Read data from FILE
--csv ARG=VAL [ARG=VAL ...]
Configure csv parsing (see pandas.read_csv)
--output FILE [ARG=VAL ...], -o FILE [ARG=VAL ...]
Save output to FILE
Plot elements:
--geom GEOM [ARG=VAL ...], -g GEOM [ARG=VAL ...]
Add a geom to the plot (see plotnine.geoms)
--stat STAT [ARG=VAL ...], -s STAT [ARG=VAL ...]
Add a stat to the plot (see plotnine.stats)
--ann GEOM [ARG=VAL ...]
Add an annotation to the plot (see plotnine.annotate)
--scale SCALE [ARG=VAL ...]
Add an annotation to the plot (see plotnine.scales)
--facet TYPE [ARG=VAL ...], -f TYPE [ARG=VAL ...]
Add faceting to the plot (see plotnine.facets)
--theme [NAME] [ARG=VAL ...], -t [NAME] [ARG=VAL ...]
With NAME, apply a built-in theme to the plot;
without, customize the theme (see plotnine.themes)
--xlab XLAB Add an x-axis label to the plot (see plotnine.xlab)
--ylab YLAB Add a y-axis label to the plot (see plotnine.ylab)
--title TITLE Add a title to the plot (see plotnine.ggtitle)
mapping Add an aesthetic mapping to the plot (see
plotnine.ggplot, plotnine.aes)
For example, you can do
# scatter plot (default), with points colored and faceted
p9 --dataset mpg \
x=displ y=hwy color=class \
-f grid facets='drv ~ cyl'
# scatter plot with joined-up dots, plus a smoothed curve
p9 --dataset economics \
x=date y='unemploy/pop' \
-g point size=0.2 \
-g line \
-s smooth method=glm
See more examples in the examples/ folder, generated by examples/examples.sh.
There's support, at least on some level, for geoms (-g
, --geom
), stats (-s
, --stat
), scales (--scale
), facets (-f
, --facet
), themes (-t
, --theme
), annotations (--ann
), labels (--xlab
, --ylab
), title (--title
). You can take input from a file (-i
), stdin (default), or one of the builtin datasets (--dataset
).
The general model is that you pass aesthetic mappings in the form key=value
and add plot elements with the optional arguments. For --geom
, --stat
, --scale
and --facet
, you specify a name and keyword parameters in the form key=value
. The name (with -
replaced with _
) is looked up in the relevant part of the plotnine API, the keyword parameters are passed to it, and that's added to the plot. So -g point size=0.2
is the same as adding geom_point(size=0.2)
if you were writing Python. --scale x-date
is scale_x_date()
. --ann
is similar, except the name and args are passed directly to plotnine.annotate
.
When parsing keyword parameters, including aesthetic mappings, any -
in keys are replaced with _
. Ints are interpreted as ints, floats as floats. y
, n
, -
are interpreted as True
, False
, None
. A leading :
is dropped and forces string interpretation.
You can insert into a dict by appending .key
to the key, or a list by appending ,
(for single elements) or +
(for multiple elements separated by commas or a numeric range), and then you can leave off the name beforehand in future. So
a=3 b=4.5
dict-val.dict-key1=y .dict-key2=:n .dict-key3=-
list-val,=foo ,=bar +=1,3 +=7..10
==> { 'a': 3,
'b': 4.5,
'dict_val': {'dict_key1': True, 'dict_key2': 'n', 'dict_key3': None},
'list_val': ['foo', 'bar', 1, 3, 7, 8, 9, 10]
}
Ranges can be spcified in four ways:
from..to Inclusive range 1..3 == [1, 2, 3]
from,then..to Inclusive range with step 1,1.5..3 == [1, 1.5, 2, 2.5, 3]
from..^to Exclusive range 1..^3 == [1, 2]
from,then..^to Exclusive range with step 1,1.5..^3 == [1, 1.5, 2, 2.5]
There's currently no support for lists or dicts containing lists or dicts.
Plotnine has a number of built-in configurable themes, which you can select with --theme name key=val ...
. You can also override specific parts of the theme by not providing a name, like --theme key=val ...
.
To install, I use pipx
. It installs to an isolated environment in your home folder, and then adds a symlink to the executable from (in my case) ~/.local/bin
. Either of these should work:
pipx install 'git+https://github.com/ChickenProp/p9-cli.git'
git clone https://github.com/ChickenProp/p9-cli.git
pipx install ./p9-cli
Or you can maybe just run the p9
executable directly, if you have plotnine
and dependencies installed in your python environment.
Here are some things p9-cli
lacks:
-
There's no way to pass a dataset to a specific layer.
-
No support for coord transformations.
-
No support for animations.
-
Many theme elements aren't configurable because they're required to be specific
element_*
types that p9-cli can't construct. -
It should be possible to use
..foo..
and (equivalently)stat(foo)
in your aesthetics. But it looks like those are deprecated features of plotnine. The current way to do these in python would bey=after_stat('foo')
(instead ofy='..foo..'
ory='stat(foo)'
), but p9-cli doesn't support that yet. Nor does it supportafter_scale()
orstage()
, which have no equivalent. -
This file, plus the file examples.sh, is the full extent of the documentation.
-
It's not on pip or anything, you just have to install it from here. You need to install plotnine, too.
I make no commitment to future development.
I've written a little about my motivation for writing this.