Computes the size of bokeh models that make up a layout such as
    figures, rows, columns, widgetboxes and Plot.

def compute_plot_size(plot):
    """
    Computes the size of bokeh models that make up a layout such as
    figures, rows, columns, widgetboxes and Plot.
    """
    if isinstance(plot, GridBox):
        ndmapping = NdMapping({(x, y): fig for fig, y, x in plot.children}, kdims=['x', 'y'])
        cols = ndmapping.groupby('x')
        rows = ndmapping.groupby('y')
        width = sum([max([compute_plot_size(f)[0] for f in col]) for col in cols])
        height = sum([max([compute_plot_size(f)[1] for f in row]) for row in rows])
        return width, height
    elif isinstance(plot, (Div, ToolbarBox)):
        # Cannot compute size for Div or ToolbarBox
        return 0, 0
    elif isinstance(plot, (Row, Column, WidgetBox, Tabs)):
        if not plot.children: return 0, 0
        if isinstance(plot, Row) or (isinstance(plot, ToolbarBox) and plot.toolbar_location not in ['right', 'left']):
            w_agg, h_agg = (np.sum, np.max)
        elif isinstance(plot, Tabs):
            w_agg, h_agg = (np.max, np.max)
        else:
            w_agg, h_agg = (np.max, np.sum)
        widths, heights = zip(*[compute_plot_size(child) for child in plot.children])
        return w_agg(widths), h_agg(heights)
    elif isinstance(plot, (Figure, Chart)):
        if plot.plot_width:
            width = plot.plot_width
        else:
            width = plot.frame_width + plot.min_border_right + plot.min_border_left
        if plot.plot_height:
            height = plot.plot_height
        else:
            height = plot.frame_height + plot.min_border_bottom + plot.min_border_top
        return width, height
    elif isinstance(plot, (Plot, DataTable, Spacer)):
        return plot.width, plot.height
    else:
        return 0, 0