# Buggy code
def _init_tools(self, element, callbacks=[]):
    """
    Processes the list of tools to be supplied to the plot.
    """
    tooltips, hover_opts = self._hover_opts(element)
    tooltips = [
        (ttp.pprint_label, "@{%s}" % util.dimension_sanitizer(ttp.name))
        if isinstance(ttp, Dimension)
        else ttp
        for ttp in tooltips
    ]
    if not tooltips:
        tooltips = None

    callbacks = callbacks + self.callbacks
    cb_tools, tool_names = [], []
    hover = False
    for cb in callbacks:
        for handle in cb.models + cb.extra_models:
            if handle and handle in known_tools:
                tool_names.append(handle)
                if handle == "hover":
                    tool = HoverTool(tooltips=tooltips, **hover_opts)
                    hover = tool
                else:
                    tool = known_tools[handle]()
                cb_tools.append(tool)
                self.handles[handle] = tool

    tools = [
        t for t in cb_tools + self.default_tools + self.tools if t not in tool_names
    ]
    hover_tools = [t for t in tools if isinstance(t, HoverTool)]
    if "hover" in tools:
        hover = HoverTool(tooltips=tooltips, **hover_opts)
        tools[tools.index("hover")] = hover
    elif any(hover_tools):
        hover = hover_tools[0]
    if hover:
        self.handles["hover"] = hover
    return tools


# Traceback (ValueError)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~/virtualenvs/env/lib/python3.6/site-packages/IPython/core/formatters.py in __call__(self, obj)
330                 pass
331             else:
--> 332                 return printer(obj)
333             # Finally look for special method names
334             method = get_real_method(obj, self.print_method)

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/ipython/display_hooks.py in pprint_display(obj)
257     if not ip.display_formatter.formatters['text/plain'].pprint:
258         return None
--> 259     return display(obj, raw=True)
260
261

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/ipython/display_hooks.py in display(obj, raw, **kwargs)
240     elif isinstance(obj, (Layout, NdLayout, AdjointLayout)):
241         with option_state(obj):
--> 242             html = layout_display(obj)
243     elif isinstance(obj, (HoloMap, DynamicMap)):
244         with option_state(obj):

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/ipython/display_hooks.py in wrapped(element)
129         try:
130             html = fn(element,
--> 131                       max_frames=OutputSettings.options['max_frames'])
132
133             # Only want to add to the archive for one display hook...

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/ipython/display_hooks.py in layout_display(layout, max_frames)
211         return None
212
--> 213     return render(layout)
214
215

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/ipython/display_hooks.py in render(obj, **kwargs)
59     if renderer.fig == 'pdf':
60         renderer = renderer.instance(fig='png')
---> 61     return renderer.html(obj, **kwargs)
62
63

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/plotting/renderer.py in html(self, obj, fmt, css, comm, **kwargs)
253         code to initialize a Comm, if the plot supplies one.
254         """
--> 255         plot, fmt =  self._validate(obj, fmt)
256         figdata, _ = self(plot, fmt, **kwargs)
257         if css is None: css = self.css

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/plotting/renderer.py in _validate(self, obj, fmt)
189         if isinstance(obj, tuple(self.widgets.values())):
190             return obj, 'html'
--> 191         plot = self.get_plot(obj, renderer=self)
192
193         fig_formats = self.mode_formats['fig'][self.mode]

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/plotting/bokeh/renderer.py in get_plot(self_or_cls, obj, doc, renderer)
110         combining the bokeh model with another plot.
111         """
--> 112         plot = super(BokehRenderer, self_or_cls).get_plot(obj, renderer)
113         if doc is not None:
114             plot.document = doc

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/plotting/renderer.py in get_plot(self_or_cls, obj, renderer)
176             plot = self_or_cls.plotting_class(obj)(obj, renderer=renderer,
177                                                    **plot_opts)
--> 178             plot.update(0)
179         else:
180             plot = obj

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/plotting/plot.py in update(self, key)
483     def update(self, key):
484         if len(self) == 1 and key == 0 and not self.drawn:
--> 485             return self.initialize_plot()
486         item = self.__getitem__(key)
487         self.traverse(lambda x: setattr(x, '_updated', True))

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/plotting/bokeh/plot.py in initialize_plot(self, plots, ranges)
630             if subplot is not None:
631                 shared_plots = passed_plots if self.shared_axes else None
--> 632                 subplots = subplot.initialize_plot(ranges=ranges, plots=shared_plots)
633
634                 # Computes plotting offsets depending on

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/plotting/bokeh/plot.py in initialize_plot(self, ranges, plots)
767             if subplot:
768                 passed_plots = plots  + adjoined_plots
--> 769                 adjoined_plots.append(subplot.initialize_plot(ranges=ranges, plots=passed_plots))
770             else:
771                 adjoined_plots.append(empty_plot(0, 0))

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/plotting/bokeh/element.py in initialize_plot(self, ranges, plot, plots, source)
771         # Initialize plot, source and glyph
772         if plot is None:
--> 773             plot = self._init_plot(key, style_element, ranges=ranges, plots=plots)
774             self._init_axes(plot)
775         else:

