Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

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]
          [--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/

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:         Inclusive range             1..3      == [1, 2, 3]
from,    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 ....

Here are some things it 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 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 be y=after_stat('foo') (instead of y='' or y='stat(foo)'), but p9-cli doesn't support that yet. Nor does it support after_scale() or stage(), which have no equivalent.

  • This file, plus the file, 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.


A command line grammar of graphics