Skip to content

Commit

Permalink
More plotter tests (#12)
Browse files Browse the repository at this point in the history
Added additional tests to increase coverage. Simplified some interfaces and updated documentation accordingly.
  • Loading branch information
jemrobinson committed Jul 2, 2018
1 parent efd6901 commit 2a1721d
Show file tree
Hide file tree
Showing 34 changed files with 881 additions and 170 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ script:
fi
# Static analysis
- pyflakes mATLASplotlib
# Check PEP8 compliance
- pycodestyle --statistics --ignore=E501 --count mATLASplotlib
# Run tests using coveralls output
- py.test --cov=mATLASplotlib --cov-report term-missing
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ For example, something like
with mATLASplotlib.canvases.Simple(shape="landscape") as canvas:
x, y = [0, 1, 2, 3], [0, 1, 4, 9]
canvas.plot_dataset(x, y, style="scatter", label="Example points", colour="black")
canvas.save_to_file("simple_example")
canvas.save("simple_example")

will produce a minimal scatter plot with automatically determined axis limits and save this to a PDF (if not otherwise specified).

Expand Down
4 changes: 2 additions & 2 deletions docs/source/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ And the file is saved

.. code:: python
canvas.save_to_file("example_fig_01")
canvas.save("example_fig_01")
.. image:: images/example_fig_01_official.png
:width: 49%
Expand Down Expand Up @@ -172,7 +172,7 @@ Finally save it

.. code:: python
canvas.save_to_file("example_fig_02", extension="png")
canvas.save("example_fig_02", extension="png")
.. image:: images/example_fig_02_official.png
:width: 49%
Expand Down
2 changes: 1 addition & 1 deletion docs/source/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Saving the output to a file is very simple.

.. code:: python
canvas.save_to_file("simple_example")
canvas.save("simple_example")
This function takes an optional ``extension`` argument which sets the file extension of the output file.
Running this code will produce a minimal scatter plot with automatically determined axis limits and save this to a PDF (if not otherwise specified).
Expand Down
2 changes: 1 addition & 1 deletion examples/example_fig_01.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@
canvas.set_axis_ticks("x", [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5])

# Finally save to a file (.pdf will be used by default)
canvas.save_to_file("example_fig_01", extension=["png", "pdf"])
canvas.save("example_fig_01", extension=["png", "pdf"])
2 changes: 1 addition & 1 deletion examples/example_fig_02.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@
canvas.set_axis_ticks("y", [1e-3, 1e-2, 1e-1, 1, 10, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7])

# Finally save to a file (.pdf will be used by default)
canvas.save_to_file("example_fig_02", extension="png")
canvas.save("example_fig_02", extension="png")
4 changes: 2 additions & 2 deletions mATLASplotlib/canvases/base_canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def add_text(self, x, y, text, **kwargs):
ha, va = self.location_map[anchor_to]
draw_text(text, x, y, self.subplots[axes], ha=ha, va=va, **kwargs)

def save_to_file(self, output_name, extension="pdf"):
def save(self, output_name, extension="pdf"):
"""Save the current state of the canvas to a file.
:param output_name: name of output file.
Expand All @@ -189,7 +189,7 @@ def save_to_file(self, output_name, extension="pdf"):
if isinstance(extension, str):
extension = [extension]
for output in extension:
matplotlib.pyplot.savefig("{0}.{1}".format(output_name, output)) # , dpi=1000)
matplotlib.pyplot.savefig("{0}.{1}".format(output_name, output))
logger.info("Saved figure to: {0}.{1}".format(output_name, output))

def close(self):
Expand Down
7 changes: 5 additions & 2 deletions mATLASplotlib/canvases/ratio.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ def __init__(self, shape="square", line_ypos=1.0, **kwargs):
self.line_ypos = line_ypos
self.main_subplot = "top"
self.axis_ranges["y_ratio"] = [0.5, 1.5]
self.ratio_tick_sizes = [0.001, 0.002, 0.0025, 0.005, 0.01, 0.02, 0.025, 0.04, 0.05, 0.1, 0.2, 0.25, 0.4, 0.5, 1.0, 2.0]
self.auto_ratio_tick_intervals = [0.001, 0.002, 0.0025, 0.004, 0.005,
0.01, 0.02, 0.025, 0.04, 0.05,
0.1, 0.2, 0.25, 0.4, 0.5,
1.0, 2.0, 2.5, 4.0, 5.0]
self.use_auto_ratio_ticks = True

def plot_dataset(self, *args, **kwargs):
Expand Down Expand Up @@ -154,7 +157,7 @@ def __get_auto_ratio_ticks(self, n_approximate=4):
"""
# Underestimate the interval size since we might be removing the highest tick
interval = 0.99 * abs(self.axis_ranges["y_ratio"][1] - self.axis_ranges["y_ratio"][0])
tick_size = min(self.ratio_tick_sizes, key=lambda x: abs((interval / x) - n_approximate))
tick_size = min(self.auto_ratio_tick_intervals, key=lambda x: abs((interval / x) - n_approximate))
tick_list = arange(1.0 - 10 * tick_size, 1.0 + 10 * tick_size, tick_size)
# Remove topmost tick if it would be at the top of the axis
tick_list = [t for t in tick_list if not allclose(t, self.axis_ranges["y_ratio"][1])]
Expand Down
8 changes: 8 additions & 0 deletions mATLASplotlib/canvases/simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ def __init__(self, shape="square", **kwargs):
self.subplots["main"] = self.figure.add_axes(self.shape_dict["dimensions"])
self.main_subplot = "main"

def plot_dataset(self, *args, **kwargs):
axes = kwargs.get("axes", self.main_subplot)
super(Simple, self).plot_dataset(*args, **kwargs)
if "x" not in self.axis_ranges:
self.set_axis_range("x", self.subplots[axes].get_xlim())
if "y" not in self.axis_ranges:
self.set_axis_range("y", self.subplots[axes].get_ylim())

def _apply_axis_limits(self):
if "x" in self.axis_ranges:
self.subplots["main"].set_xlim(self.axis_ranges["x"])
Expand Down
19 changes: 10 additions & 9 deletions mATLASplotlib/converters/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def construct_2D_bin_list(self, axes="xy"):
:raises ValueError: unsupported axes argument
"""
if axes == "xy":
bin_centres = np.meshgrid(self.x_points, self.y_points, indexing="xy")
bin_centres = np.meshgrid(getattr(self, "x_points"), getattr(self, "y_points"), indexing="xy")
else:
raise ValueError("Attempted to construct 2D bin list for {0} axes. Only 'xy' is currently supported.".format(axes))
return [bin_centre.ravel() for bin_centre in bin_centres]
Expand Down Expand Up @@ -187,7 +187,8 @@ def __get_all_bin_edges(self, dimension):
"""Return array of all x/y/z bin edges, constructing if necessary."""
attr_name = "_{0}_all_bin_edges".format(dimension)
if not hasattr(self, attr_name):
value = np.array(sum([[low_edge, high_edge] for low_edge, high_edge in zip(self.__get_bin_low_edges(dimension), self.__get_bin_high_edges(dimension))], []))
low_edges, high_edges = self.__get_bin_low_edges(dimension), self.__get_bin_high_edges(dimension)
value = np.array(sum([[l, h] for l, h in zip(low_edges, high_edges)], []))
setattr(self, attr_name, value)
return getattr(self, attr_name)

Expand Down Expand Up @@ -226,29 +227,29 @@ def __get_bin_high_edges(self, dimension):
def __get_x_at_y_bin_edges(self):
"""Return array of x at the bin edges of y bins, constructing if necessary."""
if not hasattr(self, "_x_at_y_bin_edges"):
setattr(self, "_x_at_y_bin_edges", np.array(sum([[x_point, x_point] for x_point in self.x_points], [])))
return self._x_at_y_bin_edges
setattr(self, "_x_at_y_bin_edges", np.array(sum([[x_point, x_point] for x_point in getattr(self, "x_points")], [])))
return getattr(self, "_x_at_y_bin_edges")

def __get_y_at_x_bin_edges(self):
"""Return array of y at the bin edges of x bins, constructing if necessary."""
if not hasattr(self, "_y_at_x_bin_edges"):
setattr(self, "_y_at_x_bin_edges", np.array(sum([[y_point, y_point] for y_point in self.y_points], [])))
return self._y_at_x_bin_edges
setattr(self, "_y_at_x_bin_edges", np.array(sum([[y_point, y_point] for y_point in getattr(self, "y_points")], [])))
return getattr(self, "_y_at_x_bin_edges")

def __get_band_edges_x(self):
"""Return array of x edges for fillable band, constructing if necessary."""
if not hasattr(self, "_band_edges_x"):
setattr(self, "_band_edges_x", np.array(sum([[point[0] - point[1], point[0] + point[2]] for point in self._data["x"]], [])))
return self._band_edges_x
return getattr(self, "_band_edges_x")

def __get_band_edges_y_low(self):
"""Return array of y minima for fillable band, constructing if necessary."""
if not hasattr(self, "_band_edges_y_low"):
setattr(self, "_band_edges_y_low", np.array(sum([[point[0] - point[1], point[0] - point[1]] for point in self._data["y"]], [])))
return self._band_edges_y_low
return getattr(self, "_band_edges_y_low")

def __get_band_edges_y_high(self):
"""Return array of y maxima for fillable band, constructing if necessary."""
if not hasattr(self, "_band_edges_y_high"):
setattr(self, "_band_edges_y_high", np.array(sum([[point[0] + point[2], point[0] + point[2]] for point in self._data["y"]], [])))
return self._band_edges_y_high
return getattr(self, "_band_edges_y_high")
11 changes: 6 additions & 5 deletions mATLASplotlib/decorations/legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ def plot(self, x, y, axes, anchor_to, fontsize):
"""
transform = axes.transAxes
handles, labels = self.__get_legend_handles_labels(axes)
_legend = axes.legend(handles, labels, numpoints=1, loc=anchor_to, bbox_to_anchor=(x, y), bbox_transform=transform, borderpad=0, borderaxespad=0, columnspacing=0)
_legend = axes.legend(handles, labels, numpoints=1, loc=anchor_to, bbox_to_anchor=(x, y),
bbox_transform=transform, borderpad=0, borderaxespad=0, columnspacing=0)
_legend.get_frame().set_linewidth(0)
_legend.get_frame().set_alpha(0.0)
fontsize = self.default_fontsize if fontsize is None else fontsize
Expand All @@ -69,13 +70,13 @@ def __get_legend_handles_labels(self, axes):
if label not in seen:
seen.add(label)
labels.append(label)
if isinstance(handle, matplotlib.patches.Polygon):
proxy_artist = matplotlib.pyplot.Line2D([0], [0], color=handle.properties()["edgecolor"], linestyle=handle.properties()["linestyle"])
handles.append(proxy_artist)
elif isinstance(handle, matplotlib.patches.Ellipse):
if isinstance(handle, matplotlib.patches.Ellipse):
line = matplotlib.pyplot.Line2D([0], [0], color=handle.properties()["edgecolor"], linestyle=handle.properties()["linestyle"])
rectangle = matplotlib.pyplot.Rectangle((0, 0), 0, 0, facecolor=handle.properties()["facecolor"])
handles.append((rectangle, line))
# elif isinstance(handle, matplotlib.patches.Polygon):
# proxy_artist = matplotlib.pyplot.Line2D([0], [0], color=handle.properties()["edgecolor"], linestyle=handle.properties()["linestyle"])
# handles.append(proxy_artist)
else:
handles.append(handle)
# Pre-sort legend order for stacks, which need reversing
Expand Down
11 changes: 7 additions & 4 deletions mATLASplotlib/plotters/bar_chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,19 @@ def add_to_axes(self, axes, dataset, **kwargs):
:Keyword Arguments:
* **colour** (*str*) -- which face colour to use
* **edgewidth** (*float*) -- how large an outline width to use
* **edgecolour** (*float*) -- which colour to use for the outline
* **edgewidth** (*float*) -- how large an outline width to use
* **label** (*str*) -- label to use when this appears in a legend
"""
logger.debug("Adding dataset to axes as bar")
# Interpret arguments
# Construct plotting argument dictionary
self.plot_args["color"] = kwargs.pop("colour", "black") # Default colour: black
linewidth = kwargs.pop("edgewidth", 4) # Default linewidth: 4

# Extract other known arguments from kwargs
edgecolour = kwargs.pop("edgecolour", None) # Default edgecolour: None
linewidth = kwargs.pop("edgewidth", 4) # Default linewidth: 4
label = kwargs.pop("label", None) # Default label: None

# Add any other user-provided arguments
self.plot_args.update(kwargs)

Expand All @@ -37,7 +40,7 @@ def add_to_axes(self, axes, dataset, **kwargs):
axes.bar(dataset.x_points, height=dataset.y_points, width=dataset.x_bin_widths, color=None, edgecolor=edgecolour, linewidth=linewidth)

# Draw main bar - expand the widths slightly to fill in zero-width gaps
axes.bar(dataset.x_points, height=dataset.y_points, width=[1.005 * x for x in dataset.x_bin_widths], edgecolor=None, **self.plot_args)
axes.bar(dataset.x_points, height=dataset.y_points, width=[1.004 * x for x in dataset.x_bin_widths], edgecolor=None, **self.plot_args)

# Add a proxy artist with correct edge and facecolours
if edgecolour is None:
Expand Down
45 changes: 31 additions & 14 deletions mATLASplotlib/plotters/binned_band.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ class BinnedBand(BasePlotter):
"""Plot as binned band in the x-y plane.
:Additional plot_style options:
* `central line` -- also draw a line at the bin centre
* `central line` -- also draw a horizontal line at the vertical centre of each bin
* `central line stepped` -- as for `central line` but also join these vertically at the edge of each bin
"""

def add_to_axes(self, axes, dataset, **kwargs):
Expand All @@ -26,33 +27,49 @@ def add_to_axes(self, axes, dataset, **kwargs):
:Keyword Arguments:
* **alpha** (*float*) -- set alpha transparency
* **colour** (*str*) -- which face colour to use
* **background_colour** (*str*) -- which background colour to use
* **hatch** (*str*) -- set hatch pattern
* **line_colour** (*float*) -- which colour to use for the main line and for hatches
* **edgecolour** (*float*) -- which colour to use for the outline
* **hatchcolour** (*str*) -- which hatch colour to use
* **label** (*str*) -- label to use when this appears in a legend
* **linecolour** (*float*) -- which colour to use for the main line and for hatches
* **linewidth** (*str*) -- how wide to draw the line
"""
# Construct plotting arguments
self.plot_args["facecolor"] = kwargs.pop("colour", "black") # Default colour: black
self.plot_args["edgecolor"] = kwargs.pop("background_colour", "white") # Default colour: white
line_colour = kwargs.pop("line_colour", "white") # Default colour: white
self.plot_args["hatch"] = kwargs.pop("hatch", None) # Default hatch: None
self.plot_args["alpha"] = kwargs.pop("alpha", None) # Default alpha: None
self.plot_args["linewidth"] = kwargs.pop("linewidth", 0) # Default linewidth: 2
# Construct plotting argument dictionary
self.plot_args["alpha"] = kwargs.pop("alpha", None) # Default alpha: None
self.plot_args["facecolor"] = kwargs.pop("colour", "black") # Default colour: black
self.plot_args["hatch"] = kwargs.pop("hatch", None) # Default hatch: None

# Extract other known arguments from kwargs
hatch_colour = kwargs.pop("hatchcolour", "white") # Default colour: white
line_colour = kwargs.pop("linecolour", "white") # Default colour: white
line_style = kwargs.pop("linestyle", None) # Default style: None
line_width = kwargs.pop("linewidth", 2) # Default linewidth: 2
plot_label = kwargs.pop("label", None) # Default label: None

# Add any other user-provided arguments
plot_label = kwargs.pop("label", None) # Default label: None
self.plot_args.update(kwargs)

# Plot the central line
if "central line" in self.plot_style:
axes.errorbar(dataset.x_points, dataset.y_points, fmt="", markeredgewidth=0, linestyle="None", color=line_colour, xerr=np.transpose(dataset.x_error_pairs))
if "central line stepped" in self.plot_style:
axes.plot(dataset.x_all_bin_edges, dataset.y_at_x_bin_edges, drawstyle="steps-pre", color=line_colour, linestyle=line_style, linewidth=line_width)
else:
_, _, barlinecols = axes.errorbar(dataset.x_points, dataset.y_points, xerr=np.transpose(dataset.x_error_pairs),
fmt="", markeredgewidth=0, linestyle="None", color=line_colour, linewidth=line_width)
if line_style is not None:
barlinecols[0].set_linestyle(line_style)

# Add the hatch colour if requested, this also adds an outline
if self.plot_args["hatch"] is not None:
self.plot_args["edgecolor"] = hatch_colour

# Plot the band
if plot_label is None:
axes.fill_between(dataset.band_edges_x, dataset.band_edges_y_low, dataset.band_edges_y_high, **self.plot_args)
else:
axes.fill_between(dataset.band_edges_x, dataset.band_edges_y_low, dataset.band_edges_y_high, **self.plot_args)

if "central line" in self.plot_style:
proxy_artist = Ellipse((0, 0), 0, 0, axes=axes, label=plot_label, facecolor=self.plot_args["facecolor"], edgecolor=line_colour)
proxy_artist = Ellipse((0, 0), 0, 0, axes=axes, label=plot_label, linestyle=line_style, facecolor=self.plot_args["facecolor"], edgecolor=line_colour)
axes.add_patch(proxy_artist)
else:
proxy_artist = Rectangle((0, 0), 0, 0, axes=axes, label=plot_label, **self.plot_args)
Expand Down
13 changes: 10 additions & 3 deletions mATLASplotlib/plotters/coloured_2D.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,22 @@ def add_to_axes(self, axes, dataset, **kwargs):
:Keyword Arguments:
* **colour_map** (*str*) -- which colour map to use
* **with_key** (*bool*) -- draw the key (True by default)
"""
# Construct plotting arguments
# Construct plotting argument dictionary
self.plot_args["cmap"] = getattr(pyplot.cm, kwargs.pop("colour_map", "Purples")) # Default colour-map: Purples

# Extract other known arguments from kwargs
with_key = kwargs.pop("with_key", True) # Default True

# Add any other user-provided arguments
self.plot_args.update(kwargs)

x_values, y_values = dataset.construct_2D_bin_list(axes="xy")
assert len(x_values) == len(y_values) == len(dataset.z_points)
_, _, _, axes_image = axes.hist2d(x_values, y_values,
bins=[dataset.x_bin_edges, dataset.y_bin_edges],
weights=dataset.z_points, **self.plot_args)
colourbar = axes.get_figure().colorbar(axes_image, ax=axes, **self.plot_args)
colourbar.solids.set_rasterized(True)
if with_key:
colourbar = axes.get_figure().colorbar(axes_image, ax=axes, **self.plot_args)
colourbar.solids.set_rasterized(True)
2 changes: 1 addition & 1 deletion mATLASplotlib/plotters/get_plotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def get_plotter(plot_style):
return BarChart(plot_style)
if "binned band" in plot_style:
return BinnedBand(plot_style)
if "coloured_2D" in plot_style:
if "coloured 2D" in plot_style:
return Coloured2D(plot_style)
if "line" in plot_style:
return Line(plot_style)
Expand Down
Loading

0 comments on commit 2a1721d

Please sign in to comment.