Initial commit

This commit is contained in:
Lucas Verney 2016-03-01 14:51:25 +01:00
commit b3f2b03e8f
4 changed files with 7393 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.ipynb_checkpoints/
__pycache__

7229
Examples.ipynb Normal file

File diff suppressed because one or more lines are too long

53
README.md Normal file
View File

@ -0,0 +1,53 @@
Replot
======
This repo is an attempt for a better API to plot graphs with
[Matplotlib](http://matplotlib.org/) in Python.
## Features
These are the current features. I will extend the module whenever I feel the
need to introduce new functions and methods. Please let me know about any bad
design in the API, or required feature!
<dl>
<dt>Saner default plots</dt>
<dd>Matplotlib plots are quite ugly by default, colors are not really
suited for optimal black and white print, or ease reading for colorblind
people. This module imports and makes use of
[Seaborn](https://github.com/mwaskom/seaborn) for saner default params.</dd>
<dt>Support `with` statement</dt>
<dd>Ever got tired of having to start any figure with a call to
`matplotlib.pyplot.subplots()`? This module abstracts it using `with`
statement. New figures are defined by a `with` statement, and are `show`n
automatically upon leaving the `with` context.
<dt>Plot functions</dt>
<dd>Ever got annoyed by the fact that `matplotlib` can only plot point
series and not evaluate a function _à la_ Mathematica? This module let
you do things like `plot(sin, (-10, 10))` to plot a sine function between
-10 and 10.
<dt>Order of call of methods is no longer important</dt>
<dd>When calling a method from `matplotlib`, it is directly applied to the
figure, and not deferred to the final render call. Then, if calling
`matplotlib.pyplot.legend()` **before** having actually `plot`ted
anything, it will fail. This is not the case with this module, as it
abstracts on top of `matplotlib` and do the actual render only when the
figure is to be `show`n. Even after having called the `show` method, you
can still change everything in your figure!</dd>
</dl>
## Examples
A more up to date doc is still to be written, but you can have a look at the
`Examples.ipynb` [Jupyter](https://github.com/jupyter/notebook/) notebook for
examples.
## License
MIT license.

109
replot.py Normal file
View File

@ -0,0 +1,109 @@
"""
* Saner default config.
* Matplotlib API methods have an immediate effect on the figure. We do not want
it, then we write a buffer on top of matplotlib API.
"""
import matplotlib.pyplot as plt
import numpy as np
import seaborn
plt.rcParams['figure.figsize'] = (10.0, 8.0) # Larger figures by default
plt.rcParams['text.usetex'] = True # Use LaTeX rendering
class Figure():
def __init__(self,
xlabel="", ylabel="", title="", palette="hls",
legend=None):
self.max_colors = 10
self.default_points_number = 1000
self.default_x_interval = np.linspace(-10, 10,
self.default_points_number)
self.xlabel = xlabel
self.ylabel = ylabel
self.title = title
self.palette = palette
# TODO: Legend should be automatic if labelled data is found
self.legend = legend
self.plots = []
def __enter__(self):
return self
def __exit__(self, exception_type, exception_value, traceback):
self.show()
def show(self):
"""
"""
seaborn.set()
with seaborn.color_palette(self.palette, self.max_colors):
# Create figure
figure, axes = plt.subplots()
# Add plots
for plot in self.plots:
axes.plot(*(plot[0]), **(plot[1]))
# Set properties
axes.set_xlabel(self.xlabel)
axes.set_ylabel(self.ylabel)
axes.set_title(self.title)
if self.legend is not None:
self._legend(axes, location=self.legend)
# Draw figure
figure.show()
seaborn.reset_orig()
#def palette(self, palette):
# """
# """
# if isinstance(palette, str):
# self.current_palette = palette
# with seaborn.color_palette(self.current_palette, self.max_colors):
# # TODO
# pass
def plot(self, data, *args, **kwargs):
"""
Plot something on the figure.
>>> plot(np.sin)
>>> plot(np.sin, (-1, 1))
>>> plot(np.sin, [-1, -0.9, , 1])
>>> plot([1, 2, 3], [4, 5, 6])
"""
if hasattr(data, "__call__"):
self._plot_function(data, *args, **kwargs)
else:
self.plots.append(((data,) + args, kwargs))
def _plot_function(self, data, *args, **kwargs):
"""
"""
# TODO: Better default interval and so on
if len(args) == 0:
# No interval specified, using default one
x_values = self.default_x_interval
elif isinstance(args[0], (list, np.ndarray)):
x_values = args[0]
elif isinstance(args[0], tuple):
x_values = np.linspace(args[0][0], args[0][1],
self.default_points_number)
else:
# TODO: Error
assert False
y_values = [data(i) for i in x_values]
self.plots.append(((x_values, y_values) + args[1:], kwargs))
def _legend(self, axes, location="best"):
"""
"""
# If there should be a legend, but no location provided, put it at best
# location
if location is True:
location = "best"
location.replace("top ", "upper ")
location.replace("bottom ", "lower ")
axes.legend(loc=location)