<commit_before>''' This module provides functions for embedding Bokeh plots in various
different ways.

There are a number of different combinations of options when embedding
Bokeh plots. The data for the plot can be contained in the document,
or on a Bokeh server, or in a sidecar JavaScript file. Likewise, BokehJS
may be inlined in the document, or loaded from CDN or a Bokeh server.

The functions in ``bokeh.embed`` provide functionality to embed in all
these different cases.

'''

from __future__ import absolute_import

from warnings import warn
import uuid

from .protocol import serialize_json
from .resources import Resources
from .templates import (
    AUTOLOAD, AUTOLOAD_SERVER, AUTOLOAD_STATIC, FILE,
    NOTEBOOK_DIV, PLOT_DIV, PLOT_JS, PLOT_SCRIPT, RESOURCES
)
from .util.string import encode_utf8

from .plot_object import PlotObject
from collections import Sequence
from six import string_types

def _wrap_in_function(code):
    # Indent and wrap Bokeh function def around
    code = "\n".join([ "    " + line for line in code.split("\n") ])
    return 'Bokeh.$(function() {\n%s\n});' % code


def components(plot_objects, resources=None):
    ''' Return HTML components to embed a Bokeh plot.

    The data for the plot is stored directly in the returned HTML.

    .. note:: The returned components assume that BokehJS resources
              are **already loaded**.

    Args:
        plot_objects (PlotObject|list|dict|tuple) :
        The |components| function takes either a single PlotObject, a list/tuple of
        PlotObjects, or a dictionary of keys and PlotObjects. Each returns
        a corresponding data structure of script and div pairs.

        The following illustrates how different input types correlate to outputs:

            components(plot)
            #=> (script, plot_div)

            components((plot_1, plot_2))
            #=> (script, (plot_1_div, plot_2_div))

            components({"Plot 1": plot_1, "Plot 2": plot_2})
            #=> (script, {"Plot 1": plot_1_div, "Plot 2": plot_2_div})

        An example can be found in examples/embed/embed_multiple.py

        resources : Deprecated argument

    Returns:
        (script, div[s]): UTF-8 encoded
    '''
    plot_objects = _check_components_input(plot_objects, resources)

    if isinstance(plot_objects, Sequence):
        all_models = []
        plots = []
        divs = []
        for idx, plot_object in enumerate(plot_objects):
            elementid = str(uuid.uuid4())
            _append_plot(all_models, plots, plot_object, elementid)
            divs = _append_div(elementid, divs)
        if len(divs) == 1:
            divs = divs[0]
        else:
            divs = tuple(divs)

    if isinstance(plot_objects, dict):
        all_models = []
        plots = []
        divs = {}
        for key in plot_objects.keys():
            elementid = str(uuid.uuid4())
            _append_plot(all_models, plots, plot_objects[key], elementid)
            divs = _append_div(elementid, divs, key)

    script = _get_script(all_models, plots)

    return encode_utf8(script), divs


def raw_components(plot_objects):
    ''' Return the javascript code and the plotinfo dictionary that can be used to embed a bokeh plot
    into an html template. Unlike the |components| method, this does not wrap the javascript or
    id in a <script> or <div> tag. The user must do this manually, allowing for complete customization
    on the html side.

    The plot_info for each plot is a dictionary with the following information:
        {
            'modelid':  'The plots id, which can be used in the Bokeh.index',
            'elementid': 'The css identifier the BokehJS will look for to target the plot',
            'modeltype': 'Plot',
        }

    If a local datasource is used, the data for the plot is stored directly in the returned javascript.

    Also see the |components| method.

    Args:
        plot_objects (PlotObject|list|dict|tuple) :
        The |raw_components| function takes either a single PlotObject, a list/tuple of
        PlotObjects, or a dictionary of keys and PlotObjects.

        The following illustrates how different input types correlate to outputs:

            components(plot)
            #=> (raw_script, plot_info)

            components((plot_1, plot_2))
            #=> (raw_script, (plot_1_info, plot_2_info))

            components({"Plot 1": plot_1, "Plot 2": plot_2})
            #=> (raw_script, {"Plot 1": plot_1_info, "Plot 2": plot_2_info})

    Returns:
        (script, plotid[s]): UTF-8 encoded
    '''
    plot_objects = _check_components_input(plot_objects)
    all_models = []
    plots = []

    if isinstance(plot_objects, Sequence):
        for idx, plot_object in enumerate(plot_objects):
            elementid = str(uuid.uuid4())
            _append_plot(all_models, plots, plot_object, elementid)
        if len(plots) == 1:
            plot_info = plots[0]
        else:
            plot_info = tuple(plots)

    if isinstance(plot_objects, dict):
        plot_info = {}
        for key in plot_objects.keys():
            elementid = str(uuid.uuid4())
            plot_info[key] = _append_plot(all_models, plots, plot_objects[key], elementid)

    js = _get_js(all_models, plots)

    return encode_utf8(js), plot_info


