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-cliOr 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.