Replot

This is some basic Jupyter notebook to show you the features of replot. It gives you usage examples, and is used by me as a visual test suite to check I did not break anything between updates.

For detailed documentations, please refer to the module documentation.

Let's go!

First import the required modules. Note that importing replot will not have any side effect and that if you previously imported matplotlib it will be left untouched.


In [1]:
import replot

%matplotlib notebook

In [2]:
# Also import numpy as it will be useful…
import numpy as np

# and add some black magic for easy reloading of the module before executing any cell (just here to ease testing)
%load_ext autoreload
%autoreload 2

# ignore matplotlib warnings about too many figures in the notebook
import matplotlib as mpl
mpl.rcParams["figure.max_open_warning"] = 50

Basic plotting

Let's start by doing some basic plotting.


In [3]:
# Let's plot a basic data series, as we would do with matplotlib
with replot.Figure() as figure:
    x = range(10)
    figure.plot(x)



In [4]:
# Or a (X, Y) point series, as we would do with matplotlib
with replot.Figure() as figure:
    x = range(10)
    y = [i**2 for i in x]
    figure.plot(x, y)



In [5]:
# Plotting a discrete (X, Y) point series
with replot.Figure() as figure:
    x = range(10)
    y = [i**2 for i in x]
    figure.plot(x, y, line=False)
    
# or equivalently plotting a discrete (X, Y) point series, as we would do with matplotlib
with replot.Figure() as figure:
    x = range(10)
    y = [i**2 for i in x]
    figure.plot(x, y, "x")



In [6]:
# Plotting broken lines
with replot.Figure() as figure:
    x = [1, 2, 3, 2, 1]
    y = [1, 1, 2, 2, 1]
    figure.plot(x=x, y=y)



In [7]:
# You can use "x" and "y" keywords if you wish, to specify data
with replot.Figure() as figure:
    x = range(10)
    y = [i**2 for i in x]
    figure.plot(x=x, y=y, line=False)



In [8]:
# But we can also plot a function, by automatically
# evaluating it on the given interval
with replot.Figure() as figure:
    figure.plot(np.sin, (-2, 2))  # Plot sinus on [-2, 2]



In [9]:
# We can also do the same forcing replot to use some evaluation points
with replot.Figure() as figure:
    x = np.linspace(-np.pi, np.pi, 200)
    figure.plot(np.sin, x)



In [10]:
# And we can plot multiples graphs on the same figure
with replot.Figure() as figure:
    figure.plot(range(5))
    for i in range(8):
        figure.plot(lambda x: np.sin(x + np.pi * i / 4), (-10, 10))


Advanced plotting

We can do more elaborated stuff easily with replot.


In [21]:
# Plot with a label on the axis, and a title for the figure
# Note how the legend will be automatically added when a "label" is found!
with replot.Figure() as figure:
    x = range(10)
    figure.plot(x, x, label="x")
    figure.xlabel = "some x label"
    figure.ylabel = "some y label"
    figure.title = "A title for the figure"



In [12]:
# We can also pass these options directly to the constructor
# Here, we force the legend to be at the best location
with replot.Figure(xlabel="some x label",
                   ylabel="some y label",
                   title="A title for the figure",
                   legend="best") as figure:
    figure.plot(np.sin, (-10, 10), label="sin")
    
# But we could also not constraint it (best location will be choosen)
with replot.Figure(xlabel="some x label",
                   ylabel="some y label",
                   title="A title for the figure") as figure:
    figure.plot(np.sin, (-10, 10), label="sin")
    
# Or just say we want a legend (same as not constraining it)
with replot.Figure(xlabel="some x label",
                   ylabel="some y label",
                   title="A title for the figure",
                   legend=True) as figure:
    figure.plot(np.sin, (-10, 10), label="sin")

# Or force it to be in the lower right corner
with replot.Figure(xlabel="some x label",
                   ylabel="some y label",
                   title="A title for the figure",
                   legend="lower right") as figure:
    figure.plot(np.sin, (-10, 10), label="sin")
    
# Or explicitly disable the legend, even if labels are found
with replot.Figure(xlabel="some x label",
                   ylabel="some y label",
                   title="A title for the figure",
                   legend=False) as figure:
    figure.plot(np.sin, (-10, 10), label="sin")



In [13]:
# We can also force the range of the axis
with replot.Figure(xlabel="some x label",
                   ylabel="some y label",
                   title="A title for the figure",
                   legend=False,
                   xrange=(-20, 10),
                   yrange=(-3.0, 3.0)) as figure:
    figure.plot(np.sin, (-10, 10), label="sin")
    