~/virtualenvs/env/lib/python3.6/site-packages/holoviews/plotting/bokeh/element.py in _init_plot(self, key, element, plots, ranges)
404             return bokeh.plotting.Figure(x_axis_type=x_axis_type,
405                                          y_axis_type=y_axis_type, title=title,
--> 406                                          **properties)
407
408

~/virtualenvs/env/lib/python3.6/site-packages/bokeh/plotting/figure.py in __init__(self, *arg, **kw)
133
134         tool_objs, tool_map = _process_tools_arg(self, opts.tools)
--> 135         self.add_tools(*tool_objs)
136         _process_active_tools(self.toolbar, tool_map, opts.active_drag, opts.active_inspect, opts.active_scroll, opts.active_tap)
137

~/virtualenvs/env/lib/python3.6/site-packages/bokeh/models/plots.py in add_tools(self, *tools)
251         for tool in tools:
252             if tool.plot is not None:
--> 253                 raise ValueError("tool %s to be added already has 'plot' attribute set" % tool)
254             tool.plot = self
255             if hasattr(tool, 'overlay'):

ValueError: tool HoverTool(id='fee2b217-4838-46de-9d31-3f2e1a95ad96', ...) to be added already has 'plot' attribute set

# Fixed code
def _init_tools(self, element, callbacks=[]):
    """
    Processes the list of tools to be supplied to the plot.
    """
    tooltips, hover_opts = self._hover_opts(element)
    tooltips = [
        (ttp.pprint_label, "@{%s}" % util.dimension_sanitizer(ttp.name))
        if isinstance(ttp, Dimension)
        else ttp
        for ttp in tooltips
    ]
    if not tooltips:
        tooltips = None

    callbacks = callbacks + self.callbacks
    cb_tools, tool_names = [], []
    hover = False
    for cb in callbacks:
        for handle in cb.models + cb.extra_models:
            if handle and handle in known_tools:
                tool_names.append(handle)
                if handle == "hover":
                    tool = HoverTool(tooltips=tooltips, **hover_opts)
                    hover = tool
                else:
                    tool = known_tools[handle]()
                cb_tools.append(tool)
                self.handles[handle] = tool

    tools = [
        t for t in cb_tools + self.default_tools + self.tools if t not in tool_names
    ]

    copied_tools = []
    for tool in tools:
        if isinstance(tool, Tool):
            properties = tool.properties_with_values(include_defaults=False)
            tool = type(tool)(**properties)
        copied_tools.append(tool)

    hover_tools = [t for t in copied_tools if isinstance(t, HoverTool)]
    if "hover" in copied_tools:
        hover = HoverTool(tooltips=tooltips, **hover_opts)
        copied_tools[copied_tools.index("hover")] = hover
    elif any(hover_tools):
        hover = hover_tools[0]
    if hover:
        self.handles["hover"] = hover
    return copied_tools