From 328b34fd550993b2e9350cedadf55563450ddb6c Mon Sep 17 00:00:00 2001 From: Philipp Rudiger <P.Rudiger@ed.ac.uk> Date: Sun, 21 Aug 2016 13:42:18 +0100 Subject: [PATCH 01/13] Allowed redrawing colorbars without passing arguments --- holoviews/plotting/mpl/chart3d.py | 5 ++++- holoviews/plotting/mpl/element.py | 14 ++++++++------ holoviews/plotting/mpl/path.py | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/holoviews/plotting/mpl/chart3d.py b/holoviews/plotting/mpl/chart3d.py index 342c78be23..dd7a1b3e19 100644 --- a/holoviews/plotting/mpl/chart3d.py +++ b/holoviews/plotting/mpl/chart3d.py @@ -84,7 +84,10 @@ def _finalize_axis(self, key, **kwargs): return super(Plot3D, self)._finalize_axis(key, **kwargs) - def _draw_colorbar(self, artist, element, dim=None): + def _draw_colorbar(self, dim=None): + element = self.hmap.last + artist = self.handles.get('artist', None) + fig = self.handles['fig'] ax = self.handles['axis'] # Get colorbar label diff --git a/holoviews/plotting/mpl/element.py b/holoviews/plotting/mpl/element.py index d899082463..c7e0e7d908 100644 --- a/holoviews/plotting/mpl/element.py +++ b/holoviews/plotting/mpl/element.py @@ -553,21 +553,23 @@ def _adjust_cbar(self, cbar, label, dim): def _finalize_artist(self, key): - element = self.hmap.last artist = self.handles.get('artist', None) if artist and self.colorbar: - self._draw_colorbar(artist, element) + self._draw_colorbar() - def _draw_colorbar(self, artist, element, dim=None): + def _draw_colorbar(self, dim=None, redraw=True): + element = self.hmap.last + artist = self.handles.get('artist', None) fig = self.handles['fig'] axis = self.handles['axis'] ax_colorbars, position = ColorbarPlot._colorbars.get(id(axis), ([], None)) specs = [spec[:2] for _, _, spec, _ in ax_colorbars] spec = util.get_spec(element) - if position is None: - fig.canvas.draw() + if position is None or not redraw: + if redraw: + fig.canvas.draw() bbox = axis.get_position() l, b, w, h = bbox.x0, bbox.y0, bbox.width, bbox.height else: @@ -594,7 +596,7 @@ def _draw_colorbar(self, artist, element, dim=None): self.handles['bbox_extra_artists'] += [cax, ylabel] ax_colorbars.append((artist, cax, spec, label)) - for i, (artist, cax, spec, label) in enumerate(ax_colorbars[:-1]): + for i, (artist, cax, spec, label) in enumerate(ax_colorbars): scaled_w = w*width cax.set_position([l+w+padding+(scaled_w+padding+w*0.15)*i, b, scaled_w, h]) diff --git a/holoviews/plotting/mpl/path.py b/holoviews/plotting/mpl/path.py index 755bace782..313a8014e8 100644 --- a/holoviews/plotting/mpl/path.py +++ b/holoviews/plotting/mpl/path.py @@ -69,7 +69,7 @@ def init_artists(self, ax, plot_args, plot_kwargs): collection = PatchCollection(*plot_args, **plot_kwargs) ax.add_collection(collection) if self.colorbar: - self._draw_colorbar(collection, self.current_frame) + self._draw_colorbar() return {'artist': collection, 'polys': plot_args[0]} From 1f9391aca6d908b0453ba33f41ed5a457e3ab0db Mon Sep 17 00:00:00 2001 From: Philipp Rudiger <P.Rudiger@ed.ac.uk> Date: Sun, 21 Aug 2016 13:43:16 +0100 Subject: [PATCH 02/13] Added support for fixing aspects of layout plots --- holoviews/plotting/mpl/plot.py | 31 +++++++-- holoviews/plotting/mpl/renderer.py | 30 +-------- holoviews/plotting/mpl/util.py | 102 +++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 31 deletions(-) diff --git a/holoviews/plotting/mpl/plot.py b/holoviews/plotting/mpl/plot.py index 2d24f82ea5..3019076c80 100644 --- a/holoviews/plotting/mpl/plot.py +++ b/holoviews/plotting/mpl/plot.py @@ -1,5 +1,7 @@ from __future__ import division +from itertools import chain + import numpy as np import matplotlib as mpl from mpl_toolkits.mplot3d import Axes3D # noqa (For 3D plots) @@ -15,7 +17,7 @@ from ..plot import DimensionedPlot, GenericLayoutPlot, GenericCompositePlot from ..util import get_dynamic_mode, initialize_sampled from .renderer import MPLRenderer -from .util import compute_ratios +from .util import compute_ratios, fix_aspect class MPLPlot(DimensionedPlot): @@ -617,7 +619,7 @@ def initialize_plot(self, ranges=None): self.drawn = True - def adjust_positions(self): + def adjust_positions(self, redraw=True): """ Make adjustments to the positions of subplots (if available) relative to the main plot axes as required. @@ -631,7 +633,8 @@ def adjust_positions(self): top = all('top' in check for check in checks) if not 'main' in self.subplots or not (top or right): return - self.handles['fig'].canvas.draw() + if redraw: + self.handles['fig'].canvas.draw() main_ax = self.subplots['main'].handles['axis'] bbox = main_ax.get_position() if right: @@ -695,6 +698,10 @@ class LayoutPlot(GenericLayoutPlot, CompositePlot): (left, bottom, right, top), defining the size of the border around the subplots.""") + fix_aspect = param.Boolean(default=False, doc="""Apply a fix to the + figure aspect to take into account non-square plots (will be the + default in future versions""") + tight = param.Boolean(default=False, doc=""" Tightly fit the axes in the layout within the fig_bounds and tight_padding.""") @@ -706,7 +713,7 @@ class LayoutPlot(GenericLayoutPlot, CompositePlot): Specifies the space between horizontally adjacent elements in the grid. Default value is set conservatively to avoid overlap of subplots.""") - vspace = param.Number(default=0.1, doc=""" + vspace = param.Number(default=0.3, doc=""" Specifies the space between vertically adjacent elements in the grid. Default value is set conservatively to avoid overlap of subplots.""") @@ -1025,12 +1032,28 @@ def initialize_plot(self): subplot.initialize_plot(ranges=ranges) # Create title handle + title = None if self.show_title and len(self.coords) > 1: title = self._format_title(key) title = self.handles['fig'].suptitle(title, **self._fontsize('title')) self.handles['title'] = title self.handles['bbox_extra_artists'] += [title] + fig = self.handles['fig'] + if (not self.traverse(specs=[GridPlot]) and not isinstance(self.fig_inches, tuple) + and self.fix_aspect): + traverse_fn = lambda x: x.handles.get('bbox_extra_artists', None) + extra_artists = list(chain(*[artists for artists in self.traverse(traverse_fn) + if artists is not None])) + aspect = fix_aspect(fig, title, extra_artists, vspace=self.vspace, + hspace=self.hspace) + colorbars = self.traverse(specs=[lambda x: hasattr(x, 'colorbar')]) + for cbar_plot in colorbars: + if cbar_plot.colorbar: + cbar_plot._draw_colorbar(redraw=False) + adjoined = self.traverse(specs=[AdjointLayoutPlot]) + for adjoined in adjoined: + adjoined.adjust_positions(redraw=False) return self._finalize_axis(None) diff --git a/holoviews/plotting/mpl/renderer.py b/holoviews/plotting/mpl/renderer.py index 0eb0f432d6..923ed1277f 100644 --- a/holoviews/plotting/mpl/renderer.py +++ b/holoviews/plotting/mpl/renderer.py @@ -19,6 +19,7 @@ from ..renderer import Renderer, MIME_TYPES from .widgets import MPLSelectionWidget, MPLScrubberWidget +from .util import get_tight_bbox class OutputWarning(param.Parameterized):pass outputwarning = OutputWarning(name='Warning') @@ -233,34 +234,9 @@ def _compute_bbox(self, fig, kw): if not fig_id in MPLRenderer.drawn: fig.set_dpi(self.dpi) fig.canvas.draw() - renderer = fig._cachedRenderer - bbox_inches = fig.get_tightbbox(renderer) - bbox_artists = kw.pop("bbox_extra_artists", []) - bbox_artists += fig.get_default_bbox_extra_artists() - bbox_filtered = [] - for a in bbox_artists: - bbox = a.get_window_extent(renderer) - if isinstance(bbox, tuple): - continue - if a.get_clip_on(): - clip_box = a.get_clip_box() - if clip_box is not None: - bbox = Bbox.intersection(bbox, clip_box) - clip_path = a.get_clip_path() - if clip_path is not None and bbox is not None: - clip_path = clip_path.get_fully_transformed_path() - bbox = Bbox.intersection(bbox, - clip_path.get_extents()) - if bbox is not None and (bbox.width != 0 or - bbox.height != 0): - bbox_filtered.append(bbox) - if bbox_filtered: - _bbox = Bbox.union(bbox_filtered) - trans = Affine2D().scale(1.0 / self.dpi) - bbox_extra = TransformedBbox(_bbox, trans) - bbox_inches = Bbox.union([bbox_inches, bbox_extra]) + extra_artists = kw.pop("bbox_extra_artists", []) pad = plt.rcParams['savefig.pad_inches'] - bbox_inches = bbox_inches.padded(pad) + bbox_inches = get_tight_bbox(fig, extra_artists, pad=pad) MPLRenderer.drawn[fig_id] = bbox_inches kw['bbox_inches'] = bbox_inches else: diff --git a/holoviews/plotting/mpl/util.py b/holoviews/plotting/mpl/util.py index 15dd388912..22d40acc9f 100644 --- a/holoviews/plotting/mpl/util.py +++ b/holoviews/plotting/mpl/util.py @@ -4,6 +4,7 @@ import numpy as np from matplotlib import ticker +from matplotlib.transforms import Bbox, TransformedBbox, Affine2D from ...core.util import basestring @@ -58,3 +59,104 @@ def compute_ratios(ratios, normalized=True): with warnings.catch_warnings(): warnings.filterwarnings('ignore', r'All-NaN (slice|axis) encountered') return np.nanmax(np.vstack([v for _, v in sorted_ratios]), axis=0) + + +def axis_overlap(ax1, ax2): + """ + Tests whether two axes overlap vertically + """ + b1, t1 = ax1.get_position().intervaly + b2, t2 = ax2.get_position().intervaly + return t1 >= b2 and b1 <= t2 + + +def resolve_rows(rows): + """ + Recursively iterate over lists of axes merging + them by their vertical overlap leaving a list + of rows. + """ + merged_rows = [] + for row in rows: + overlap = False + for mrow in merged_rows: + if any(axis_overlap(ax1, ax2) for ax1 in row + for ax2 in mrow): + mrow += row + overlap = True + break + if not overlap: + merged_rows.append(row) + if rows == merged_rows: + return rows + else: + return resolve_rows(merged_rows) + + +def fix_aspect(fig, title=None, extra_artists=[], vspace=0.2, hspace=0.2): + """ + Calculate heights and widths of axes and adjust + the size of the figure to match the aspect. + """ + fig.canvas.draw() + w, h = fig.get_size_inches() + + # Compute maximum height and width of each row and columns + rows = resolve_rows([[ax] for ax in fig.axes]) + rs, cs = len(rows), max([len(r) for r in rows]) + heights = [[] for i in range(cs)] + widths = [[] for i in range(rs)] + for r, row in enumerate(rows): + for c, ax in enumerate(row): + bbox = ax.get_tightbbox(fig.canvas.renderer) + heights[c].append(bbox.height) + widths[r].append(bbox.width) + height = (max([sum(c) for c in heights])) + (rs)*vspace + width = (max([sum(r) for r in widths])) + (cs)*hspace + + # Compute aspect and set new size (in inches) + aspect = height/width + offset = 0.2 if title and title.get_text() else 0 + fig.set_size_inches(w, (w*aspect)+offset) + + # Redraw and adjust title position if defined + fig.canvas.draw() + if title and title.get_text(): + bbox = get_tight_bbox(fig, extra_artists) + top = bbox.intervaly[1] + extra_artists = [a for a in extra_artists if a is not title] + if title and title.get_text(): + title.set_y((top/(w*aspect))) + + +def get_tight_bbox(fig, bbox_extra_artists=[], pad=None): + """ + Compute a tight bounding box around all the artists in the figure. + """ + renderer = fig._cachedRenderer + bbox_inches = fig.get_tightbbox(renderer) + bbox_artists = bbox_extra_artists[:] + bbox_artists += fig.get_default_bbox_extra_artists() + bbox_filtered = [] + for a in bbox_artists: + bbox = a.get_window_extent(renderer) + if isinstance(bbox, tuple): + continue + if a.get_clip_on(): + clip_box = a.get_clip_box() + if clip_box is not None: + bbox = Bbox.intersection(bbox, clip_box) + clip_path = a.get_clip_path() + if clip_path is not None and bbox is not None: + clip_path = clip_path.get_fully_transformed_path() + bbox = Bbox.intersection(bbox, + clip_path.get_extents()) + if bbox is not None and (bbox.width != 0 or + bbox.height != 0): + bbox_filtered.append(bbox) + if bbox_filtered: + _bbox = Bbox.union(bbox_filtered) + trans = Affine2D().scale(1.0 / fig.dpi) + bbox_extra = TransformedBbox(_bbox, trans) + bbox_inches = Bbox.union([bbox_inches, bbox_extra]) + return bbox_inches.padded(pad) if pad else bbox_inches From b210329db6bfdef7fa7460b1313b3c48a9240258 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger <P.Rudiger@ed.ac.uk> Date: Sun, 21 Aug 2016 15:03:15 +0100 Subject: [PATCH 03/13] Fix for padding calculation --- holoviews/plotting/mpl/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/holoviews/plotting/mpl/util.py b/holoviews/plotting/mpl/util.py index 22d40acc9f..22901ff5ba 100644 --- a/holoviews/plotting/mpl/util.py +++ b/holoviews/plotting/mpl/util.py @@ -111,8 +111,8 @@ def fix_aspect(fig, title=None, extra_artists=[], vspace=0.2, hspace=0.2): bbox = ax.get_tightbbox(fig.canvas.renderer) heights[c].append(bbox.height) widths[r].append(bbox.width) - height = (max([sum(c) for c in heights])) + (rs)*vspace - width = (max([sum(r) for r in widths])) + (cs)*hspace + height = (max([sum(c) for c in heights])) + (rs)*vspace*fig.dpi + width = (max([sum(r) for r in widths])) + (cs)*hspace*fig.dpi # Compute aspect and set new size (in inches) aspect = height/width From b0811254fa6cbc6196fcd738c7280c4130d0d035 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger <P.Rudiger@ed.ac.uk> Date: Sun, 21 Aug 2016 15:18:06 +0100 Subject: [PATCH 04/13] Made axis_overlap non-inclusive --- holoviews/plotting/mpl/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/holoviews/plotting/mpl/util.py b/holoviews/plotting/mpl/util.py index 22901ff5ba..3136fdbf56 100644 --- a/holoviews/plotting/mpl/util.py +++ b/holoviews/plotting/mpl/util.py @@ -67,7 +67,7 @@ def axis_overlap(ax1, ax2): """ b1, t1 = ax1.get_position().intervaly b2, t2 = ax2.get_position().intervaly - return t1 >= b2 and b1 <= t2 + return t1 > b2 and b1 < t2 def resolve_rows(rows): From 5be177261e05878ef5dda540703c320d3dc8bf95 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger <P.Rudiger@ed.ac.uk> Date: Sun, 21 Aug 2016 15:33:15 +0100 Subject: [PATCH 05/13] Removed magic number for title height --- holoviews/plotting/mpl/util.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/holoviews/plotting/mpl/util.py b/holoviews/plotting/mpl/util.py index 3136fdbf56..301a32518a 100644 --- a/holoviews/plotting/mpl/util.py +++ b/holoviews/plotting/mpl/util.py @@ -116,7 +116,9 @@ def fix_aspect(fig, title=None, extra_artists=[], vspace=0.2, hspace=0.2): # Compute aspect and set new size (in inches) aspect = height/width - offset = 0.2 if title and title.get_text() else 0 + offset = 0 + if title and title.get_text(): + offset = title.get_window_extent().height/fig.dpi fig.set_size_inches(w, (w*aspect)+offset) # Redraw and adjust title position if defined From 584836e16995d95fd1693ba0a3bdc96d8124065d Mon Sep 17 00:00:00 2001 From: Philipp Rudiger <P.Rudiger@ed.ac.uk> Date: Sun, 21 Aug 2016 16:15:54 +0100 Subject: [PATCH 06/13] Simplified figure scaling --- holoviews/plotting/mpl/plot.py | 13 +++++++------ holoviews/plotting/mpl/renderer.py | 10 ++-------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/holoviews/plotting/mpl/plot.py b/holoviews/plotting/mpl/plot.py index 3019076c80..d56cf254cf 100644 --- a/holoviews/plotting/mpl/plot.py +++ b/holoviews/plotting/mpl/plot.py @@ -56,7 +56,7 @@ class MPLPlot(DimensionedPlot): fig_rcparams = param.Dict(default={}, doc=""" matplotlib rc parameters to apply to the overall figure.""") - fig_size = param.Integer(default=100, bounds=(1, None), doc=""" + fig_size = param.Number(default=100., bounds=(1, None), doc=""" Size relative to the supplied overall fig_inches in percent.""") initial_hooks = param.HookList(default=[], doc=""" @@ -99,12 +99,12 @@ def __init__(self, fig=None, axis=None, **params): self._create_fig = True super(MPLPlot, self).__init__(**params) # List of handles to matplotlib objects for animation update - scale = self.fig_size/100. + self.fig_scale = self.fig_size/100. if isinstance(self.fig_inches, (tuple, list)): - self.fig_inches = [None if i is None else i*scale + self.fig_inches = [None if i is None else i*self.fig_scale for i in self.fig_inches] else: - self.fig_inches *= scale + self.fig_inches *= self.fig_scale fig, axis = self._init_axis(fig, axis) self.handles['fig'] = fig self.handles['axis'] = axis @@ -1045,8 +1045,9 @@ def initialize_plot(self): traverse_fn = lambda x: x.handles.get('bbox_extra_artists', None) extra_artists = list(chain(*[artists for artists in self.traverse(traverse_fn) if artists is not None])) - aspect = fix_aspect(fig, title, extra_artists, vspace=self.vspace, - hspace=self.hspace) + aspect = fix_aspect(fig, title, extra_artists, + vspace=self.vspace*self.fig_scale, + hspace=self.hspace*self.fig_scale) colorbars = self.traverse(specs=[lambda x: hasattr(x, 'colorbar')]) for cbar_plot in colorbars: if cbar_plot.colorbar: diff --git a/holoviews/plotting/mpl/renderer.py b/holoviews/plotting/mpl/renderer.py index 923ed1277f..15ed87cc51 100644 --- a/holoviews/plotting/mpl/renderer.py +++ b/holoviews/plotting/mpl/renderer.py @@ -122,15 +122,9 @@ def plot_options(cls, obj, percent_size): factor = percent_size / 100.0 obj = obj.last if isinstance(obj, HoloMap) else obj options = Store.lookup_options(cls.backend, obj, 'plot').options - fig_inches = options.get('fig_inches', MPLPlot.fig_inches) + fig_size = options.get('fig_size', MPLPlot.fig_size)*factor - if isinstance(fig_inches, (list, tuple)): - fig_inches = (None if fig_inches[0] is None else fig_inches[0] * factor, - None if fig_inches[1] is None else fig_inches[1] * factor) - else: - fig_inches = MPLPlot.fig_inches * factor - - return dict({'fig_inches':fig_inches}, + return dict({'fig_size':fig_size}, **Store.lookup_options(cls.backend, obj, 'plot').options) From f618ecc819c7c1cc1315ecc6ec7c14a4f4058814 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger <P.Rudiger@ed.ac.uk> Date: Sun, 21 Aug 2016 16:16:41 +0100 Subject: [PATCH 07/13] Small fixes for fix_aspect --- holoviews/plotting/mpl/plot.py | 2 +- holoviews/plotting/mpl/util.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/holoviews/plotting/mpl/plot.py b/holoviews/plotting/mpl/plot.py index d56cf254cf..597391ef15 100644 --- a/holoviews/plotting/mpl/plot.py +++ b/holoviews/plotting/mpl/plot.py @@ -713,7 +713,7 @@ class LayoutPlot(GenericLayoutPlot, CompositePlot): Specifies the space between horizontally adjacent elements in the grid. Default value is set conservatively to avoid overlap of subplots.""") - vspace = param.Number(default=0.3, doc=""" + vspace = param.Number(default=0.1, doc=""" Specifies the space between vertically adjacent elements in the grid. Default value is set conservatively to avoid overlap of subplots.""") diff --git a/holoviews/plotting/mpl/util.py b/holoviews/plotting/mpl/util.py index 301a32518a..4769e7b8e7 100644 --- a/holoviews/plotting/mpl/util.py +++ b/holoviews/plotting/mpl/util.py @@ -111,8 +111,8 @@ def fix_aspect(fig, title=None, extra_artists=[], vspace=0.2, hspace=0.2): bbox = ax.get_tightbbox(fig.canvas.renderer) heights[c].append(bbox.height) widths[r].append(bbox.width) - height = (max([sum(c) for c in heights])) + (rs)*vspace*fig.dpi - width = (max([sum(r) for r in widths])) + (cs)*hspace*fig.dpi + height = (max([sum(c) for c in heights])) + (rs-1)*vspace*fig.dpi + width = (max([sum(r) for r in widths])) + (cs-1)*hspace*fig.dpi # Compute aspect and set new size (in inches) aspect = height/width @@ -124,9 +124,10 @@ def fix_aspect(fig, title=None, extra_artists=[], vspace=0.2, hspace=0.2): # Redraw and adjust title position if defined fig.canvas.draw() if title and title.get_text(): + extra_artists = [a for a in extra_artists + if a is not title] bbox = get_tight_bbox(fig, extra_artists) top = bbox.intervaly[1] - extra_artists = [a for a in extra_artists if a is not title] if title and title.get_text(): title.set_y((top/(w*aspect))) From d585a2e9814312387a44263558d81aa0a7cdfee4 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger <P.Rudiger@ed.ac.uk> Date: Sun, 21 Aug 2016 16:33:00 +0100 Subject: [PATCH 08/13] Enabled fix_aspect by default --- holoviews/plotting/mpl/plot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/holoviews/plotting/mpl/plot.py b/holoviews/plotting/mpl/plot.py index 597391ef15..9a96c3d220 100644 --- a/holoviews/plotting/mpl/plot.py +++ b/holoviews/plotting/mpl/plot.py @@ -698,7 +698,7 @@ class LayoutPlot(GenericLayoutPlot, CompositePlot): (left, bottom, right, top), defining the size of the border around the subplots.""") - fix_aspect = param.Boolean(default=False, doc="""Apply a fix to the + fix_aspect = param.Boolean(default=True, doc="""Apply a fix to the figure aspect to take into account non-square plots (will be the default in future versions""") @@ -713,7 +713,7 @@ class LayoutPlot(GenericLayoutPlot, CompositePlot): Specifies the space between horizontally adjacent elements in the grid. Default value is set conservatively to avoid overlap of subplots.""") - vspace = param.Number(default=0.1, doc=""" + vspace = param.Number(default=0.25, doc=""" Specifies the space between vertically adjacent elements in the grid. Default value is set conservatively to avoid overlap of subplots.""") From 1a4c2cbcf10c396bac3bc598f4ecf7ee63ed78d0 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger <P.Rudiger@ed.ac.uk> Date: Sun, 21 Aug 2016 18:41:52 +0100 Subject: [PATCH 09/13] Simplified tutorial layout options --- doc/Tutorials/Columnar_Data.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/Tutorials/Columnar_Data.ipynb b/doc/Tutorials/Columnar_Data.ipynb index 3d9cea3827..77a674c8bc 100644 --- a/doc/Tutorials/Columnar_Data.ipynb +++ b/doc/Tutorials/Columnar_Data.ipynb @@ -820,8 +820,8 @@ }, "outputs": [], "source": [ - "%opts HeatMap [show_values=False xticks=40 xrotation=90 aspect=1.2 invert_yaxis=True colorbar=True]\n", - "%opts Layout [figure_size=120 aspect_weight=0.5 hspace=0.8 vspace=0]" + "%opts HeatMap [show_values=False xticks=40 xrotation=90 aspect=1.5 invert_yaxis=True colorbar=True]\n", + "%opts Layout [figure_size=150 vspace=0.4]" ] }, { From 303a9d01c9475294c57881a08276d731ec45ccbb Mon Sep 17 00:00:00 2001 From: Philipp Rudiger <P.Rudiger@ed.ac.uk> Date: Sun, 21 Aug 2016 20:54:59 +0100 Subject: [PATCH 10/13] Adjusted default vspace --- doc/Tutorials/Columnar_Data.ipynb | 4 ++-- holoviews/plotting/mpl/plot.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/Tutorials/Columnar_Data.ipynb b/doc/Tutorials/Columnar_Data.ipynb index 77a674c8bc..41fa1c44b4 100644 --- a/doc/Tutorials/Columnar_Data.ipynb +++ b/doc/Tutorials/Columnar_Data.ipynb @@ -820,8 +820,8 @@ }, "outputs": [], "source": [ - "%opts HeatMap [show_values=False xticks=40 xrotation=90 aspect=1.5 invert_yaxis=True colorbar=True]\n", - "%opts Layout [figure_size=150 vspace=0.4]" + "%opts HeatMap [show_values=False xticks=40 xrotation=90 aspect=1.2 invert_yaxis=True colorbar=True]\n", + "%opts Layout [figure_size=150]" ] }, { diff --git a/holoviews/plotting/mpl/plot.py b/holoviews/plotting/mpl/plot.py index 9a96c3d220..6f04944e8b 100644 --- a/holoviews/plotting/mpl/plot.py +++ b/holoviews/plotting/mpl/plot.py @@ -713,7 +713,7 @@ class LayoutPlot(GenericLayoutPlot, CompositePlot): Specifies the space between horizontally adjacent elements in the grid. Default value is set conservatively to avoid overlap of subplots.""") - vspace = param.Number(default=0.25, doc=""" + vspace = param.Number(default=0.3, doc=""" Specifies the space between vertically adjacent elements in the grid. Default value is set conservatively to avoid overlap of subplots.""") From b89867c6a6207e04fc973301dd2c9bef0e613c24 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger <P.Rudiger@ed.ac.uk> Date: Sun, 21 Aug 2016 21:41:49 +0100 Subject: [PATCH 11/13] Small fixes to Layout padding --- holoviews/plotting/mpl/plot.py | 15 ++++++++------- holoviews/plotting/mpl/util.py | 7 ++++--- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/holoviews/plotting/mpl/plot.py b/holoviews/plotting/mpl/plot.py index 6f04944e8b..c4ef606158 100644 --- a/holoviews/plotting/mpl/plot.py +++ b/holoviews/plotting/mpl/plot.py @@ -1032,12 +1032,12 @@ def initialize_plot(self): subplot.initialize_plot(ranges=ranges) # Create title handle - title = None - if self.show_title and len(self.coords) > 1: - title = self._format_title(key) - title = self.handles['fig'].suptitle(title, **self._fontsize('title')) - self.handles['title'] = title - self.handles['bbox_extra_artists'] += [title] + title_obj = None + title = self._format_title(key) + if self.show_title and len(self.coords) > 1 and title: + title_obj = self.handles['fig'].suptitle(title, **self._fontsize('title')) + self.handles['title'] = title_obj + self.handles['bbox_extra_artists'] += [title_obj] fig = self.handles['fig'] if (not self.traverse(specs=[GridPlot]) and not isinstance(self.fig_inches, tuple) @@ -1045,7 +1045,8 @@ def initialize_plot(self): traverse_fn = lambda x: x.handles.get('bbox_extra_artists', None) extra_artists = list(chain(*[artists for artists in self.traverse(traverse_fn) if artists is not None])) - aspect = fix_aspect(fig, title, extra_artists, + aspect = fix_aspect(fig, self.rows, self.cols, + title_obj, extra_artists, vspace=self.vspace*self.fig_scale, hspace=self.hspace*self.fig_scale) colorbars = self.traverse(specs=[lambda x: hasattr(x, 'colorbar')]) diff --git a/holoviews/plotting/mpl/util.py b/holoviews/plotting/mpl/util.py index 4769e7b8e7..3212e0e8fd 100644 --- a/holoviews/plotting/mpl/util.py +++ b/holoviews/plotting/mpl/util.py @@ -93,7 +93,8 @@ def resolve_rows(rows): return resolve_rows(merged_rows) -def fix_aspect(fig, title=None, extra_artists=[], vspace=0.2, hspace=0.2): +def fix_aspect(fig, nrows, ncols, title=None, extra_artists=[], + vspace=0.2, hspace=0.2): """ Calculate heights and widths of axes and adjust the size of the figure to match the aspect. @@ -111,8 +112,8 @@ def fix_aspect(fig, title=None, extra_artists=[], vspace=0.2, hspace=0.2): bbox = ax.get_tightbbox(fig.canvas.renderer) heights[c].append(bbox.height) widths[r].append(bbox.width) - height = (max([sum(c) for c in heights])) + (rs-1)*vspace*fig.dpi - width = (max([sum(r) for r in widths])) + (cs-1)*hspace*fig.dpi + height = (max([sum(c) for c in heights])) + nrows*vspace*fig.dpi + width = (max([sum(r) for r in widths])) + ncols*hspace*fig.dpi # Compute aspect and set new size (in inches) aspect = height/width From 6298a8895e42aba0bed4c3d3becd5ec3d7d86f2e Mon Sep 17 00:00:00 2001 From: Philipp Rudiger <P.Rudiger@ed.ac.uk> Date: Mon, 22 Aug 2016 12:34:24 +0100 Subject: [PATCH 12/13] Added compatibility flag for new layout format --- holoviews/plotting/mpl/plot.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/holoviews/plotting/mpl/plot.py b/holoviews/plotting/mpl/plot.py index c4ef606158..884e5973d8 100644 --- a/holoviews/plotting/mpl/plot.py +++ b/holoviews/plotting/mpl/plot.py @@ -698,10 +698,6 @@ class LayoutPlot(GenericLayoutPlot, CompositePlot): (left, bottom, right, top), defining the size of the border around the subplots.""") - fix_aspect = param.Boolean(default=True, doc="""Apply a fix to the - figure aspect to take into account non-square plots (will be the - default in future versions""") - tight = param.Boolean(default=False, doc=""" Tightly fit the axes in the layout within the fig_bounds and tight_padding.""") @@ -713,12 +709,17 @@ class LayoutPlot(GenericLayoutPlot, CompositePlot): Specifies the space between horizontally adjacent elements in the grid. Default value is set conservatively to avoid overlap of subplots.""") - vspace = param.Number(default=0.3, doc=""" + vspace = param.Number(default=0.1, doc=""" Specifies the space between vertically adjacent elements in the grid. Default value is set conservatively to avoid overlap of subplots.""") fontsize = param.Parameter(default={'title':16}, allow_None=True) + # Whether to enable fix for non-square figures + # Will be enabled by default in v1.7 + # If enabled default vspace should be increased to 0.3 + v17_layout_format = False + def __init__(self, layout, **params): super(LayoutPlot, self).__init__(layout=layout, **params) self.subplots, self.subaxes, self.layout = self._compute_gridspec(layout) @@ -1041,7 +1042,7 @@ def initialize_plot(self): fig = self.handles['fig'] if (not self.traverse(specs=[GridPlot]) and not isinstance(self.fig_inches, tuple) - and self.fix_aspect): + and self.v17_layout_format): traverse_fn = lambda x: x.handles.get('bbox_extra_artists', None) extra_artists = list(chain(*[artists for artists in self.traverse(traverse_fn) if artists is not None])) From e34c20f32eca0e46cc8cf61bc29a273781488650 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger <P.Rudiger@ed.ac.uk> Date: Mon, 22 Aug 2016 12:54:23 +0100 Subject: [PATCH 13/13] Reverted tutorial layout fix --- doc/Tutorials/Columnar_Data.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Tutorials/Columnar_Data.ipynb b/doc/Tutorials/Columnar_Data.ipynb index 41fa1c44b4..3d9cea3827 100644 --- a/doc/Tutorials/Columnar_Data.ipynb +++ b/doc/Tutorials/Columnar_Data.ipynb @@ -821,7 +821,7 @@ "outputs": [], "source": [ "%opts HeatMap [show_values=False xticks=40 xrotation=90 aspect=1.2 invert_yaxis=True colorbar=True]\n", - "%opts Layout [figure_size=150]" + "%opts Layout [figure_size=120 aspect_weight=0.5 hspace=0.8 vspace=0]" ] }, {