content: # -*- coding: utf-8 -*-
  
  # Copyright (C) 2010-2013 Trémouilles David
  
  #This file is part of Thunderstorm.
  #
  #ThunderStrom is free software: you can redistribute it and/or modify
  #it under the terms of the GNU Lesser General Public License as published by
  #the Free Software Foundation, either version 3 of the License, or
  #(at your option) any later version.
  #
  #ThunderStorm is distributed in the hope that it will be useful,
  #but WITHOUT ANY WARRANTY; without even the implied warranty of
  #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  #GNU Lesser General Public License for more details.
  #
  #You should have received a copy of the GNU Lesser General Public License
  #along with ThunderStorm.  If not, see <http://www.gnu.org/licenses/>.
  
  """
  Various utility functions
  """
  
  import matplotlib
  from weakref import WeakValueDictionary
  from weakref import WeakKeyDictionary
  
  import warnings
  
  
  class UniversalCursors(object):
  
      def __init__(self):
          self.all_cursor_orient = WeakKeyDictionary()
          self.all_canvas = WeakValueDictionary()
          self.all_axes = WeakValueDictionary()
          self.backgrounds = {}
          self.visible = True
          self.needclear = False
  
      def _onmove(self, event):
          for canvas in self.all_canvas.values():
              if not canvas.widgetlock.available(self):
                  return
          if event.inaxes is None or not self.visible:
              if self.needclear:
                  self._update(event)
                  for canvas in self.all_canvas.values():
                      canvas.draw()
                  self.needclear = False
              return
          self._update(event)
  
      def _update(self, event):
          # 1/ Reset background
          for canvas in self.all_canvas.values():
              canvas.restore_region(self.backgrounds[id(canvas)])
          # 2/ update cursors
          for cursors in self.all_cursor_orient.keys():
              orient = self.all_cursor_orient[cursors]
              if (event.inaxes in [line.get_axes() for line in cursors]
                      and self.visible):
                  visible = True
                  self.needclear = True
              else:
                  visible = False
              for line in cursors:
                  if orient == 'vertical':
                      line.set_xdata((event.xdata, event.xdata))
                  if orient == 'horizontal':
                      line.set_ydata((event.ydata, event.ydata))
                  line.set_visible(visible)
                  ax = line.get_axes()
                  ax.draw_artist(line)
          # 3/ update canvas
          for canvas in self.all_canvas.values():
              canvas.blit(canvas.figure.bbox)
  
      def _clear(self, event):
          """clear the cursor"""
          self.backgrounds = {}
          for canvas in self.all_canvas.values():
              self.backgrounds[id(canvas)] = (
                  canvas.copy_from_bbox(canvas.figure.bbox))
          for cursor in self.all_cursor_orient.keys():
              for line in cursor:
                  line.set_visible(False)
  
      def add_cursor(self, axes=(), orient='vertical', **lineprops):
          class CursorList(list):
              def __hash__(self):
                  return hash(tuple(self))
          cursors = CursorList()  # Required to keep weakref
          for ax in axes:
              self.all_axes[id(ax)] = ax
              ax_canvas = ax.get_figure().canvas
              if ax_canvas not in self.all_canvas.values():
                  #if not ax_canvas.supports_blit:
                  #    warnings.warn("Must use canvas that support blit")
                  #    return
                  self.all_canvas[id(ax_canvas)] = ax_canvas
                  ax_canvas.mpl_connect('motion_notify_event', self._onmove)
                  ax_canvas.mpl_connect('draw_event', self._clear)
              if orient == 'vertical':
                  line = ax.axvline(ax.get_xbound()[0], visible=False,
                                    animated=True, **lineprops)
              if orient == 'horizontal':
                  line = ax.axhline(ax.get_ybound()[0], visible=False,
                                    animated=True, **lineprops)
              cursors.append(line)
          self.all_cursor_orient[cursors] = orient
          return cursors
  
  
  def autoscale_visible_lines(axs):
      """
      Function to autoscale only on visible lines.
      """
      mplt_ver = [int(elem) for elem in matplotlib.__version__.split('.')[0:2]]
      ignore = True
      for line in (axs.lines):
          if not line.get_visible():
              continue  # jump to next line if this one is not visible
          if mplt_ver[0] == 0 and mplt_ver[1] < 98:
              axs.dataLim.update_numerix(line.get_xdata(),
                                         line.get_ydata(),
                                         ignore)
          else:
              axs.dataLim.update_from_data_xy(line.get_xydata(),
                                              ignore)
          ignore = False
      axs.autoscale_view()
      return None
  
  
  def neg_bool_list(a_list):
      return [not elem for elem in a_list]
  