# Or equivalently
with replot.Figure(xlabel="some x label",
                   ylabel="some y label",
                   title="A title for the figure",
                   legend=False) as figure:
    figure.xrange = (-20, 10)
    figure.yrange = (-3.0, 3.0)
    figure.plot(np.sin, (-10, 10), label="sin")



In [14]:
# Passing extra arguments to matplotlib plot command is as easy as
# passing them to replot plot command.
with replot.Figure(xlabel="some x label",
                   ylabel="some y label",
                   title="A title for the figure",
                   legend=True) as figure:
    figure.plot(np.sin, (-10, 10), linewidth=20)



In [19]:
import seaborn.apionly as sns
# You can also tweak the palette used, either with a seaborn palette
with replot.Figure(palette=sns.color_palette("dark", 10)) as figure:
    figure.plot(np.sin, (-10, 10))

# or by passing it a list of colors as RGB tuples
palette = list(sns.color_palette("husl", 2))
import pprint
pprint.pprint(palette)
with replot.Figure(palette=palette) as figure:
    figure.plot(np.sin, (-10, 10))
    
# or by passing it a callable taking number of subplots as argument
with replot.Figure(palette=lambda n: sns.color_palette("dark", n)) as figure:
    figure.plot(np.sin, (-10, 10))
    
# or using one of the predefined palettes: colorbrewerq10 (default one), colorbrewerq9 and tableau10
with replot.Figure(palette="tableau10") as figure:
    figure.plot(np.sin, (-10, 10))
    figure.plot(np.cos, (-10, 10))


[(0.9677975592919913, 0.44127456009157356, 0.5358103155058701),
 (0.21044753832183283, 0.6773105080456748, 0.6433941168468681)]

In [20]:
# It is not mandatory at all to use a with statement
fig = replot.Figure(xlabel="some x label",
                    ylabel="some y label",
                    title="A title for the figure",
                    legend="best")
fig.plot(np.sin, (-10, 10), label="sin")
fig.show()  # But in this case, we must show the figure



In [21]:
# NOTE: Passing tuples to the plot function uses
# the tuples as (x, y) point series, which is not the standard matplotlib
# behavior.
with replot.Figure() as figure:
    x = range(10)
    y = [i**2 for i in x]
    figure.plot(zip(x, y))



In [22]:
# To plot in log scale, you can use the Figure.logplot() method
with replot.Figure() as figure:
    figure.logplot(np.log, (-1, 1))



In [23]:
# Same for log-log scale, you can use the Figure.loglogplot() method
with replot.Figure() as figure:
    figure.loglogplot(lambda x: x**2, (0, 1))



In [24]:
# To force an orthonormal frame, use orthonormal=True on the plot
with replot.Figure() as figure:
    figure.plot(np.sin, (-1, 1), orthonormal=True)



In [25]:
# To force the limits of the axis, use xlim and ylim
with replot.Figure() as figure:
    figure.plot(np.sin, (-1, 1), xlim=(-2, 2), ylim=(-3, 3))



In [26]:
# You can invert X and Y components easily
# Note that this will invert axes labels as well
with replot.Figure() as figure:
    figure.xlabel = "ylabel"
    figure.ylabel = "xlabel"
    figure.plot(lambda x: x**2, (0, 10), invert=True)  # Note that we plot x^2, not sqrt(x), but invert axis



In [27]:
# You can also rotate X and Y components easily
# Note that this will not affect the axes labels  
with replot.Figure() as figure:
    x = range(10)
    figure.xlabel = "xlabel"
    figure.ylabel = "ylabel"
    figure.plot(x, x, rotate=90)



In [29]:
# You can plot multiple times the same figure
with replot.Figure() as fig:
    fig.plot(range(10))
    fig.show()  # Show the figure with only the plot above
    fig.plot(range(10), [-i for i in range(10)])  # Add an extra plot to the figure
    # Figure is shown again when going out of scope, with two subplots this time


One-liner plotting

You can also make plot with a one-liner.


In [30]:
# Many plots done with a single one-liner
replot.plot([range(10), (np.sin, (-5, 5)), (lambda x: np.sin(x) + 4, (-10, 10), {"linewidth": 10}), (lambda x: np.sin(x) - 4, (-10, 10), {"linewidth": 10}), ([-i for i in range(5)], {"linewidth": 10})],
            xlabel="some x label",
            ylabel="some y label",
            title="A title for the figure",
            legend="best")