def _check_components_input(plot_objects, resources=None):
    from .document import Document
    if resources is not None:
        warn('Because the ``resources`` argument is no longer needed, '
             'it is deprecated and will be removed in'
             'a future version.', DeprecationWarning, stacklevel=2)

    input_type_valid = False

    # Check for single item
    if isinstance(plot_objects, (PlotObject, Document)):
        plot_objects = [plot_objects]

    # Check for sequence
    if isinstance(plot_objects, Sequence) and all(isinstance(x, (PlotObject, Document)) for x in plot_objects):
        input_type_valid = True

    if isinstance(plot_objects, dict) and \
         all(isinstance(x, string_types) for x in plot_objects.keys()) and \
         all(isinstance(x, (PlotObject, Document)) for x in plot_objects.values()):
        input_type_valid = True

    if not input_type_valid:
        raise ValueError('Input must be a PlotObject, a Sequence of PlotObjects, or a mapping of string to PlotObjects')

    return plot_objects


def _get_js(all_models, plots):
    js = PLOT_JS.render(
        all_models = serialize_json(all_models),
        plots = plots
    )
    return _wrap_in_function(js)


def _get_script(all_models, plots):
    js = _get_js(all_models, plots)
    script = PLOT_SCRIPT.render(
        plot_js = js,
    )
    return script

def _append_plot(all_models, plots, plot_object, elementid):
    ref = plot_object.ref
    all_models.extend(plot_object.dump())
    plot_info = {
        'modelid': ref["id"],
        'elementid': '#' + elementid,
        'modeltype': ref["type"]
    }
    plots.append(plot_info)
    return plot_info

def _append_div(elementid, divs=None, key=None):
    div = PLOT_DIV.render(
        elementid = elementid
    )
    if isinstance(divs, list):
        divs.append(encode_utf8(div))
        return divs
    elif isinstance(divs, dict):
        divs[key] = encode_utf8(div)
        return divs
    else:
        return encode_utf8(div)

def notebook_div(plot_object):
    ''' Return HTML for a div that will display a Bokeh plot in an
    IPython Notebook

    The data for the plot is stored directly in the returned HTML.

    Args:
        plot_object (PlotObject) : Bokeh object to render
            typically a Plot or PlotContext

    Returns:
        div : UTF-8 encoded HTML text

    .. note::
        Assumes ``bokeh.load_notebook()`` or the equivalent has already
        been executed.
<commit_msg>Dry out raw_components and components<commit_after>''' This module provides functions for embedding Bokeh plots in various
different ways.

There are a number of different combinations of options when embedding
Bokeh plots. The data for the plot can be contained in the document,
or on a Bokeh server, or in a sidecar JavaScript file. Likewise, BokehJS
may be inlined in the document, or loaded from CDN or a Bokeh server.

The functions in ``bokeh.embed`` provide functionality to embed in all
these different cases.

