├── .gitignore ├── MANIFEST.in ├── plottyprint ├── __init__.py ├── boxplot.py ├── utils.py ├── timeseries.py ├── histogram.py └── scatterplot.py ├── setup.py ├── LICENSE.txt ├── readme.rst ├── boxplot.svg ├── histogram_fancy.svg ├── histogram_simple.svg ├── scatterplot.svg └── timeseries.svg /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | /dist/ 3 | *.egg-info 4 | *.egg 5 | build/ 6 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.rst 2 | include *.svg 3 | include *.txt 4 | -------------------------------------------------------------------------------- /plottyprint/__init__.py: -------------------------------------------------------------------------------- 1 | from .scatterplot import scatterplot 2 | from .boxplot import boxplot 3 | from .histogram import histogram 4 | from .timeseries import timeseries 5 | -------------------------------------------------------------------------------- /plottyprint/boxplot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | from .utils import remove_chart_junk, PlottyFig 4 | 5 | 6 | def boxplot(variables, 7 | labels, 8 | title="", 9 | numticks=3, 10 | labelsize=14, 11 | size=(10, 10), 12 | font="Lato", 13 | notch=True): 14 | arrays = [np.sort(np.array(x)) for x in variables] 15 | 16 | fig = plt.figure(figsize=size, FigureClass=PlottyFig) 17 | ax = fig.add_subplot(1, 1, 1) 18 | 19 | ax.set_title(title + '\n', 20 | fontsize=labelsize * 1.25, 21 | fontname=font) 22 | 23 | ax = remove_chart_junk(ax, numticks, labelsize) 24 | 25 | bp = ax.boxplot(arrays, notch=notch, sym="k.", labels=labels) 26 | for element in ['boxes', 'whiskers', 'fliers', 'means', 'medians', 'caps']: 27 | plt.setp(bp[element], color="black", linewidth=1.75) 28 | return fig 29 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | 4 | def readme(): 5 | with open('README.rst') as f: 6 | return f.read() 7 | 8 | 9 | setup(name='plottyprint', 10 | version='0.1', 11 | description='provide a couple of easy to use, very basic, printable plots on top of matplotlib', 12 | long_description=readme(), 13 | url='https://github.com/paultopia/plottyprint', 14 | classifiers=[ 15 | 'Development Status :: 3 - Alpha', 16 | "Intended Audience :: Developers", 17 | "Intended Audience :: Science/Research", 18 | "License :: OSI Approved :: MIT License", 19 | "Programming Language :: Python :: 3 :: Only" 20 | ], 21 | keywords="plotting, datavis", 22 | author='Paul Gowder', 23 | author_email='paul.gowder@gmail.com', 24 | license='MIT', 25 | packages=['plottyprint'], 26 | python_requires='>=3', 27 | install_requires=['numpy', 'matplotlib>=2.1.1', 'statsmodels', 'scipy'], 28 | zip_safe=False) 29 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2018 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the “Software”), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /plottyprint/utils.py: -------------------------------------------------------------------------------- 1 | import matplotlib 2 | def remove_chart_junk(axis, numticks, labelsize): 3 | 4 | # reduce ticks 5 | axis.locator_params(nbins=numticks) 6 | 7 | # remove unnecessary borders 8 | axis.spines['top'].set_visible(False) 9 | axis.spines['right'].set_visible(False) 10 | axis.spines['left'].set_color((0.1, 0.1, 0.1, 0.2)) 11 | axis.spines['bottom'].set_color((0.1, 0.1, 0.1, 0.2)) 12 | 13 | # prettify tick labels 14 | axis.tick_params(axis='both', 15 | which='both', 16 | length=0, 17 | labelsize=labelsize, 18 | pad=labelsize * 0.66, 19 | labelcolor=(0.25, 0.25, 0.25)) 20 | return axis 21 | 22 | 23 | class PlottyFig(matplotlib.figure.Figure): 24 | 25 | def get_main_plot(self): 26 | return self._axstack.as_list()[0] 27 | 28 | def get_lines(self): 29 | return self._axstack.as_list()[0].lines 30 | 31 | def set_line_width(self, width): 32 | for line in self._axstack.as_list()[0].lines: 33 | line._linewidth = width 34 | 35 | def change_title(self, title): 36 | self._axstack.as_list()[0].set_title(title) 37 | -------------------------------------------------------------------------------- /plottyprint/timeseries.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | from .utils import remove_chart_junk, PlottyFig 4 | 5 | 6 | def timeseries(in_dates, 7 | events, 8 | labels=["", ""], 9 | title="", 10 | numticks=3, 11 | labelsize=12, 12 | size=(10, 10), 13 | font="Lato"): 14 | fig = plt.figure(figsize=size, FigureClass=PlottyFig) 15 | ax = fig.add_subplot(1, 1, 1) 16 | numticks = 5 17 | 18 | ax.set_title(title + '\n', 19 | fontsize=labelsize * 1.25, 20 | fontname=font) 21 | 22 | ax = remove_chart_junk(ax, numticks, labelsize) 23 | 24 | dates = np.array(in_dates) 25 | dates_sorted = (np.sort(dates)) 26 | event1 = np.array(events[0])[np.argsort(dates)] 27 | p1 = ax.plot(dates_sorted, event1, 'k-', label=labels[0]) 28 | if len(events) > 1: 29 | event2 = np.array(events[1])[np.argsort(dates)] 30 | p2 = ax.plot(dates_sorted, event2, color=(0.6, 0.6, 0.6), linestyle='-', label=labels[1]) 31 | leg = ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05), ncol=2, framealpha=0) 32 | leg.get_texts()[1].set_color((0.4, 0.4, 0.4)) 33 | return fig 34 | -------------------------------------------------------------------------------- /plottyprint/histogram.py: -------------------------------------------------------------------------------- 1 | import matplotlib 2 | import matplotlib.pyplot as plt 3 | import numpy as np 4 | from scipy.stats import gaussian_kde 5 | from .utils import remove_chart_junk, PlottyFig 6 | 7 | def histogram(variable, 8 | bins="auto", 9 | title="", 10 | numticks=5, 11 | labelsize=15, 12 | size=(10, 10), 13 | add_kde=False, 14 | kernel_param=0.4, 15 | show_n=True, 16 | font="Lato"): 17 | var = np.sort(np.array(variable)) 18 | 19 | fig = plt.figure(figsize=size, FigureClass=PlottyFig) 20 | ax = fig.add_subplot(1, 1, 1) 21 | 22 | ax.set_title(title + '\n', 23 | fontsize=labelsize * 1.25, 24 | fontname=font) 25 | 26 | ax = remove_chart_junk(ax, numticks, labelsize) 27 | 28 | if add_kde: 29 | density = True 30 | else: 31 | density = False 32 | 33 | if show_n: 34 | ax.set_xlabel("n = " + str(var.size), 35 | fontsize=labelsize, 36 | labelpad=labelsize * 0.7, 37 | color=(0.15, 0.15, 0.15), 38 | fontname=font) 39 | 40 | ax.hist(var, bins=bins, density=density, lw=0) 41 | 42 | # fix bar colors 43 | bars = [x for x in ax.get_children() if type(x) is matplotlib.patches.Rectangle] 44 | for idx, bar in enumerate(bars): 45 | if idx % 2 == 0: 46 | bar.set_color((0.1, 0.1, 0.1, 0.3)) 47 | else: 48 | bar.set_color((0.4, 0.4, 0.4, 0.3)) 49 | bars[-1].set_color("white") 50 | 51 | if add_kde: 52 | ds = gaussian_kde(var) 53 | mx = np.max(var) 54 | mn = np.min(var) 55 | ls = np.linspace(mn, mx) 56 | ds.covariance_factor = lambda : kernel_param 57 | ds._compute_covariance() 58 | dy = ds(ls) 59 | ax.plot(ls, dy, color=(0.1, 0.1, 0.1, 0.8)) 60 | ax.set_yticks([]) 61 | ax.spines['left'].set_visible(False) 62 | 63 | return fig 64 | -------------------------------------------------------------------------------- /plottyprint/scatterplot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import statsmodels.api as sm 4 | import textwrap 5 | from statsmodels.stats.outliers_influence import summary_table 6 | from .utils import remove_chart_junk, PlottyFig 7 | 8 | 9 | def get_ci_values(fitted_regression, alpha): 10 | _, sumdata, _ = summary_table(fitted_regression, alpha=alpha) 11 | ci_low, ci_high = sumdata[:, 4:6].T 12 | return ci_low, ci_high 13 | 14 | 15 | def scatterplot(x, y, title="", 16 | xlabel="", 17 | ylabel="", 18 | numticks=3, 19 | labelsize=15, 20 | dotsize=8, 21 | ylabel_wrapping=6, 22 | size=(10, 10), 23 | fit_line=True, 24 | confidence=True, 25 | alpha=0.05, 26 | font="Lato"): 27 | 28 | # everything works better with numpy arrays 29 | x = np.array(x) 30 | y = np.array(y) 31 | 32 | # generate the fitted values and confidence intervals 33 | if fit_line: 34 | regline = sm.OLS(y, sm.add_constant(x)).fit() 35 | if confidence: 36 | ci_low, ci_high = get_ci_values(regline, alpha) 37 | 38 | # baseline plot 39 | fig = plt.figure(figsize=size, FigureClass=PlottyFig) 40 | ax = fig.add_subplot(1, 1, 1) 41 | 42 | # label all the things 43 | ax.set_title(title + '\n', 44 | fontsize=labelsize * 1.25, 45 | fontname=font) 46 | ax.set_xlabel(xlabel, 47 | fontsize=labelsize, 48 | labelpad=labelsize * 0.7, 49 | color=(0.15, 0.15, 0.15), 50 | fontname=font) 51 | ax.set_ylabel(textwrap.fill(ylabel, ylabel_wrapping), 52 | fontsize=labelsize, 53 | labelpad=labelsize * 2, 54 | color=(0.15, 0.15, 0.15), 55 | rotation='horizontal', 56 | horizontalalignment='center', 57 | fontname=font) 58 | 59 | # matplotlib tends to get broken if you don't sort the data first, so 60 | x_sorted = np.sort(x) 61 | y_sorted = y[np.argsort(x)] 62 | if fit_line: 63 | fitted = regline.fittedvalues[np.argsort(x)] 64 | if confidence: 65 | lowband = ci_low[np.argsort(x)] 66 | highband = ci_high[np.argsort(x)] 67 | 68 | # plot the basic scatterplot 69 | ax.plot(x_sorted, y_sorted, 'k.', ms=dotsize) 70 | 71 | ax = remove_chart_junk(ax, numticks, labelsize) 72 | 73 | # plot regression line in grey, transparent enough for dots to show through 74 | if fit_line: 75 | ax.plot(x_sorted, fitted, color=(0.1, 0.1, 0.1, 0.2), linewidth=2) 76 | # fill space between confidence interval endpoints and regression line in lighter grey 77 | 78 | # plot bands for confidence intervals 79 | if confidence: 80 | ax.fill_between(x_sorted, lowband, fitted, facecolor=(0.7, 0.7, 0.7, 0.2)) 81 | ax.fill_between(x_sorted, highband, fitted, facecolor=(0.7, 0.7, 0.7, 0.2)) 82 | 83 | return fig 84 | -------------------------------------------------------------------------------- /readme.rst: -------------------------------------------------------------------------------- 1 | Plottyprint 2 | =========== 3 | 4 | The Goal 5 | -------- 6 | 7 | Make simple data visualizations in Python that are **easy**, 8 | **attractive**, and most importantly **appropriate for dead-tree 9 | printing** (like in academic journals, conference posters, or 10 | newspapers), with a bias toward greyscale in case color printing is 11 | expensive (or just not allowed). 12 | 13 | This very small library is targeted at the easiest 60% or so of plots 14 | that social scientists and student journalists and other 15 | light-to-moderate data users will want to produce. 16 | 17 | Right now, the amount of effort it takes to go from from no plots at all 18 | or really ugly plots to simple but attractive plots is *much* longer 19 | than the amount of effort from simple but attractive plots to really 20 | complex plots. This strikes me as unacceptable. If you want to produce a 21 | 4-d contour plot overlaid on a map of the world with color representing 22 | time, I can’t help you. But if you want to produce a basic scatterplot, 23 | maybe with a least squares fit on top of it, and then slap it into your 24 | journal submission to impress the peer reviewers, I’m here for you. 25 | 26 | The Challenges 27 | -------------- 28 | 29 | 1. Default matplotlib plotting is ugly, and making attractive plots is 30 | difficult. 31 | 32 | 2. There are many Python packages that make it easy to create beautiful 33 | plots on top of Matplotlib. 34 | `Seaborn `__, 35 | `Bokeh `__, and 36 | `Plotly `__ are my favorite examples, but 37 | the readme to `Altair `__ lists 38 | numerous other excellent options. However, these options are all 39 | built for web or interactive use, not for printing. They have lots of 40 | colors, default proportions appropriate for screen usage, and often 41 | interactive elements that don’t make sense on paper. While it’s 42 | possibly to convince those libraries to make plots for print, it’s a 43 | lot of work. (If you want to do that, I recommend using a Python 44 | port of `ggplot `__ or the plotting 45 | convenience functions `in Pandas `__.) 46 | 47 | The Plottyprint Solution 48 | ------------------------ 49 | 50 | This very small library aims to provide a handful of basic and 51 | attractive printable plots that will work out of the box with sensible 52 | defaults for the most simple use cases. Right now, it supplies four 53 | workhorse plots: 54 | 55 | 1. A **scatterplot** between two variables. By default, the scatterplot 56 | has a least squares line through it, and a confidence region around 57 | that line, but this is easy to turn off. 58 | 59 | 2. A **histogram** of one variable. If you want to get really fancy to 60 | impress the peer reviewers, you can stick a kernel density estimator 61 | line on top of it. 62 | 63 | 3. A **boxplot** with the standard frills (whiskers, notches, all that 64 | good stuff). 65 | 66 | 4. A **time series plot** that gives you a line of one or two events 67 | over time. The time series plot is experimental, and might not work 68 | with your data; I’ll try to improve it in subsequent versions. 69 | 70 | This, obviously, represents the science communicator’s basic toolkit for 71 | displaying the relationship between two variables, the shape of one 72 | variable, the relationship between mean, interquartile range, and 73 | outliers for several variables, and variable behavior over time, 74 | respectively. 75 | 76 | Each of these elements is presented in high-contrast greyscale, and has 77 | all of matplotlib’s default `chart 78 | junk `__ ruthlessly ripped 79 | out. 80 | 81 | In this 0.1 release, there are only a handful of customization options, 82 | but over time I plan to add more plot types and add a bit more 83 | customization. Moreover, every plot returns a (subclass of a) Matplotlib 84 | figure, so if you know matplotlib you can always do your own 85 | customization after the fact. 86 | 87 | Here are some examples. 88 | 89 | Scatterplot, with fit line and confidence region. 90 | 91 | .. figure:: scatterplot.svg 92 | :alt: scatterplot 93 | 94 | 95 | Histogram, no KDE estimator. 96 | 97 | .. figure:: histogram_simple.svg 98 | :alt: simple histogram 99 | 100 | 101 | Histogram, with KDE estimator 102 | 103 | .. figure:: histogram_fancy.svg 104 | :alt: fancy histogram 105 | 106 | 107 | Boxplot 108 | 109 | .. figure:: boxplot.svg 110 | :alt: boxplot 111 | 112 | 113 | Time Series 114 | 115 | .. figure:: timeseries.svg 116 | :alt: time series 117 | 118 | 119 | Installation 120 | ------------ 121 | 122 | ``pip install plottyprint`` 123 | 124 | Usage 125 | ----- 126 | 127 | There are three functions, each corresponding to a plot. Each takes one 128 | or more Numpy arrays, or anything that can be cast into a Numpy array 129 | with ``np.array()`` without going wrong (lists, Pandas ``DataFrame`` 130 | columns, etc.), plus some configuration. 131 | 132 | Each function returns a ``PlottyFig`` object. This is just a subclass of 133 | ``matplotlib.figure.Figure``, with a handful of convenience methods 134 | (documented below) to tweak your plots after you create them and smooth 135 | out the rough edges of the Matplotlib api. Because it’s a figure 136 | subclass, those who know Matplotlib can also dig in deeper to tweak to 137 | your heart’s content. 138 | 139 | Scatterplot 140 | ~~~~~~~~~~~ 141 | 142 | **scatterplot(x, y, title=“”, xlabel=“”, ylabel=“”, numticks=3, 143 | labelsize=15, dotsize=8, ylabel_wrapping=6, size=(10, 10), 144 | fit_line=True, confidence=True, alpha=0.05, font=“Lato”)** 145 | 146 | - x and y are, obviously, your data. 147 | 148 | - title is, obviously, the title of the plot 149 | 150 | - xlabel and ylabel are, obviously, the labels for your data. 151 | 152 | - numticks is (wait for it) the number of ticks to show on each axis. 153 | For mysterious reasons, sometimes Matplotlib likes to give you a 154 | little more or fewer than the number asked for, but at any rate the 155 | default is a nice small number that will show the scale of the data 156 | without overwhelming the reader with noise. 157 | 158 | - labelsize is the size of the axis labels. The title will be scaled up 159 | a little from this. 160 | 161 | - dotsize is the size of the individual points in the plot. 162 | 163 | - ylabel_wrapping is the number of characters in the y label before it 164 | wraps to another line. (Making y labels attractive is a bit 165 | difficult.) 166 | 167 | - size is a tuple representing the size in inches 168 | 169 | - fit_line is a boolean representing whether or not to put a least 170 | squares line in the plot. 171 | 172 | - confidence is a boolean representing whether or not to put a 173 | confidence interval around the least squares line. Obviously, this 174 | won’t do anything if you don’t have a least squares line in there. 175 | 176 | - alpha is the width of your confidence interval. The default 177 | represents the good old fashioned 95% interval. 178 | 179 | - font is the name of the font for labels. See below for some caveats on this. 180 | 181 | Histogram 182 | ~~~~~~~~~ 183 | 184 | **histogram(variable, bins=“auto”, density = False, title=“”, 185 | numticks=5, labelsize=15, size=(10, 10), add_kde=False, kernel_param = 186 | 0.4, show_n = True, font=“Lato”)** 187 | 188 | - variable is, obviously, your data. 189 | 190 | - bins can be a number of bins, or “auto” to let numpy come up with 191 | something for you 192 | 193 | - add_kde controls whether you want to slap a kernel density estimator 194 | plot on top of your histogram. If you do want to do this, it’ll 195 | change the scale of the histogram: it will become probability density 196 | rather than counts, and, since the y label on a density histogram is 197 | anywhere between confusing and outright deceptive, it gets removed. 198 | Call me paternalistic. 199 | 200 | - kernel_param is a parameter that goes into the kernel density 201 | estimator. Scipy does `a lot of fancy 202 | math `__ 203 | with this, but you can think of it as kind of similar to the 204 | bandwidth parameter in the `R kde 205 | function `__. 206 | For practical purposes, larger numers should produce smoother plots, 207 | but it’s probably worth playing with interactively. 208 | 209 | - show_n is a boolean determining whether to show the number of 210 | observations as a label below the x axis or not. 211 | 212 | Everything else is the same as in ``scatterplot``. 213 | 214 | Boxplot 215 | ~~~~~~~ 216 | 217 | **boxplot(variables, labels, title=“”, numticks=3, labelsize=14, 218 | size=(10, 10), font=“Lato”)** 219 | 220 | Everything here is the same as in ``scatterplot`` except that variables 221 | is a list of, well, variables (numpy arrays etc.), and labels is a list 222 | of labels. You can put as many variables in here as you can squeeze in. 223 | 224 | Time Series 225 | ~~~~~~~~~~~ 226 | 227 | **timeseries(in_dates, events, labels = [“”, “”], title=“”, numticks=3, 228 | labelsize=12, size=(10, 10), font=“Lato”, notch=True)** 229 | 230 | - in_dates is an array (or list etc.) of ``date`` objects (from the 231 | standard Python datetime module). 232 | 233 | - events is a list of arrays of events. There can be a maximum of 234 | two—each of these will be plotted as a different line. (So, in_dates 235 | will be a column of your data, and events will be a list of one or 236 | two columns from your data.) 237 | 238 | - labels is, like in boxplot, a list of labels for your events. 239 | 240 | - notch is whether to put a notch in the boxes marking out a confidence 241 | interval around the median. Uses the Matplotlib default, which isn’t 242 | terribly clearly specified in `the 243 | documentation `__, 244 | but I assume (from the bootstrap parameter in there) is 95%. 245 | 246 | Otherwise, the parameters are the same as above. However, you should 247 | note that numticks doesn’t control the number of entries on the x axis 248 | (time). Messing with that is actually a terribly gnarly procedure, but 249 | the defaults seem to be working. 250 | 251 | PlottyFig Object 252 | ~~~~~~~~~~~~~~~~ 253 | 254 | As noted above, the PlottyFig object supplies several convenience 255 | methods, which can be called on any instance generated by this library 256 | (denoted ``instance`` below), including: 257 | 258 | **instance.get_main_plot()** returns the Matplotlib ``Axes`` object 259 | containing the actual plot—this is where you do things like change the 260 | title, tweak borders, fonts, etc., or, for more advanced uses, overlay 261 | plots of extra data onto the existing axis and suchlike. Mutating the object returned by this function should mutate the underlying figure. 262 | 263 | **instance.get_lines()** returns a list of the lines that make up the 264 | plot. 265 | 266 | **instance.change_title(title)** changes the title of an existing plot. 267 | 268 | **instance.set_line_width(width)** sets the width of the lines in the 269 | plot. 270 | 271 | Right now, this class is a stub for future development: I like the idea 272 | of smoothing out the Matplotlib api a little, but don’t know what 273 | convenience methods would be most useful. More to be added in future 274 | versions. 275 | 276 | Possible Glitches 277 | ----------------- 278 | 279 | - This requires python 3, and a recent version of Matplotlib. 280 | I've tested it in Python 3.6.4 with Matplotlib 2.1.2. 281 | In particular, if ``histogram`` breaks, or if ``scatterplot`` 282 | produces strange lines around the confidence bands, that's 283 | going to be an obsolete Matplotlib version. 284 | 285 | - Fonts are a problem with Matplotlib, and if you run into font 286 | difficulties then see `this blog 287 | post `__ for 288 | a fix. I’ve set Lato as the font for everything because it’s pretty 289 | and `on google fonts `__. 290 | 291 | - I haven’t quite sorted out timeseries date ranges yet. Right now it 292 | just uses the Matplotlib defaults, and uses the ordinary plotting 293 | method rather than the ``plot_date`` method to generate 294 | (``plot_date`` produces mysterious and bizarre results). A PR to make 295 | this a little nicer would be very welcome. 296 | 297 | Contributing 298 | ------------ 299 | 300 | Just file an issue or a PR. 301 | 302 | Current priorities include: 303 | 304 | 1. Making the time series better, particularly with respect to 305 | customization options for the x axis ticks. 306 | 307 | 2. Some way to apply the stylistic choices in here to plots generated 308 | from other libraries like Seaborn (perhaps a Matplotlib stylesheet, 309 | or some heavy hacking around with rcparams). 310 | 311 | 3. Tests. (Maybe by comparing function results against a SVG string?) 312 | 313 | 4. More useful ``PlottyFig`` convenience methods. 314 | 315 | 5. A scatterplot matrix (like the one produced by Pandas). 316 | 317 | License 318 | ------- 319 | 320 | MIT. 321 | -------------------------------------------------------------------------------- /boxplot.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 46 | 65 | 91 | 100 | 121 | 153 | 159 | 160 | 180 | 196 | 220 | 241 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 330 | 351 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 464 | 465 | 466 | 469 | 470 | 471 | 474 | 475 | 476 | 479 | 480 | 481 | 484 | 485 | 486 | 487 | 493 | 494 | 495 | 498 | 499 | 500 | 503 | 504 | 505 | 508 | 509 | 510 | 513 | 514 | 515 | 516 | 519 | 520 | 521 | 524 | 525 | 526 | 529 | 530 | 531 | 534 | 535 | 536 | 537 | 538 | 550 | 569 | 610 | 643 | 676 | 712 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | -------------------------------------------------------------------------------- /histogram_fancy.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 36 | 37 | 38 | 44 | 45 | 46 | 52 | 53 | 54 | 60 | 61 | 62 | 68 | 69 | 70 | 76 | 77 | 78 | 84 | 85 | 86 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 116 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 261 | 262 | 273 | 319 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 401 | 402 | 403 | 406 | 407 | 408 | 409 | 410 | 424 | 448 | 499 | 529 | 562 | 641 | 660 | 710 | 746 | 774 | 806 | 827 | 833 | 874 | 882 | 919 | 971 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | -------------------------------------------------------------------------------- /histogram_simple.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 36 | 37 | 38 | 44 | 45 | 46 | 52 | 53 | 54 | 60 | 61 | 62 | 68 | 69 | 70 | 76 | 77 | 78 | 84 | 85 | 86 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 116 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 261 | 262 | 273 | 319 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 433 | 434 | 435 | 438 | 439 | 440 | 441 | 442 | 456 | 480 | 531 | 561 | 594 | 673 | 692 | 742 | 778 | 806 | 838 | 859 | 865 | 906 | 914 | 951 | 1003 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | -------------------------------------------------------------------------------- /scatterplot.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 216 | 217 | 218 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 459 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 521 | 542 | 572 | 605 | 626 | 662 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 798 | 804 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 882 | 883 | 891 | 941 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | 1095 | 1096 | 1097 | 1098 | 1190 | 1191 | 1192 | 1195 | 1196 | 1197 | 1200 | 1201 | 1202 | 1203 | 1204 | 1221 | 1272 | 1273 | 1274 | 1275 | 1276 | 1277 | 1278 | 1279 | 1280 | 1281 | 1282 | 1283 | 1284 | 1285 | 1286 | 1287 | 1288 | 1289 | 1290 | 1291 | 1292 | 1293 | 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | 1300 | 1301 | 1302 | 1303 | 1304 | 1305 | 1306 | 1307 | 1308 | 1309 | -------------------------------------------------------------------------------- /timeseries.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 59 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 441 | 442 | 443 | 584 | 585 | 586 | 589 | 590 | 591 | 594 | 595 | 596 | 597 | 598 | 623 | 644 | 685 | 721 | 754 | 760 | 793 | 813 | 843 | 844 | 894 | 927 | 971 | 992 | 1016 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | 1095 | 1096 | 1097 | 1108 | 1109 | 1110 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1139 | 1158 | 1182 | 1212 | 1238 | 1244 | 1265 | 1281 | 1301 | 1302 | 1303 | 1304 | 1305 | 1306 | 1307 | 1308 | 1309 | 1310 | 1311 | 1312 | 1313 | 1314 | 1315 | 1316 | 1317 | 1318 | 1321 | 1322 | 1323 | 1324 | 1325 | 1326 | 1357 | 1373 | 1382 | 1393 | 1414 | 1415 | 1430 | 1443 | 1468 | 1469 | 1470 | 1471 | 1472 | 1473 | 1474 | 1475 | 1476 | 1477 | 1478 | 1479 | 1480 | 1481 | 1482 | 1483 | 1484 | 1485 | 1486 | 1487 | 1488 | 1489 | 1490 | 1491 | 1492 | 1493 | 1494 | 1495 | 1496 | 1497 | 1498 | 1499 | --------------------------------------------------------------------------------