In [31]:
# Another one-liner plot example
replot.plot([range(10), (np.sin, (-5, 5)), (lambda x: np.sin(x) + 4, (-10, 10), {"linewidth": 10}), (lambda x: np.sin(x) - 4, (-10, 10), {"linewidth": 10}), ([-i for i in range(5)], {"linewidth": 10})],
            xlabel="some x label",
            ylabel="some y label",
            title="A title for the figure",
            legend="best",
            palette=sns.color_palette("dark"))


Using subplots

Subplots are defined by group. You can declare a group and add figure to it using the group keyword in plot commands, as demonstrated below.

Note: Groups are represented by one unicode character. "_" is the default group in which go all the plots which are not mapped onto a group. Hence, it is a reserved group symbol which cannot be used.


In [32]:
# Using groups to define subplots
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10), group="a")
    figure.plot(np.sin, (-10, 10), group="ç")



In [33]:
# Applying a grid on a figure, one empty subplot
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10), group="a")
    figure.set_grid(["ab"])



In [34]:
# Applying a grid on a figure, one empty subplot
# Note that if there is a single row, enclosing in a list is not mandatory
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10), group="a")
    figure.set_grid("ab")



In [35]:
# Applying a grid on a figure, default group is masked
# Note that if we do not put the default group ("_") in the grid,
# it will not be shown
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10))
    figure.set_grid(["a"])



In [36]:
# Using set_grid, you can define very easily (and visually) a quite complex grid layout
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10), group="a")
    figure.plot(np.cos, (-10, 10), group="b")
    figure.plot(np.cos, (-10, 10), group="c")
    figure.plot(np.cos, (-10, 10), group="d")
    figure.plot(np.cos, (-10, 10), group="e")
    figure.plot(np.sin, (-10, 10), group="e")
    figure.set_grid(["aaa",
                     "bbc",
                     "dec"])



In [37]:
# By setting the grid to False, you can ignore the groups you defined
# and plot everything in the same subplot.
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10), group="a")
    figure.plot(np.sin, (-10, 10), group="ç")
    figure.set_grid(False)



In [38]:
# Forcing a grid layout
# Use auto={"ignore_groups": True} to put every plot in
# a different subplot, regardless of their group.
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10))
    figure.plot(np.cos, (-10, 10))
    figure.plot(np.cos, (-10, 10))
    figure.set_grid(ignore_groups=True)



In [39]:
# Auto gridifying example
# Use ignore_groups=True to put every plot in a different subplot,
# without having to deal with groups.
# Note that ignore_groups=True will discard the groups you may have defined.
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10), group="a")
    figure.plot(np.cos, (-10, 10), group="b")
    figure.plot(np.cos, (-10, 10), group="c")
    figure.set_grid(ignore_groups=True)



In [40]:
# Gridify example
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10), group="a")
    figure.plot(np.cos, (-10, 10), group="b")
    figure.plot(np.cos, (-10, 10))
    figure.plot(np.sin, (-10, 10))



In [41]:
# Gridify example, forced height
# If the default gridify layout is not fitting well, you can force the height
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10), group="a")
    figure.plot(np.cos, (-10, 10), group="b")
    figure.set_grid(height=2)
    
# Gridify example, forced width
# … or the width
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10), group="a")
    figure.plot(np.cos, (-10, 10), group="b")
    figure.set_grid(width=2)



In [42]:
# You can also specify a grid directly in the constructor
with replot.Figure(
    grid={
        "width": 2, 
        "height": 1, 
        "grid": [
            ((0, 0), "a", (1, 1)),
            ((0, 1), "b", (1, 1))
        ]}) as figure:
    figure.plot(np.cos, (-10, 10), group="a")
    figure.plot(np.cos, (-10, 10), group="b")



In [43]:
# You can also specify a grid directly in the constructor
# Setting the grid to False ignores the groups you may have defined.
with replot.Figure(
    grid=False) as figure:
    figure.plot(np.cos, (-10, 10), group="a")
    figure.plot(np.sin, (-10, 10), group="b")



In [44]:
# Note that if we use legend, xlabel or ylabel with subplots,
# they will be set identically on every subplot
with replot.Figure(xlabel="some x label", ylabel="some y label") as figure:
    figure.plot(np.cos, (-10, 10), group="a", label="cos")
    figure.plot(np.sin, (-10, 10), group="ç", label="sin")
    figure.set_grid(["aç"])



In [45]:
# You can avoid it by passing dict for these arguments
# they will be set identically on every subplot
with replot.Figure(xlabel={"a": "some x label", "ç": ""},
                   ylabel={"a": "", "ç": "some y label"},
                   legend={"a": False}) as figure:
    figure.plot(np.cos, (-10, 10), group="a", label="cos")
    figure.plot(np.sin, (-10, 10), group="ç", label="sin")
    figure.set_grid(["aç"])


