content: from __future__ import absolute_import
  
  from ..plot_object import PlotObject
  from ..properties import HasProps
  from ..properties import Any, Int, String, Instance, List, Dict, Either, Bool, Enum
  from ..validation.errors import COLUMN_LENGTHS
  from .. import validation
  from ..util.serialization import transform_column_source_data
  from .actions import Callback
  
  class DataSource(PlotObject):
      """ A base class for data source types. ``DataSource`` is
      not generally useful to instantiate on its own.
  
      """
  
      column_names = List(String, help="""
      An list of names for all the columns in this DataSource.
      """)
  
      selected = Dict(String, Dict(String, Any), default={
          '0d': {'flag': False, 'indices': []},
          '1d': {'indices': []},
          '2d': {'indices': []}
      }, help="""
      A dict to indicate selected indices on different dimensions on this DataSource. Keys are:
  
      - 0d: indicates whether a Line or Patch glyphs have been hit. Value is a
              dict with the following keys:
  
              - flag (boolean): true if glyph was with false otherwise
              - indices (list): indices hit (if applicable)
  
      - 1d: indicates whether any of all other glyph (except [multi]line or
              patches) was hit:
  
              - indices (list): indices that were hit/selected
  
      - 2d: indicates whether a [multi]line or patches) were hit:
  
              - indices (list(list)): indices of the lines/patches that were
                  hit/selected
      """)
  
      callback = Instance(Callback, help="""
      A callback to run in the browser whenever the selection is changed.
      """)
  
      def columns(self, *columns):
          """ Returns a ColumnsRef object for a column or set of columns
          on this data source.
  
          Args:
              *columns
  
          Returns:
              ColumnsRef
  
          """
          return ColumnsRef(source=self, columns=list(columns))
  
  class ColumnsRef(HasProps):
      """ A utility object to allow referring to a collection of columns
      from a specified data source, all together.
  
      """
  
      source = Instance(DataSource, help="""
      A data source to reference.
      """)
  
      columns = List(String, help="""
      A list of column names to reference from ``source``.
      """)
  
  class ColumnDataSource(DataSource):
      """ Maps names of columns to sequences or arrays.
  
      If the ColumnDataSource initializer is called with a single
      argument that is a dict, that argument is used as the value for
      the "data" attribute. For example::
  
          ColumnDataSource(mydict) # same as ColumnDataSource(data=mydict)
  
      .. note::
          There is an implicit assumption that all the columns in a
          a given ColumnDataSource have the same length.
  
      """
  
      data = Dict(String, Any, help="""
      Mapping of column names to sequences of data. The data can be, e.g,
      Python lists or tuples, NumPy arrays, etc.
      """)
  
      def __init__(self, *args, **kw):
          """ If called with a single argument that is a dict, treat
          that implicitly as the "data" attribute.
          """
          if len(args) == 1 and "data" not in kw:
              kw["data"] = args[0]
          # TODO (bev) invalid to pass args and "data", check and raise exception
          raw_data = kw.pop("data", {})
          if not isinstance(raw_data, dict):
              import pandas as pd
              if isinstance(raw_data, pd.DataFrame):
                  raw_data = self.from_df(raw_data)
              else:
                  raise ValueError("expected a dict or pandas.DataFrame, got %s" % raw_data)
          for name, data in raw_data.items():
              self.add(data, name)
          super(ColumnDataSource, self).__init__(**kw)
  
      # TODO: (bev) why not just return a ColumnDataSource?
      @classmethod
      def from_df(cls, data):
          """ Create a ``dict`` of columns from a Pandas DataFrame,
          suitable for creating a ColumnDataSource.
  
          Args:
              data (DataFrame) : data to convert
  
          Returns:
              dict(str, list)
  
          """
          index = data.index
          new_data = {}
          for colname in data:
              new_data[colname] = data[colname].tolist()
          if index.name:
              new_data[index.name] = index.tolist()
          elif index.names and not all([x is None for x in index.names]):
              new_data["_".join(index.names)] = index.tolist()
          else:
              new_data["index"] = index.tolist()
          return new_data
  
      def to_df(self):
          """ Convert this data source to pandas dataframe.
  
          If ``column_names`` is set, use those. Otherwise let Pandas
          infer the column names. The ``column_names`` property can be
          used both to order and filter the columns.
  
          Returns:
              DataFrame
  
          """
          import pandas as pd
          if self.column_names:
              return pd.DataFrame(self.data, columns=self.column_names)
          else:
              return pd.DataFrame(self.data)
  
      def add(self, data, name=None):
          """ Appends a new column of data to the data source.
  
          Args:
              data (seq) : new data to add
              name (str, optional) : column name to use.
                  If not supplied, generate a name go the form "Series ####"
  
          Returns:
              str:  the column name used
  
          """
          if name is None:
              n = len(self.data)
              while "Series %d"%n in self.data:
                  n += 1
              name = "Series %d"%n
          self.column_names.append(name)
          self.data[name] = data
          return name
  
      def vm_serialize(self, changed_only=True):
          attrs = super(ColumnDataSource, self).vm_serialize(changed_only=changed_only)
          if 'data' in attrs:
              attrs['data'] = transform_column_source_data(attrs['data'])
          return attrs
  
      def remove(self, name):
          """ Remove a column of data.
  
          Args:
              name (str) : name of the column to remove
  
          Returns:
              None
  
          .. note::
              If the column name does not exist, a warning is issued.
  
          """
          try:
              self.column_names.remove(name)
              del self.data[name]
          except (ValueError, KeyError):
              import warnings
              warnings.warn("Unable to find column '%s' in data source" % name)
  
      def push_notebook(self):
          """ Update date for a plot in the IPthon notebook in place.
  
          This function can be be used to update data in plot data sources
          in the IPython notebook, without having to use the Bokeh server.
  
          Returns:
              None
  
          .. warning::
              The current implementation leaks memory in the IPython notebook,
              due to accumulating JS code. This function typically works well
              with light UI interactions, but should not be used for continuously
              updating data. See :bokeh-issue:`1732` for more details and to
              track progress on potential fixes.
  
          """
          from IPython.core import display
          from bokeh.protocol import serialize_json
          id = self.ref['id']
          model = self.ref['type']
          json = serialize_json(self.vm_serialize())
          js = """
              var ds = Bokeh.Collections('{model}').get('{id}');
              var data = {json};
              ds.set(data);
          """.format(model=model, id=id, json=json)
          display.display_javascript(js, raw=True)
  
      @validation.error(COLUMN_LENGTHS)
      def _check_column_lengths(self):
          lengths = set(len(x) for x in self.data.values())
          if len(lengths) > 1:
              return str(self)
  
  class RemoteSource(DataSource):
      data_url = String(help="""
      The URL to the endpoint for the data.
      """)
      data = Dict(String, Any, help="""
      Additional data to include directly in this data source object. The
      columns provided here are merged with those from the Bokeh server.
      """)
      polling_interval = Int(help="""
      polling interval for updating data source in milliseconds
      """)
  
  class AjaxDataSource(RemoteSource):
      method = Enum('POST', 'GET', help="http method - GET or POST")
  
      mode = Enum("replace", "append", help="""
      Whether to append new data to existing data (up to ``max_size``),
      or to replace existing data entirely.
      """)
      max_size = Int(help="""
      Maximum size of the data array being kept after each pull requests.
      Larger than that size, the data will be right shifted.
      """)
      if_modified = Bool(False, help="""
      Whether to include an ``If-Modified-Since`` header in AJAX requests
      to the server. If this header is supported by the server, then only
      new data since the last request will be returned.
      """)
  
  class BlazeDataSource(RemoteSource):
      #blaze parts
      expr = Dict(String, Any(), help="""
      blaze expression graph in json form
      """)
      namespace = Dict(String, Any(), help="""
      namespace in json form for evaluating blaze expression graph
      """)
      local = Bool(help="""
      Whether this data source is hosted by the bokeh server or not.
      """)
  
      def from_blaze(self, remote_blaze_obj, local=True):
          from blaze.server import to_tree
          # only one Client object, can hold many datasets
          assert len(remote_blaze_obj._leaves()) == 1
          leaf = remote_blaze_obj._leaves()[0]
          blaze_client = leaf.data
          json_expr = to_tree(remote_blaze_obj, {leaf : ':leaf'})
          self.data_url = blaze_client.url + "/compute.json"
          self.local = local
          self.expr = json_expr
  
      def to_blaze(self):
          from blaze.server.client import Client
          from blaze.server import from_tree
          from blaze import Data
          # hacky - blaze urls have `compute.json` in it, but we need to strip it off
          # to feed it into the blaze client lib
          c = Client(self.data_url.rsplit('compute.json', 1)[0])
          d = Data(c)
          return from_tree(self.expr, {':leaf' : d})
  
  
  class ServerDataSource(BlazeDataSource):
      """ A data source that referes to data located on a Bokeh server.
  
      The data from the server is loaded on-demand by the client.
      """
      # Paramters of data transformation operations
      # The 'Any' is used to pass primtives around.
      # TODO: (jc) Find/create a property type for 'any primitive/atomic value'
      transform = Dict(String,Either(Instance(PlotObject), Any), help="""
      Paramters of the data transformation operations.
  
      The associated valuse is minimally a tag that says which downsample routine
      to use.  For some downsamplers, parameters are passed this way too.
      """)
  