'''

from __future__ import absolute_import

from warnings import warn
import uuid

from .protocol import serialize_json
from .resources import Resources
from .templates import (
    AUTOLOAD, AUTOLOAD_SERVER, AUTOLOAD_STATIC, FILE,
    NOTEBOOK_DIV, PLOT_DIV, PLOT_JS, PLOT_SCRIPT, RESOURCES
)
from .util.string import encode_utf8

from .plot_object import PlotObject
from collections import Sequence
from six import string_types


def _wrap_in_function(code):
    # Indent and wrap Bokeh function def around
    code = "\n".join(["    " + line for line in code.split("\n")])
    return 'Bokeh.$(function() {\n%s\n});' % code


def components(plot_objects, resources=None):
    ''' Return HTML components to embed a Bokeh plot.

    The data for the plot is stored directly in the returned HTML.

    .. note:: The returned components assume that BokehJS resources
              are **already loaded**.

    Args:
        plot_objects (PlotObject|list|dict|tuple) :
        The |components| function takes either a single PlotObject, a list/tuple of
        PlotObjects, or a dictionary of keys and PlotObjects. Each returns
        a corresponding data structure of script and div pairs.

        The following illustrates how different input types correlate to outputs:

            components(plot)
            #=> (script, plot_div)

            components((plot_1, plot_2))
            #=> (script, (plot_1_div, plot_2_div))

            components({"Plot 1": plot_1, "Plot 2": plot_2})
            #=> (script, {"Plot 1": plot_1_div, "Plot 2": plot_2_div})

        An example can be found in examples/embed/embed_multiple.py

        resources : Deprecated argument

    Returns:
        (script, div[s]): UTF-8 encoded
    '''
    all_models, plots, plot_info, divs = build_components(plot_objects, resources)
    script = _get_script(all_models, plots)
    return encode_utf8(script), divs


def raw_components(plot_objects):
    ''' Return the javascript code and the plotinfo dictionary that can be used to embed a bokeh plot
    into an html template. Unlike the |components| method, this does not wrap the javascript or
    id in a <script> or <div> tag. The user must do this manually, allowing for complete customization
    on the html side.

    The plot_info for each plot is a dictionary with the following information:
        {
            'modelid':  'The plots id, which can be used in the Bokeh.index',
            'elementid': 'The css identifier the BokehJS will look for to target the plot',
            'modeltype': 'Plot',
        }

    If a local datasource is used, the data for the plot is stored directly in the returned javascript.

    Also see the |components| method.

    Args:
        plot_objects (PlotObject|list|dict|tuple) :
        The |raw_components| function takes either a single PlotObject, a list/tuple of
        PlotObjects, or a dictionary of keys and PlotObjects.

        The following illustrates how different input types correlate to outputs:

            components(plot)
            #=> (raw_script, plot_info)

            components((plot_1, plot_2))
            #=> (raw_script, (plot_1_info, plot_2_info))

            components({"Plot 1": plot_1, "Plot 2": plot_2})
            #=> (raw_script, {"Plot 1": plot_1_info, "Plot 2": plot_2_info})

    Returns:
        (script, plotid[s]): UTF-8 encoded
    '''
    all_models, plots, plot_info, divs = build_components(plot_objects)
    js = _get_js(all_models, plots)
    return encode_utf8(js), plot_info


def build_components(plot_objects, resources=None):
    plot_objects = _check_components_input(plot_objects, resources)

    all_models = []
    plots = []

    if isinstance(plot_objects, Sequence):
        divs = []
        for idx, plot_object in enumerate(plot_objects):
            elementid = str(uuid.uuid4())
            _append_plot(all_models, plots, plot_object, elementid)
            divs = _append_div(elementid, divs)
        if len(divs) == 1:
            divs = divs[0]
            plot_info = plots[0]
        else:
            divs = tuple(divs)
            plot_info = tuple(plots)

    if isinstance(plot_objects, dict):
        divs = {}
        plot_info = {}
        for key in plot_objects.keys():
            elementid = str(uuid.uuid4())
            plot_info[key] = _append_plot(all_models, plots, plot_objects[key], elementid)
            divs = _append_div(elementid, divs, key)

    return all_models, plots, plot_info, divs


def _check_components_input(plot_objects, resources=None):
    from .document import Document
    if resources is not None:
        warn('Because the ``resources`` argument is no longer needed, '
             'it is deprecated and will be removed in'
             'a future version.', DeprecationWarning, stacklevel=2)

    input_type_valid = False

    # Check for single item
    if isinstance(plot_objects, (PlotObject, Document)):
        plot_objects = [plot_objects]

    # Check for sequence
    if isinstance(plot_objects, Sequence) and all(isinstance(x, (PlotObject, Document)) for x in plot_objects):
        input_type_valid = True

    if isinstance(plot_objects, dict) and \
       all(isinstance(x, string_types) for x in plot_objects.keys()) and \
       all(isinstance(x, (PlotObject, Document)) for x in plot_objects.values()):
        input_type_valid = True

    if not input_type_valid:
        raise ValueError('Input must be a PlotObject, a Sequence of PlotObjects, or a mapping of string to PlotObjects')

    return plot_objects


def _get_js(all_models, plots):
    js = PLOT_JS.render(
        all_models=serialize_json(all_models),
        plots=plots
    )
    return _wrap_in_function(js)


def _get_script(all_models, plots):
    js = _get_js(all_models, plots)
    script = PLOT_SCRIPT.render(
        plot_js=js,
    )
    return script


def _append_plot(all_models, plots, plot_object, elementid):
    ref = plot_object.ref
    all_models.extend(plot_object.dump())
    plot_info = {
        'modelid': ref["id"],
        'elementid': '#' + elementid,
        'modeltype': ref["type"]
    }
    plots.append(plot_info)
    return plot_info


def _append_div(elementid, divs=None, key=None):
    div = PLOT_DIV.render(
        elementid=elementid
    )
    if isinstance(divs, list):
        divs.append(encode_utf8(div))
        return divs
    elif isinstance(divs, dict):
        divs[key] = encode_utf8(div)
        return divs
    else:
        return encode_utf8(div)


def notebook_div(plot_object):
    ''' Return HTML for a div that will display a Bokeh plot in an
    IPython Notebook

    The data for the plot is stored directly in the returned HTML.

    Args:
        plot_object (PlotObject) : Bokeh object to render
            typically a Plot or PlotContext

    Returns:
        div : UTF-8 encoded HTML text

    .. note::
        Assumes ``bokeh.load_notebook()`` or the equivalent has already
        been executed.

{'fraction_non_alphanumeric': 0.0850088414434475, 'fraction_numerical': 0.005304866068504814, 'mean_word_length': 2.8213213213213213, 'pattern_counts': {'":': 16, '<': 7, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5472323', 'n_tokens_mistral': 4593, 'n_tokens_neox': 4354, 'n_words': 1500}