Saving figures


In [46]:
# Save a figure to a file
with replot.Figure(savepath="/tmp/out.png") as figure:
    figure.plot(np.cos, (-10, 10))

In [47]:
# or equivalently
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10))
    figure.savepath = "/tmp/out.png"

Animations


In [49]:
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10))
    figure.animate()


Hacking with matplotlib


In [50]:
# You can set the figure and axis attributes used by replot, to call extra methods and pass
# specific parameters to them, that replot would not expose.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_xlim((-20, 20))

with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10))
    figure.figure = fig
    figure.axes = {"_": ax}


Some errors you might encounter


In [51]:
# Invalid interval for plotting a function
with replot.Figure() as figure:
    figure.plot(np.sin, None)


---------------------------------------------------------------------------
InvalidParameterError                     Traceback (most recent call last)
<ipython-input-51-810be42c9f1a> in <module>()
      1 # Invalid interval for plotting a function
      2 with replot.Figure() as figure:
----> 3     figure.plot(np.sin, None)

/home/phyks/Code/replot/replot/figure.py in plot(self, *args, **kwargs)
    317         if hasattr(args[0], "__call__"):
    318             # We want to plot a function
--> 319             plot_ = plot_helpers.plot_function(args[0], *(args[1:]), **kwargs)
    320         else:
    321             # Else, it is a point series, and we just have to store it for

/home/phyks/Code/replot/replot/helpers/plot.py in plot_function(data, *args, **kwargs)
     40         raise exc.InvalidParameterError(
     41             "Second parameter in plot command should be a tuple " +
---> 42             "specifying plotting interval.")
     43     return ((x_values, y_values) + args[1:], kwargs)

InvalidParameterError: Second parameter in plot command should be a tuple specifying plotting interval.

In [52]:
# Invalid plot call, no arguments given
with replot.Figure() as figure:
    figure.plot()


---------------------------------------------------------------------------
InvalidParameterError                     Traceback (most recent call last)
<ipython-input-52-bb8eaf706fb0> in <module>()
      1 # Invalid plot call, no arguments given
      2 with replot.Figure() as figure:
----> 3     figure.plot()

/home/phyks/Code/replot/replot/figure.py in plot(self, *args, **kwargs)
    309             else:
    310                 raise exc.InvalidParameterError(
--> 311                     "You should pass at least one argument to this function.")
    312 
    313         # Extract custom kwargs (the ones from replot but not matplotlib) from

InvalidParameterError: You should pass at least one argument to this function.

In [53]:
# Invalid group argument, groups are one unicode character long
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10), group="abc")


---------------------------------------------------------------------------
InvalidParameterError                     Traceback (most recent call last)
<ipython-input-53-8b04957bf3f0> in <module>()
      1 # Invalid group argument, groups are one unicode character long
      2 with replot.Figure() as figure:
----> 3     figure.plot(np.cos, (-10, 10), group="abc")

/home/phyks/Code/replot/replot/figure.py in plot(self, *args, **kwargs)
    313         # Extract custom kwargs (the ones from replot but not matplotlib) from
    314         # kwargs
--> 315         kwargs, custom_kwargs = custom_kwargs_parser.parse(kwargs)
    316 
    317         if hasattr(args[0], "__call__"):

/home/phyks/Code/replot/replot/helpers/custom_kwargs.py in parse(kwargs)
     26         if len(kwargs["group"]) > 1:
     27             raise exc.InvalidParameterError(
---> 28                 "Group name cannot be longer than one unicode character.")
     29         elif kwargs["group"] == constants.DEFAULT_GROUP:
     30             raise exc.InvalidParameterError(

InvalidParameterError: Group name cannot be longer than one unicode character.

In [54]:
# Invalid grid, no grid provided
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10), group="a")
    figure.apply_grid([])


---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-54-c89b5aaa14ef> in <module>()
      2 with replot.Figure() as figure:
      3     figure.plot(np.cos, (-10, 10), group="a")
----> 4     figure.apply_grid([])

AttributeError: 'Figure' object has no attribute 'apply_grid'

In [55]:
# Invalid grid, not a rectangular one
with replot.Figure() as figure:
    figure.plot(np.cos, (-10, 10), group="a")
    figure.apply_grid(["a",
                       "ba"])


---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-55-c6ca6527d69a> in <module>()
      2 with replot.Figure() as figure:
      3     figure.plot(np.cos, (-10, 10), group="a")
----> 4     figure.apply_grid(["a",
      5                        "ba"])

AttributeError: 'Figure' object has no attribute 'apply_grid'