This commit adds padding around the graph, depending on the used
linewidth, to close issue https://github.com/Phyks/replot/issues/2.
This commit is contained in:
Lucas Verney 2016-03-30 23:50:36 +02:00
parent 623746d5ea
commit 533462655a
3 changed files with 136 additions and 17 deletions

File diff suppressed because one or more lines are too long

View File

@ -536,10 +536,46 @@ class Figure():
self.legend, self.legend,
lambda: self._legend(axis, overload_legend=True) lambda: self._legend(axis, overload_legend=True)
) )
# Set xrange # Set xrange / yrange
render_helpers.set_axis_property(group_, axis.set_xlim, self.xrange) render_helpers.set_axis_property(group_, axis.set_xlim, self.xrange)
# Set yrange
render_helpers.set_axis_property(group_, axis.set_ylim, self.yrange) render_helpers.set_axis_property(group_, axis.set_ylim, self.yrange)
# Note: Extend axes limits to have the full plot, even with large
# linewidths. This is necessary as we do not clip lines.
maximum_linewidth = max(
max([plt[1].get("lw", 0) for plt in self.plots[group_]]),
max([plt[1].get("linewidth", 0) for plt in self.plots[group_]])
)
if maximum_linewidth > 0:
# Only extend axes limits if linewidths is larger than the default
# one.
ticks_position = { # Dump ticks position to restore them afterwards
"x": (axis.xaxis.get_majorticklocs(),
axis.xaxis.get_minorticklocs()),
"y": (axis.yaxis.get_majorticklocs(),
axis.yaxis.get_minorticklocs())
}
# Set xrange
extra_xrange = render_helpers.data_units_from_points(
maximum_linewidth,
axis,
reference="x")
xrange = (axis.get_xlim()[0] - extra_xrange / 2,
axis.get_xlim()[1] + extra_xrange / 2)
render_helpers.set_axis_property(group_, axis.set_xlim, xrange)
# Set yrange
extra_yrange = render_helpers.data_units_from_points(
maximum_linewidth,
axis,
reference="y")
yrange = (axis.get_ylim()[0] - extra_yrange / 2,
axis.get_ylim()[1] + extra_yrange / 2)
render_helpers.set_axis_property(group_, axis.set_ylim, yrange)
# Restore ticks
axis.xaxis.set_ticks(ticks_position["x"][0], minor=False)
axis.xaxis.set_ticks(ticks_position["x"][1], minor=True)
axis.yaxis.set_ticks(ticks_position["y"][0], minor=False)
axis.yaxis.set_ticks(ticks_position["y"][1], minor=True)
def _render_gif_animation(self, figure, axes): def _render_gif_animation(self, figure, axes):
""" """

View File

@ -1,6 +1,7 @@
""" """
Various helper functions for plotting. Various helper functions for plotting.
""" """
import numpy as np
def set_axis_property(group_, setter, value, default_setter=None): def set_axis_property(group_, setter, value, default_setter=None):
@ -26,3 +27,72 @@ def set_axis_property(group_, setter, value, default_setter=None):
else: else:
if value is not None: if value is not None:
setter(value) setter(value)
def linewidth_from_data_units(linewidth, axis, reference='y'):
"""
Convert a linewidth in data units to linewidth in points.
Parameters
----------
linewidth: float
Linewidth in data units of the respective reference-axis
axis: matplotlib axis
The axis which is used to extract the relevant transformation
data (data limits and size must not change afterwards)
reference: string
The axis that is taken as a reference for the data width.
Possible values: 'x' and 'y'. Defaults to 'y'.
Returns
-------
linewidth: float
Linewidth in points
From https://stackoverflow.com/questions/19394505/matplotlib-expand-the-line-with-specified-width-in-data-unit.
"""
fig = axis.get_figure()
if reference == 'x':
length = fig.bbox_inches.width * axis.get_position().width
value_range = np.diff(axis.get_xlim())
elif reference == 'y':
length = fig.bbox_inches.height * axis.get_position().height
value_range = np.diff(axis.get_ylim())
# Convert length to points
length *= 72 # Inches to points is a fixed conversion in matplotlib
# Scale linewidth to value range
return linewidth * (length / value_range)
def data_units_from_points(points, axis, reference='y'):
"""
Convert points to data units on the given axis.
Parameters
----------
points: float
Value in points to convert.
axis: matplotlib axis
The axis which is used to extract the relevant transformation
data (data limits and size must not change afterwards)
reference: string
The axis that is taken as a reference for the data width.
Possible values: 'x' and 'y'. Defaults to 'y'.
Returns
-------
points: float
Converted value.
"""
fig = axis.get_figure()
if reference == 'x':
length = fig.bbox_inches.width * axis.get_position().width
value_range = np.diff(axis.get_xlim())
elif reference == 'y':
length = fig.bbox_inches.height * axis.get_position().height
value_range = np.diff(axis.get_ylim())
# Convert length to points
length *= 72 # Inches to points is a fixed conversion in matplotlib
# Scale linewidth to value range
return points / (length / value_range)