Samplitude (s8e) is a statistical distributions command line tool
CLI generation and plotting of random variables:
$ samplitude "sin(0.31415) | sample(6) | round | cli" 0.0 0.309 0.588 0.809 0.951 1.0
The word samplitude is a portmanteau of sample and amplitude. This project also started as an étude, hence should be pronounced sampl-étude.
samplitude is a chain starting with a generator, followed by zero or more
filters, followed by a consumer. Most generators are infinite (with the
lists and possibly
stdin). Some of the filters can
turn infinite generators into finite generators (like
and some filters can turn finite generators into infinite generators, such as
Consumers are filters that necessarily flush the input;
unique, and the plotting tools,
examples of consumers. The
list consumer is a Jinja2 built-in, and other
Jinja2 consumers are
samplitude "sin(0.31415) | sample(5) | round | max | cli" 0.951
For simplicity, s8e is an alias for samplitude.
In addition to the standard
range function, we support infinite generators
lambdis 1.0 divided by the desired mean.
uniform(a, b): Get a random number in the range
[a, b]depending on rounding.
muis the mean, and
sigmais the standard deviation.
normal(mu, sigma): as above
lognormal(mu, sigma): as above
triangular(low, high): Continuous distribution bounded by given lower and upper limits, and having a given mode value in-between.
beta(alpha, beta): Conditions on the parameters are
alpha > 0and
beta > 0. Returned values range between 0 and 1.
gamma(alpha, beta): as above
alphais the scale parameter and
betais the shape parameter.
pareto(alpha): Pareto distribution.
alphais the shape parameter.
muis the mean angle, expressed in radians between 0 and
kappais the concentration parameter, which must be greater than or equal to zero. If kappa is equal to zero, this distribution reduces to a uniform random angle over the range 0 to
We have a special infinite generator (filter) that works on finite generators:
whose behaviour is explained below.
For input from files, either use
words with a specified environment variable
DICTIONARY, or pipe through
which reads from
If the file is a csv file, there is a
csv generator that reads a csv file with
Pandas and outputs the first column (if nothing else is specified). Specify the
column with either an integer index or a column name:
>>> s8e "csv('iris.csv', 'virginica') | counter | cli" 0 50 1 50 2 50
Finally, we have
permutations that are inherited from
itertools and behave exactly like those.
s8e "'ABC' | permutations | cli"
However, the output of this is rather non-UNIXy, with the abstractions leaking through:
s8e "'HT' | permutations | cli" ('H', 'T') ('T', 'H')
So to get a better output, we can use an elementwise join
s8e "'HT' | permutations | elt_join | cli" H T T H
which also takes a seperator as argument:
samplitude "'HT' | permutations | elt_join(';') | cli" H;T T;H
This is already supported by Jinja's
map function (notice the strings around
samplitude "'HT' | permutations | map('join', ';') | cli" H;T T;H
We can thus count the number of permutations of a set of size 10:
s8e "range(10) | permutations | len" 3628800
product generator takes two generators and computes a cross-product of
these. In addition,
A warning about infinity
All generators are (potentially) infinite generators, and must be sampled with
sample(n) before consuming!
Usage and installation
pip install samplitude
or to get bleeding release,
pip install git+https://github.com/pgdr/samplitude
This is pure Jinja2:
>>> samplitude "range(5) | list" [0, 1, 2, 3, 4]
However, to get a more UNIXy output, we use
cli instead of
>>> s8e "range(5) | cli" 0 1 2 3 4
To limit the output, we use
>>> s8e "range(1000) | sample(5) | cli" 0 1 2 3 4
That isn't very helpful on the
range generator, but is much more helpful on an
infinite generator, such as the
>>> s8e "uniform(0, 5) | sample(5) | cli" 3.3900198868059235 1.2002767137709318 0.40999391897569126 1.9394585953696264 4.37327472704115
We can round the output in case we don't need as many digits (note that
is a generator as well and can be placed on either side of
>>> s8e "uniform(0, 5) | round(2) | sample(5) | cli" 4.58 4.33 1.87 2.09 4.8
Selection and modifications
samplitude behavior is equivalent to the
head program, or from languages
such as Haskell. The
head alias is supported:
>>> samplitude "uniform(0, 5) | round(2) | head(5) | cli" 4.58 4.33 1.87 2.09 4.8
drop is also available:
>>> s8e "uniform(0, 5) | round(2) | drop(2) | head(3) | cli" 1.87 2.09 4.8
To shift and scale distributions, we can use the
scale(s) filters. To get a Poisson point process starting at 15, we can run
>>> s8e "poisson(0.3) | shift(15)" # equivalent to exponential(0.3)...
scale work on generators, so to add
sin(0.2), we can run
>>> s8e "sin(0.1) | shift(sin(0.2)) | sample(10) | cli"
Choices and other operations
choice with a finite generator gives an infinite generator that chooses
from the provided generator:
>>> samplitude "range(0, 11, 2) | choice | sample(6) | cli" 8 0 8 10 4 6
Jinja2 supports more generic lists, e.g., lists of strings. Hence, we can write
>>> s8e "['win', 'draw', 'loss'] | choice | sample(6) | sort | cli" draw draw draw loss win win
... and as in Python, strings are also iterable:
>>> s8e "'HT' | cli" H T
... so we can flip six coins with
>>> s8e "'HT' | choice | sample(6) | cli" H T T H H H
We can flip 100 coins and count the output with
counter (which is
>>> s8e "'HT' | choice | sample(100) | counter | cli" H 47 T 53
sort functionality does not work as expected on a
Counter object (a
dict type), so if we want the output sorted, we pipe through
>>> s8e "range(1,7) | choice | sample(100) | counter | cli" | sort -n 1 24 2 17 3 18 4 16 5 14 6 11
stdin() as a generator, we can pipe into
samplitude. Beware that
stdin() flushes the input, hence
stdin (currently) does not work with
infinite input streams.
>>> ls | samplitude "stdin() | choice | sample(1) | cli" some_file
Then, if we ever wanted to shuffle
ls we can run
>>> ls | samplitude "stdin() | shuffle | cli" some_file
>>> cat FILE | samplitude "stdin() | cli" # NOOP; cats FILE
The fun powder plot
For fun, if you have installed
matplotlib, we support plotting,
the most useful.
>>> samplitude "normal(100, 5) | sample(1000) | hist"
An exponential distribution can be plotted with
exponential(lamba). Note that
cli output must be the last filter in the chain, as that is a command-line
>>> s8e "normal(100, 5) | sample(1000) | hist | cli"
To repress output after plotting, you can use the
gobble filter to empty
>>> s8e "normal(100, 5) | sample(1000) | hist | gobble"
hist is the most useful, one could imaging running
timeseries, where a
line plot makes most sense:
>>> s8e "sin(22/700) | sample(200) | line"
The scatter function can also be used, but requires that the input stream is a
stream of pairs, which can be obtained either by the
product generator, or via
s8e "normal(100, 10) | sample(10**5) | round(0) | counter | scatter"
A fourier transform is offered as a filter
>>> samplitude "sin(0.1) | shift(sin(0.2)) | sample(1000) | fft | line | gobble"
Release history Release notifications | RSS feed
Hashes for samplitude-0.0.11-py2-none-any.whl