def __init__(self, datamodel=None, log_js_errors=True):
        # super
        super(RegularTableWidget, self).__init__()

        # install data model
        if datamodel is None:
            # Demo
            self.datamodel = TwoBillionRows()
        elif isinstance(datamodel, (DataModel, )):
            self.datamodel = datamodel
        elif isinstance(datamodel, np.ndarray):
            self.datamodel = NumpyDataModel(datamodel)
        elif isinstance(datamodel, pd.Series):
            self.datamodel = SeriesDataModel(datamodel)
        elif isinstance(datamodel, pd.DataFrame):
            self.datamodel = DataFrameDataModel(datamodel)
        else:
            raise Exception("Unsupported data model: {}".format(datamodel))

        # set self for draw callbacks
        self.datamodel._setWidget(self)

        # for click events
        self._click_handlers = CallbackDispatcher()

        # for edit events
        self._edit_handlers = CallbackDispatcher()

        # hook in custom messages
        self.on_msg(self._handle_custom_msg)

        # log js errors?
        self._log_js_errors = log_js_errors
Exemple #2
0
class JupyterFrontEnd(Widget):
    _model_name = Unicode("JupyterFrontEndModel").tag(sync=True)
    _model_module = Unicode(module_name).tag(sync=True)
    _model_module_version = Unicode(module_version).tag(sync=True)

    version = Unicode(read_only=True).tag(sync=True)
    shell = Instance(Shell).tag(sync=True, **widget_serialization)
    commands = Instance(CommandRegistry).tag(sync=True, **widget_serialization)
    sessions = Instance(SessionManager).tag(sync=True, **widget_serialization)

    def __init__(self, *args, **kwargs):
        super().__init__(*args,
                         shell=Shell(),
                         commands=CommandRegistry(),
                         sessions=SessionManager(),
                         **kwargs)
        self._ready_event = asyncio.Event()
        self._on_ready_callbacks = CallbackDispatcher()
        self.on_msg(self._on_frontend_msg)

    def _on_frontend_msg(self, _, content, buffers):
        if content.get("event", "") == "lab_ready":
            self._ready_event.set()
            self._on_ready_callbacks()

    async def ready(self):
        await self._ready_event.wait()

    def on_ready(self, callback, remove=False):
        self._on_ready_callbacks.register_callback(callback, remove)
Exemple #3
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args,
                      shell=Shell(),
                      commands=CommandRegistry(),
                      **kwargs)
     self._ready_event = asyncio.Event()
     self._on_ready_callbacks = CallbackDispatcher()
     self.on_msg(self._on_frontend_msg)
Exemple #4
0
class Event(CoreWidget):
    _model_name = Unicode('EventModel').tag(sync=True)
    _model_module = Unicode('ipyevents').tag(sync=True)
    source = InstanceDict(DOMWidget).tag(sync=True, **widget_serialization)
    watched_events = List().tag(sync=True)
    ignore_modifier_key_events = Bool(False).tag(sync=True)
    prevent_default_action = Bool(False).tag(sync=True)
    _supported_mouse_events = List([
        'click', 'auxclick', 'dblclick', 'mouseenter', 'mouseleave',
        'mousedown', 'mouseup', 'mousemove', 'wheel', 'contextmenu',
        'dragstart', 'drag', 'dragend', 'dragenter', 'dragover', 'dragleave',
        'drop'
    ]).tag(sync=True)
    _supported_key_events = List(['keydown', 'keyup']).tag(sync=True)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._dom_handlers = CallbackDispatcher()
        self.on_msg(self._handle_mouse_msg)

    @property
    def supported_key_events(self):
        return self._supported_key_events

    @property
    def supported_mouse_events(self):
        return self._supported_mouse_events

    @validate('watched_events')
    def _validate_watched_events(self, proposal):
        value = proposal['value']
        bad_events = [
            v for v in value if v not in self._supported_mouse_events +
            self._supported_key_events
        ]
        if bad_events:
            raise ValueError('The event(s) {} are not '
                             'supported.'.format(bad_events))
        return value

    def on_dom_event(self, callback, remove=False):
        """Register a callback to execute when a DOM event occurs.

        The callback will be called with one argument, an dict whose keys
        depend on the type of event.

        Parameters
        ----------
        remove: bool (optional)
            Set to true to remove the callback from the list of callbacks.
        """
        self._dom_handlers.register_callback(callback, remove=remove)

    def _handle_mouse_msg(self, _, content, buffers):
        self._dom_handlers(content)
Exemple #5
0
class DagreD3Widget(DOMWidget):
    _model_name = Unicode('DagreD3Model').tag(sync=True)
    _model_module = Unicode("ipydagred3").tag(sync=True)
    _model_module_version = Unicode("^" + __version__).tag(sync=True)
    _view_name = Unicode('DagreD3View').tag(sync=True)
    _view_module = Unicode("ipydagred3").tag(sync=True)
    _view_module_version = Unicode("^" + __version__).tag(sync=True)

    graph = Instance(Graph, args=(), kwargs={})
    _graph = Dict().tag(sync=True)

    def __init__(self, graph=None, *args, **kwargs):
        super(DagreD3Widget, self).__init__()

        if not isinstance(graph, Graph):
            graph = Graph(*args, **kwargs)
        self.graph = graph

        # set widget for callbacks
        self.graph._setWidget(self)

        # for click events
        self._click_handlers = CallbackDispatcher()
        self.on_msg(self._handle_click_msg)

    def on_click(self, callback, remove=False):
        self._click_handlers.register_callback(callback, remove=remove)

    def click(self, value):
        self._click_handlers(self, value)

    def _handle_click_msg(self, _, content, buffers):
        if content.get('event', '') == 'click':
            self.click(content.get('value', ''))

    @wraps(Graph.setGraph)
    def setGraph(self, *args, **kwargs):
        self.graph.setGraph(*args, **kwargs)

    @wraps(Graph.setNode)
    def setNode(self, *args, **kwargs):
        self.graph.setNode(*args, **kwargs)

    @wraps(Graph.setEdge)
    def setEdge(self, *args, **kwargs):
        self.graph.setEdge(*args, **kwargs)

    def post(self, msg):
        self.send(msg)
        self._graph = self.graph.to_dict()

    @observe('graph')
    def _observe_graph(self, change):
        self._graph = change['new'].to_dict()
Exemple #6
0
    def on(self, widget_type, event_type, callback, remove=False):
        """
        Register a callback to execute when the user interacts with the graph.

        Parameters
        ----------
        widget_type : str
            Specify the widget type to monitor. Pick from:
            - %s
        event_type : str
            Specify the type of event to monitor. See documentation on these
            event types on the cytoscape documentation homepage,
            (https://js.cytoscape.org/#events/user-input-device-events). Pick
            from:
            - %s
        callback : func
            Callback to run in the kernel when the user has an `event_type`
            interaction with any element of type `widget_type`. `callback`
            will be called with one argument: the JSON-dictionary of the target
            the user interacted with (which includes a `data` key for the
            user-provided data in the node).
        remove : bool, optional
            Set to true to remove the callback from the list of callbacks.
        """
        if widget_type not in self._interaction_handlers:
            self._interaction_handlers = dict(
                [
                    *self._interaction_handlers.items(),
                    (widget_type, {event_type: CallbackDispatcher()}),
                ]
            )
        elif event_type not in self._interaction_handlers[widget_type]:
            self._interaction_handlers = dict(
                [
                    *(
                        (wt, v)
                        for wt, v in self._interaction_handlers.items()
                        if wt != widget_type
                    ),
                    (
                        widget_type,
                        dict(
                            [
                                *self._interaction_handlers[widget_type].items(),
                                (event_type, CallbackDispatcher()),
                            ]
                        ),
                    ),
                ]
            )
        self._interaction_handlers[widget_type][event_type].register_callback(
            callback, remove=remove
        )
Exemple #7
0
    def __init__(self, dataframe, **kwargs):
        # Setting default index name if not explicitly
        # set by the user.
        if "index_name" in kwargs:
            self._index_name = kwargs["index_name"]
        else:
            self._index_name = None

        self.data = dataframe
        super().__init__(**kwargs)
        self._cell_click_handlers = CallbackDispatcher()
        self._cell_change_handlers = CallbackDispatcher()
        self.on_msg(self.__handle_custom_msg)
Exemple #8
0
    def __init__(self, graph=None, *args, **kwargs):
        super(DagreD3Widget, self).__init__()

        if not isinstance(graph, Graph):
            graph = Graph(*args, **kwargs)
        self.graph = graph

        # set widget for callbacks
        self.graph._setWidget(self)

        # for click events
        self._click_handlers = CallbackDispatcher()
        self.on_msg(self._handle_click_msg)
Exemple #9
0
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._submission_callbacks = CallbackDispatcher()
        self.on_msg(self._handle_string_msg)

        # Defining
        self.status = False
        self.pid, self.fd = pty.fork()

        term_thread = threading.Thread(target=self.thread_tty)
        term_thread.start()

        while not self.io_file:
            print('Waiting for io_file')
            time.sleep(1)
Exemple #10
0
    def __init__(self, **kwargs):
        super(DeckGLWidget, self).__init__(**kwargs)
        self._hover_handlers = CallbackDispatcher()
        self._click_handlers = CallbackDispatcher()
        self._resize_handlers = CallbackDispatcher()
        self._view_state_handlers = CallbackDispatcher()
        self.on_msg(self._handle_custom_msgs)

        self.handler_exception = None
        self.on_click(store_selection)
        self.selected_data = []
Exemple #11
0
class Filter(object):
    def __init__(self, func=None, disabled=False):
        self._disabled = disabled
        self._func = func
        self._dispatcher = CallbackDispatcher()

    def __call__(self, *args, **kwargs):
        return self._disabled or self._func(*args, **kwargs)

    def _notify(self):
        self._dispatcher()

    @property
    def func(self):
        return self._func

    @func.setter
    def func(self, f):
        if f != self._func:
            self._func = f
            self._notify()

    @property
    def disabled(self):
        return self._disabled

    @disabled.setter
    def disabled(self, value):
        if value != self._disabled:
            self._disabled = value
            self._notify()

    def register(self, cb):
        self._dispatcher.register_callback(cb)

    def unregister(self, cb):
        self._dispatcher.register_callback(cb, remove=True)
Exemple #12
0
 def __init__(self, **kwargs):
     super(Mark, self).__init__(**kwargs)
     self._hover_handlers = CallbackDispatcher()
     self._click_handlers = CallbackDispatcher()
     self._legend_click_handlers = CallbackDispatcher()
     self._legend_hover_handlers = CallbackDispatcher()
     self._element_click_handlers = CallbackDispatcher()
     self._bg_click_handlers = CallbackDispatcher()
     self.on_msg(self._handle_custom_msgs)
Exemple #13
0
class MarketMap(DOMWidget):

    """Waffle wrapped map.

    Attributes
    ----------
    names: numpy.ndarray of strings (default: [])
        The elements can also be objects convertible to string
        primary key for the map data. A rectangle is created for each
        unique entry in this array
    groups: numpy.ndarray (default: [])
        attribute on which the groupby is run. If this is an empty arrray, then
        there is no group by for the map.
    display_text: numpy.ndarray or None(default: None)
        data to be displayed on each rectangle of the map.If this is empty it
        defaults to the names attribute.
    ref_data: pandas.DataDrame or None (default: None)
        Additional data associated with each element of the map. The data in
        this data frame can be displayed as a tooltip.
    color: numpy.ndarray (default: [])
        Data to represent the color for each of the cells. If the value of the
        data is NaN for a cell, then the color of the cell is the color of the
        group it belongs to in absence of data for color
    scales: Dictionary of scales holding a scale for each data attribute
        If the map has data being passed as color, then a corresponding color
        scale is required
    axes: List of axes
        Ability to add an axis for the scales which are used to scale data
        represented in the map
    on_hover: custom event
        This event is received when the mouse is hovering over a cell. Returns
        the data of the cell and the ref_data associated with the cell.
    tooltip_widget: Instance of a widget
        Widget to be displayed as the tooltip. This can be combined with the
        on_hover event to display the chart corresponding to the cell being
        hovered on.
    tooltip_fields: list
        names of the fields from the ref_data dataframe which should be
        displayed in the tooltip.
    tooltip_formats: list
        formats for each of the fields for the tooltip data. Order should match
        the order of the tooltip_fields
    show_groups: bool
        attribute to determine if the groups should be displayed. If set to
        True, the finer elements are blurred

    Map Drawing Attributes
    cols: int
        Suggestion for no of columns in the map.If not specified, value is
        inferred from the no of rows and no of cells
    rows: int
        No of rows in the map.If not specified, value is inferred from the no
        of cells and no of columns.
        If both rows and columns are not specified, then a square is
        constructed basing on the no of cells.
        The above two attributes are suggestions which are respected unless
        they are not feasible. One required condition is that, the number of
        columns is odd when row_groups is greater than 1.
    row_groups: int
        No of groups the rows should be divided into. This can be used to draw
        more square cells for each of the groups

    Layout Attributes

    map_margin: dict (default: {top=50, bottom=50, left=50, right=50})
        Dictionary containing the top, bottom, left and right margins. The user
        is responsible for making sure that the width and height are greater
        than the sum of the margins.
    min_aspect_ratio: float
         minimum width / height ratio of the figure
    max_aspect_ratio: float
         maximum width / height ratio of the figure


    Display Attributes

    colors: list of colors
        Colors for each of the groups which are cycled over to cover all the
        groups
    title: string
        Title of the Market Map
    title_style: dict
        CSS style for the title of the Market Map
    stroke: color
        Stroke of each of the cells of the market map
    group_stroke: color
        Stroke of the border for the group of cells corresponding to a group
    selected_stroke: color
        stroke for the selected cells
    hovered_stroke: color
        stroke for the cell being hovered on
    font_style: dict
        CSS style for the text of each cell

    Other Attributes

    enable_select: bool
        boolean to control the ability to select the cells of the map by
        clicking
    enable_hover: bool
        boolean to control if the map should be aware of which cell is being
        hovered on. If it is set to False, tooltip will not be displayed

    Note
    ----

    The aspect ratios stand for width / height ratios.

     - If the available space is within bounds in terms of min and max aspect
       ratio, we use the entire available space.
     - If the available space is too oblong horizontally, we use the client
       height and the width that corresponds max_aspect_ratio (maximize width
       under the constraints).
     - If the available space is too oblong vertically, we use the client width
       and the height that corresponds to min_aspect_ratio (maximize height
       under the constraint).
       This corresponds to maximizing the area under the constraints.

    Default min and max aspect ratio are both equal to 16 / 9.
    """
    names = Array([]).tag(sync=True, **array_serialization)
    groups = Array([]).tag(sync=True, **array_serialization)
    display_text = Array(None, allow_none=True).tag(sync=True, **array_serialization)
    ref_data = DataFrame(None, allow_none=True).tag(sync=True, **dataframe_serialization).valid(dataframe_warn_indexname)
    title = Unicode().tag(sync=True)

    tooltip_fields = List().tag(sync=True)
    tooltip_formats = List().tag(sync=True)
    show_groups = Bool().tag(sync=True)

    cols = Int(allow_none=True).tag(sync=True)
    rows = Int(allow_none=True).tag(sync=True)

    row_groups = Int(1).tag(sync=True)
    colors = List(CATEGORY10).tag(sync=True)
    scales = Dict().tag(sync=True, **widget_serialization)
    axes = List().tag(sync=True, **widget_serialization)
    color = Array([]).tag(sync=True, **array_serialization)
    map_margin = Dict(dict(top=50, right=50, left=50, bottom=50)).tag(sync=True)

    layout = Instance(Layout, kw={
            'min_width': '125px'
        }, allow_none=True).tag(sync=True, **widget_serialization)
    min_aspect_ratio = Float(1.0).tag(sync=True)
    # Max aspect ratio is such that we can have 3 charts stacked vertically
    # on a 16:9 monitor: 16/9*3 ~ 5.333
    max_aspect_ratio = Float(6.0).tag(sync=True)

    stroke = Color('white').tag(sync=True)
    group_stroke = Color('black').tag(sync=True)
    selected_stroke = Color('dodgerblue', allow_none=True).tag(sync=True)
    hovered_stroke = Color('orangered', allow_none=True).tag(sync=True)
    font_style = Dict().tag(sync=True)
    title_style = Dict().tag(sync=True)

    selected = List().tag(sync=True)
    enable_hover = Bool(True).tag(sync=True)
    enable_select = Bool(True).tag(sync=True)
    tooltip_widget = Instance(DOMWidget, allow_none=True, default_value=None).tag(sync=True, **widget_serialization)

    def __init__(self, **kwargs):
        super(MarketMap, self).__init__(**kwargs)
        self._hover_handlers = CallbackDispatcher()
        self.on_msg(self._handle_custom_msgs)

    def on_hover(self, callback, remove=False):
        self._hover_handlers.register_callback(callback, remove=remove)

    def _handle_custom_msgs(self, _, content, buffers=None):
        if content.get('event', '') == 'hover':
            self._hover_handlers(self, content)

    def _compare(self, a, b):
        # Compare dataframes properly
        import pandas as pd
        if isinstance(a, pd.DataFrame) or isinstance(b, pd.DataFrame):
            return pd.DataFrame.equals(a,b)

        return super(MarketMap, self)._compare(a, b)

    _view_name = Unicode('MarketMap').tag(sync=True)
    _model_name = Unicode('MarketMapModel').tag(sync=True)
    _view_module = Unicode('bqplot').tag(sync=True)
    _model_module = Unicode('bqplot').tag(sync=True)
    _view_module_version = Unicode(__frontend_version__).tag(sync=True)
    _model_module_version = Unicode(__frontend_version__).tag(sync=True)
Exemple #14
0
class ElkDiagram(DOMWidget):
    """Jupyterlab widget for interacting with ELK diagrams
    """

    _model_name = T.Unicode("ELKModel").tag(sync=True)
    _model_module = T.Unicode(module_name).tag(sync=True)
    _model_module_version = T.Unicode(EXTENSION_SPEC_VERSION).tag(sync=True)
    _view_name = T.Unicode("ELKView").tag(sync=True)
    _view_module = T.Unicode(module_name).tag(sync=True)
    _view_module_version = T.Unicode(EXTENSION_SPEC_VERSION).tag(sync=True)

    value = Schema(ElkSchemaValidator).tag(sync=True)
    _mark_layout = T.Dict().tag(sync=True)
    selected = T.Tuple().tag(sync=True)
    hovered = T.Unicode(allow_none=True, default_value=None).tag(sync=True)

    # interaction = T.UseEnum(Interactions).tag(sync=True)

    def __init__(self, *value, **kwargs):
        if value:
            kwargs["value"] = value[0]
        super().__init__(**kwargs)
        self._click_handlers = CallbackDispatcher()
        self.on_msg(self._handle_click_msg)

    @T.default("value")
    def _default_value(self):
        return {"id": "root"}

    def on_click(self, callback, remove=False):
        """Register a callback to execute when the button is clicked.
        The callback will be called with one argument, the clicked button
        widget instance.
        Parameters
        ----------
        remove: bool (optional)
            Set to true to remove the callback from the list of callbacks.
        """
        self._click_handlers.register_callback(callback, remove=remove)

    def click(self, element_id):
        """Programmatically trigger a click event.
        This will call the callbacks registered to the clicked button
        widget instance.
        """
        self._click_handlers(self, element_id)

    def _handle_click_msg(self, _, content, buffers):
        """Handle a msg from the front-end.
        Parameters
        ----------
        content: dict
            Content of the msg.
        """
        if content.get("event", "") == "click":
            self.click(content.get("id", ""))

    def center(
        self,
        model_ids: List[str] = None,
        animate: bool = None,
        retain_zoom: bool = None,
    ):
        """Center Diagram View on specified model ids

        :param model_ids: [description], defaults to None
        :type model_ids: List[str], optional
        :type animate: bool, optional
        :type retain_zoom: bool, optional
        """
        self.send({
            "action": "center",
            "model_id": model_ids,
            "animate": True if animate is None else animate,
            "retain_zoom": False if retain_zoom is None else retain_zoom,
        })

    def fit(
        self,
        model_ids: List[str] = None,
        animate: bool = None,
        max_zoom: float = None,
        padding: float = None,
    ):
        """Pan/Zoom the Diagram View to focus on particular model ids
        """
        self.send({
            "action": "fit",
            "model_id": model_ids,
            "animate": True if animate is None else animate,
            "max_zoom": max_zoom,
            "padding": padding,
        })
Exemple #15
0
class Mark(Widget):

    """The base mark class.

    Traitlet mark attributes may be decorated with metadata.

    **Data Attribute Decoration**

    Data attributes are decorated with the following values:

    scaled: bool
        Indicates whether the considered attribute is a data attribute which
        must be associated with a scale in order to be taken into account.
    rtype: string
        Range type of the associated scale.
    atype: string
        Key in bqplot's axis registry of the recommended axis type to represent
        this scale. When not specified, the default is 'bqplot.Axis'.

    Attributes
    ----------
    display_name: string
        Holds a user-friendly name for the trait attribute.
    mark_types: dict (class-level attribute)
        A registry of existing mark types.
    scales: Dict of scales (default: {})
        A dictionary of scales holding scales for each data attribute.
        - If a mark holds a scaled attribute named 'x', the scales dictionary
        must have a corresponding scale for the key 'x'.
        - The scale's range type should be equal to the scaled attribute's
        range type (rtype).
    scales_metadata: Dict (default: {})
        A dictionary of dictionaries holding metadata on the way scales are
        used by the mark. For example, a linear scale may be used to count
        pixels horizontally or vertically. The content of this dictionnary
        may change dynamically. It is an instance-level attribute.
    preserve_domain: dict (default: {})
        Indicates if this mark affects the domain(s) of the specified scale(s).
        The keys of this dictionary are the same as the ones of the "scales"
        attribute, and values are boolean. If a key is missing, it is
        considered as False.
    display_legend: bool (default: False)
        Display toggle for the mark legend in the general figure legend
    labels: list of unicode strings (default: [])
        Labels of the items of the mark. This attribute has different meanings
        depending on the type of mark.
    apply_clip: bool (default: True)
        Indicates whether the items that are beyond the limits of the chart
        should be clipped.
    visible: bool (default: True)
        Visibility toggle for the mark.
    selected_style: dict (default: {})
        CSS style to be applied to selected items in the mark.
    unselected_style: dict (default: {})
        CSS style to be applied to items that are not selected in the mark,
        when a selection exists.
    selected: list of integers or None (default: None)
        Indices of the selected items in the mark.
    tooltip: DOMWidget or None (default: None)
        Widget to be displayed as tooltip when elements of the scatter are
        hovered on
    tooltip_style: Dictionary (default: {'opacity': 0.9})
        Styles to be applied to the tooltip widget
    enable_hover: Bool (default: True)
        Boolean attribute to control the hover interaction for the scatter. If
        this is false, the on_hover custom mssg is not sent back to the python
        side
    interactions: Dictionary (default: {'hover': 'tooltip'})
        Dictionary listing the different interactions for each mark. The key is
        the event which triggers the interaction and the value is the kind of
        interactions. Keys and values can only take strings from separate enums
        for each mark.
    tooltip_location : {'mouse', 'center'} (default: 'mouse')
        Enum specifying the location of the tooltip. 'mouse' places the tooltip
        at the location of the mouse when the tooltip is activated and 'center'
        places the tooltip at the center of the figure. If tooltip is linked to
        a click event, 'mouse' places the tooltip at the location of the click
        that triggered the tooltip to be visible.
    """
    mark_types = {}
    scales = Dict(trait=Instance(Scale)).tag(sync=True, **widget_serialization)
    scales_metadata = Dict().tag(sync=True)
    preserve_domain = Dict().tag(sync=True)
    display_legend = Bool().tag(sync=True, display_name='Display legend')
    labels = List(trait=Unicode()).tag(sync=True, display_name='Labels')
    apply_clip = Bool(True).tag(sync=True)
    visible = Bool(True).tag(sync=True)
    selected_style = Dict().tag(sync=True)
    unselected_style = Dict().tag(sync=True)
    selected = List(None, allow_none=True).tag(sync=True)

    enable_hover = Bool(True).tag(sync=True)
    tooltip = Instance(DOMWidget, allow_none=True, default_value=None).tag(sync=True, **widget_serialization)
    tooltip_style = Dict({'opacity': 0.9}).tag(sync=True)
    interactions = Dict({'hover': 'tooltip'}).tag(sync=True)
    tooltip_location = Enum(['mouse', 'center'], default_value='mouse').tag(sync=True)

    _model_name = Unicode('MarkModel').tag(sync=True)
    _model_module = Unicode('bqplot').tag(sync=True)
    _view_module = Unicode('bqplot').tag(sync=True)
    _ipython_display_ = None

    def _scales_validate(self, scales, scales_trait):
        """validates the dictionary of scales based on the mark's scaled
        attributes metadata. First checks for missing scale and then for
        'rtype' compatibility."""
        # Validate scales' 'rtype' versus data attribute 'rtype' decoration
        # At this stage it is already validated that all values in self.scales
        # are instances of Scale.
        for name in self.trait_names(scaled=True):
            trait = self.traits()[name]
            if name not in scales:
                # Check for missing scale
                if not trait.allow_none:
                    raise TraitError("Missing scale for data attribute %s." %
                                     name)
            else:
                # Check scale range type compatibility
                if scales[name].rtype != trait.get_metadata('rtype'):
                    raise TraitError("Range type mismatch for scale %s." %
                                     name)
        return scales

    def _selected_default(self):
        return None

    def __init__(self, **kwargs):
        super(Mark, self).__init__(**kwargs)
        self._hover_handlers = CallbackDispatcher()
        self._click_handlers = CallbackDispatcher()
        self._legend_click_handlers = CallbackDispatcher()
        self._legend_hover_handlers = CallbackDispatcher()
        self._element_click_handlers = CallbackDispatcher()
        self._bg_click_handlers = CallbackDispatcher()
        self.on_msg(self._handle_custom_msgs)

    def on_hover(self, callback, remove=False):
        self._hover_handlers.register_callback(callback, remove=remove)

    def on_click(self, callback, remove=False):
        self._click_handlers.register_callback(callback, remove=remove)

    def on_legend_click(self, callback, remove=False):
        self._legend_click_handlers.register_callback(callback, remove=remove)

    def on_legend_hover(self, callback, remove=False):
        self._legend_hover_handlers.register_callback(callback, remove=remove)

    def on_element_click(self, callback, remove=False):
        self._element_click_handlers.register_callback(callback, remove=remove)

    def on_background_click(self, callback, remove=False):
        self._bg_click_handlers.register_callback(callback, remove=remove)

    def _handle_custom_msgs(self, _, content, buffers=None):
        if content.get('event', '') == 'hover':
            self._hover_handlers(self, content)
        if content.get('event', '') == 'click':
            self._click_handlers(self, content)
        elif content.get('event', '') == 'legend_click':
            self._legend_click_handlers(self, content)
        elif content.get('event', '') == 'legend_hover':
            self._legend_hover_handlers(self, content)
        elif content.get('event', '') == 'element_click':
            self._element_click_handlers(self, content)
        elif content.get('event', '') == 'background_click':
            self._bg_click_handlers(self, content)
Exemple #16
0
class MarketMap(DOMWidget):

    """Waffle wrapped map.

    Attributes
    ----------
    names: numpy.ndarray of strings (default: [])
        The elements can also be objects convertible to string
        primary key for the map data. A rectangle is created for each
        unique entry in this array
    groups: numpy.ndarray (default: [])
        attribute on which the groupby is run. If this is an empty arrray, then
        there is no group by for the map.
    display_text: numpy.ndarray or None(default: None)
        data to be displayed on each rectangle of the map.If this is empty it
        defaults to the names attribute.
    ref_data: pandas.DataDrame or None (default: None)
        Additional data associated with each element of the map. The data in
        this data frame can be displayed as a tooltip.
    color: numpy.ndarray (default: [])
        Data to represent the color for each of the cells. If the value of the
        data is NaN for a cell, then the color of the cell is the color of the
        group it belongs to in absence of data for color
    scales: Dictionary of scales holding a scale for each data attribute
        If the map has data being passed as color, then a corresponding color
        scale is required
    axes: List of axes
        Ability to add an axis for the scales which are used to scale data
        represented in the map
    on_hover: custom event
        This event is received when the mouse is hovering over a cell. Returns
        the data of the cell and the ref_data associated with the cell.
    tooltip_widget: Instance of a widget
        Widget to be displayed as the tooltip. This can be combined with the
        on_hover event to display the chart corresponding to the cell being
        hovered on.
    tooltip_fields: list
        names of the fields from the ref_data dataframe which should be
        displayed in the tooltip.
    tooltip_formats: list
        formats for each of the fields for the tooltip data. Order should match
        the order of the tooltip_fields
    show_groups: bool
        attribute to determine if the groups should be displayed. If set to
        True, the finer elements are blurred

    Map Drawing Attributes
    cols: int
        Suggestion for no of columns in the map.If not specified, value is
        inferred from the no of rows and no of cells
    rows: int
        No of rows in the map.If not specified, value is inferred from the no
        of cells and no of columns.
        If both rows and columns are not specified, then a square is
        constructed basing on the no of cells.
        The above two attributes are suggestions which are respected unless
        they are not feasible. One required condition is that, the number of
        columns is odd when row_groups is greater than 1.
    row_groups: int
        No of groups the rows should be divided into. This can be used to draw
        more square cells for each of the groups

    Layout Attributes

    map_margin: dict (default: {top=50, bottom=50, left=50, right=50})
        Dictionary containing the top, bottom, left and right margins. The user
        is responsible for making sure that the width and height are greater
        than the sum of the margins.
    min_aspect_ratio: float
         minimum width / height ratio of the figure
    max_aspect_ratio: float
         maximum width / height ratio of the figure


    Display Attributes

    colors: list of colors
        Colors for each of the groups which are cycled over to cover all the
        groups
    title: string
        Title of the Market Map
    title_style: dict
        CSS style for the title of the Market Map
    stroke: color
        Stroke of each of the cells of the market map
    group_stroke: color
        Stroke of the border for the group of cells corresponding to a group
    selected_stroke: color
        stroke for the selected cells
    hovered_stroke: color
        stroke for the cell being hovered on
    font_style: dict
        CSS style for the text of each cell

    Other Attributes

    enable_select: bool
        boolean to control the ability to select the cells of the map by
        clicking
    enable_hover: bool
        boolean to control if the map should be aware of which cell is being
        hovered on. If it is set to False, tooltip will not be displayed

    Note
    ----

    The aspect ratios stand for width / height ratios.

     - If the available space is within bounds in terms of min and max aspect
       ratio, we use the entire available space.
     - If the available space is too oblong horizontally, we use the client
       height and the width that corresponds max_aspect_ratio (maximize width
       under the constraints).
     - If the available space is too oblong vertically, we use the client width
       and the height that corresponds to min_aspect_ratio (maximize height
       under the constraint).
       This corresponds to maximizing the area under the constraints.

    Default min and max aspect ratio are both equal to 16 / 9.
    """
    names = Array([]).tag(sync=True, **array_serialization)
    groups = Array([]).tag(sync=True, **array_serialization)
    display_text = Array(None, allow_none=True)\
        .tag(sync=True, **array_serialization)
    ref_data = DataFrame(None, allow_none=True)\
        .tag(sync=True, **dataframe_serialization)\
        .valid(dataframe_warn_indexname)
    title = Unicode().tag(sync=True)

    tooltip_fields = List().tag(sync=True)
    tooltip_formats = List().tag(sync=True)
    show_groups = Bool().tag(sync=True)

    cols = Int(allow_none=True).tag(sync=True)
    rows = Int(allow_none=True).tag(sync=True)

    row_groups = Int(1).tag(sync=True)
    colors = List(CATEGORY10).tag(sync=True)
    scales = Dict().tag(sync=True, **widget_serialization)
    axes = List().tag(sync=True, **widget_serialization)
    color = Array([]).tag(sync=True, **array_serialization)
    map_margin = Dict(dict(top=50, right=50, left=50, bottom=50))\
        .tag(sync=True)

    layout = LayoutTraitType(kw=dict(min_width='125px'))\
        .tag(sync=True, **widget_serialization)
    min_aspect_ratio = Float(1.0).tag(sync=True)
    # Max aspect ratio is such that we can have 3 charts stacked vertically
    # on a 16:9 monitor: 16/9*3 ~ 5.333
    max_aspect_ratio = Float(6.0).tag(sync=True)

    stroke = Color('white').tag(sync=True)
    group_stroke = Color('black').tag(sync=True)
    selected_stroke = Color('dodgerblue', allow_none=True).tag(sync=True)
    hovered_stroke = Color('orangered', allow_none=True).tag(sync=True)
    font_style = Dict().tag(sync=True)
    title_style = Dict().tag(sync=True)

    selected = List().tag(sync=True)
    enable_hover = Bool(True).tag(sync=True)
    enable_select = Bool(True).tag(sync=True)
    tooltip_widget = Instance(DOMWidget, allow_none=True, default_value=None)\
        .tag(sync=True, **widget_serialization)

    def __init__(self, **kwargs):
        super(MarketMap, self).__init__(**kwargs)
        self._hover_handlers = CallbackDispatcher()
        self.on_msg(self._handle_custom_msgs)

    def on_hover(self, callback, remove=False):
        self._hover_handlers.register_callback(callback, remove=remove)

    def _handle_custom_msgs(self, _, content, buffers=None):
        if content.get('event', '') == 'hover':
            self._hover_handlers(self, content)

    def _compare(self, a, b):
        # Compare dataframes properly
        import pandas as pd
        if isinstance(a, pd.DataFrame) or isinstance(b, pd.DataFrame):
            return pd.DataFrame.equals(a, b)

        return super(MarketMap, self)._compare(a, b)

    _view_name = Unicode('MarketMap').tag(sync=True)
    _model_name = Unicode('MarketMapModel').tag(sync=True)
    _view_module = Unicode('bqplot').tag(sync=True)
    _model_module = Unicode('bqplot').tag(sync=True)
    _view_module_version = Unicode(__frontend_version__).tag(sync=True)
    _model_module_version = Unicode(__frontend_version__).tag(sync=True)
Exemple #17
0
 def __init__(self, **kwargs):
     self._drag_end_handlers = CallbackDispatcher()
     super(Scatter, self).__init__(**kwargs)
Exemple #18
0
class Scatter(Mark):

    """Scatter mark.

    In the case of the Scatter mark, scales for 'x' and 'y' MUST be provided.
    The scales of other data attributes are optional. In the case where another
    data attribute than 'x' or 'y' is provided but the corresponding scale is
    missing, the data attribute is ignored.

    Attributes
    ----------
    icon: string (class-level attribute)
        Font-awesome icon for that mark
    name: string (class-level attribute)
        User-friendly name of the mark
    marker: {'circle', 'cross', 'diamond', 'square', 'triangle-down', 'triangle-up', 'arrow', 'rectangle', 'ellipse'}
        Marker shape
    default_colors: list of colors (default: ['DeepSkyBlue'])
        List of colors of the markers. If the list is shorter than the number
        of points, the colors are reused.
    stroke: Color or None (default: None)
        Stroke color of the marker
    stroke_width: Float (default: 1.5)
        Stroke width of the marker
    default_opacities: list of floats (default: [1.0])
        Default opacities of the markers. If the list is shorter than the number
        of points, the opacities are reused.
    default_skew: float (default: 0.5)
        Default skew of the marker.
        This number is validated to be between 0 and 1.
    default_size: nonnegative int (default: 64)
        Default marker size in pixel.
        If size data is provided with a scale, default_size stands for the
        maximal marker size (i.e. the maximum value for the 'size' scale range)
    names: numpy.ndarray (default: [])
        Labels for the points of the chart
    display_names: bool (default: True)
        Controls whether names are displayed for points in the scatter

    Data Attributes

    x: numpy.ndarray (default: [])
        abscissas of the data points (1d array)
    y: numpy.ndarray (default: [])
        ordinates of the data points (1d array)
    color: numpy.ndarray or None (default: [])
        color of the data points (1d array). Defaults to default_color when not
        provided or when a value is NaN
    opacity: numpy.ndarray or None (default: [])
        opacity of the data points (1d array). Defaults to default_opacity when
        not provided or when a value is NaN
    size: numpy.ndarray or None (default: [])
        size of the data points. Defaults to default_size when not provided or
        when a value is NaN
    skew: numpy.ndarray or None (default: [])
        skewness of the markers representing the data points. Defaults to
        default_skew when not provided or when a value is NaN
    rotation: numpy.ndarray or None (default: [])
        orientation of the markers representing the data points.
        The rotation scale's range is [0, 180]
        Defaults to 0 when not provided or when a value is NaN.

    Notes
    -----
    The fields which can be passed to the default tooltip are:
        All the data attributes
        index: index of the marker being hovered on
    The following are the events which can trigger interactions:
        click: left click of the mouse
        hover: mouse-over an element
    The following are the interactions which can be linked to the above events:
        tooltip: display tooltip
        add: add new points to the scatter (can only linked to click)
    """
    # Mark decoration
    icon = 'fa-cloud'
    name = 'Scatter'

    # Scaled attribtes
    x = NdArray().tag(sync=True, min_dim=1, max_dim=1, scaled=True,
                rtype='Number', atype='bqplot.Axis')
    y = NdArray().tag(sync=True, min_dim=1, max_dim=1,
                scaled=True, rtype='Number', atype='bqplot.Axis')
    color = NdArray(None, allow_none=True).tag(sync=True, scaled=True,
                    rtype='Color', atype='bqplot.ColorAxis', min_dim=1, max_dim=1)
    opacity = NdArray(None, allow_none=True).tag(sync=True, scaled=True,
                      rtype='Number', min_dim=1, max_dim=1)
    size = NdArray(None, allow_none=True).tag(sync=True, scaled=True,
                   rtype='Number', min_dim=1, max_dim=1)
    skew = NdArray(None, allow_none=True).tag(sync=True, scaled=True, rtype='Number',
                   min_dim=1, max_dim=1)
    rotation = NdArray(None, allow_none=True).tag(sync=True, scaled=True,
                       rtype='Number', min_dim=1, max_dim=1)
    hovered_style = Dict().tag(sync=True)
    unhovered_style = Dict().tag(sync=True)
    hovered_point = Int(None, allow_none=True).tag(sync=True)

    # Other attributes
    scales_metadata = Dict({
        'x': {'orientation': 'horizontal', 'dimension': 'x'},
        'y': {'orientation': 'vertical', 'dimension': 'y'},
        'color': {'dimension': 'color'},
        'size': {'dimension': 'size'},
        'opacity': {'dimension': 'opacity'}
    }).tag(sync=True)
    marker = Enum(['circle', 'cross', 'diamond', 'square', 'triangle-down',
                   'triangle-up', 'arrow', 'rectangle', 'ellipse'],
                  default_value='circle').tag(sync=True, display_name='Marker')
    default_colors = List(trait=Color(default_value=None, allow_none=True),
                          default_value=['DeepSkyBlue']).tag(sync=True,
                          display_name='Colors')
    stroke = Color(None, allow_none=True).tag(sync=True, display_name='Stroke color')
    stroke_width = Float(1.5).tag(sync=True, display_name='Stroke width')
    default_opacities = List(trait=Float(1.0, min=0, max=1, allow_none=True)).tag(sync=True, display_name='Opacities')
    default_skew = Float(0.5, min=0, max=1).tag(sync=True)
    default_size = Int(64).tag(sync=True, display_name='Default size')

    names = NdArray().tag(sync=True)
    display_names = Bool(True).tag(sync=True, display_name='Display names')
    fill = Bool(True).tag(sync=True)
    drag_color = Color(None, allow_none=True).tag(sync=True)
    names_unique = Bool(True).tag(sync=True)

    enable_move = Bool().tag(sync=True)
    enable_delete = Bool().tag(sync=True)
    restrict_x = Bool().tag(sync=True)
    restrict_y = Bool().tag(sync=True)
    update_on_move = Bool().tag(sync=True)

    def __init__(self, **kwargs):
        self._drag_start_handlers = CallbackDispatcher()
        self._drag_handlers = CallbackDispatcher()
        self._drag_end_handlers = CallbackDispatcher()
        super(Scatter, self).__init__(**kwargs)

    def on_drag_start(self, callback, remove=False):
        self._drag_start_handlers.register_callback(callback, remove=remove)

    def on_drag(self, callback, remove=False):
        self._drag_handlers.register_callback(callback, remove=remove)

    def on_drag_end(self, callback, remove=False):
        self._drag_end_handlers.register_callback(callback, remove=remove)

    def _handle_custom_msgs(self, _, content, buffers=None):
        event = content.get('event', '')

        if event == 'drag_start':
            self._drag_start_handlers(self, content)
        elif event == 'drag':
            self._drag_handlers(self, content)
        elif event == 'drag_end':
            self._drag_end_handlers(self, content)

        super(Scatter, self)._handle_custom_msgs(self, content)

    _view_name = Unicode('Scatter').tag(sync=True)
    _model_name = Unicode('ScatterModel').tag(sync=True)
Exemple #19
0
class MarketMap(DOMWidget):
    """Waffle wrapped map.

    Attributes
    ----------

    names: numpy.ndarray of strings or objects convertible to strings (default: [])
        primary key for the data of the map. One rectangle is created for each
        unique entry in this array
    groups: numpy.ndarray (default: [])
        attribute on which the groupby is run. If this is an empty arrray, then
        there is no group by for the map.
    display_text: numpy.ndarray (default: [])
        data to be displayed on each rectangle of the map.If this is empty it
        defaults to the names attribute.
    ref_data: PandasDataFrame
        Additional data associated with each element of the map. The data in
        this data frame can be displayed as a tooltip.
    color: numpy.ndarray (default: [])
        Data to represent the color for each of the cells. If the value of the
        data is NaN for a cell, then the color of the cell is the color of the
        group it belongs to in absence of data for color
    scales: Dictionary of , scales holding a scale for each data attribute
        If the map has data being passed as color, then a corresponding color
        scale is required
    axes: List of axes
        Ability to add an axis for the scales which are used to scale data
        represented in the map
    on_hover: custom event
        This event is received when the mouse is hovering over a cell. Returns
        the data of the cell and the ref_data associated with the cell.
    tooltip_widget: Instance of a widget
        Widget to be displayed as the tooltip. This can be combined with the
        on_hover event to display the chart corresponding to the cell being
        hovered on.
    tooltip_fields: list
        names of the fields from the ref_data dataframe which should be
        displayed in the tooltip.
    tooltip_formats: list
        formats for each of the fields for the tooltip data. Order should match
        the order of the tooltip_fields
    show_groups: bool
        attribute to determine if the groups should be displayed. If set to
        True, the finer elements are blurred

    Map Drawing Attributes

    map_width: int
        minimum width of the entire map
    map_height: int
        minimum height of the entire map
    map_margin: dict
        margin for the market map plot area with respect to the entire display
        area
    preserve_aspect: bool
        boolean to control if the aspect ratio should be preserved or not
        during a resize
    cols: int
        Suggestion for no of columns in the map.If not specified, value is
        inferred from the no of rows and no of cells
    rows: int
        No of rows in the map.If not specified, value is inferred from the no
        of cells and no of columns.
        If both rows and columns are not specified, then a square is
        constructed basing on the no of cells.
        The above two attributes are suggestions which are respected unless
        they are not feasible. One required condition is that, the number of
        columns is odd when row_groups is greater than 1.
    row_groups: int
        No of groups the rows should be divided into. This can be used to draw
        more square cells for each of the groups

    Display Attributes

    colors: list of colors
        colors for each of the groups which are cycled over to cover all the
        groups
    stroke: color
        Stroke of each of the cells of the market map
    group_stroke: color
        Stroke of the border for the group of cells corresponding to a group
    selected_stroke: color
        stroke for the selected cells
    hovered_stroke: color
        stroke for the cell being hovered on

    Other Attributes

    enable_select: bool
        boolean to control the ability to select the cells of the map by
        clicking
    enable_hover: bool
        boolean to control if the map should be aware of which cell is being
        hovered on. If it is set to False, tooltip will not be displayed
    """
    map_width = Int(1080, sync=True)
    map_height = Int(800, sync=True)

    names = NdArray(sync=True)
    groups = NdArray(sync=True)
    display_text = NdArray(sync=True)
    ref_data = PandasDataFrame(sync=True)

    tooltip_fields = List(sync=True)
    tooltip_formats = List(sync=True)
    show_groups = Bool(False, sync=True)

    cols = Int(sync=True, allow_none=True)
    rows = Int(sync=True, allow_none=True)

    row_groups = Int(1, sync=True)
    colors = List(CATEGORY10, sync=True)
    scales = Dict(sync=True, allow_none=True, **widget_serialization)
    axes = List(sync=True, allow_none=True, **widget_serialization)
    color = NdArray(sync=True)
    map_margin = Dict(dict(top=50, right=50, left=50, bottom=50), sync=True)
    preserve_aspect = Bool(False,
                           sync=True,
                           display_name='Preserve aspect ratio')

    stroke = Unicode('white', sync=True)
    group_stroke = Unicode('black', sync=True)
    selected_stroke = Unicode('dodgerblue', sync=True)
    hovered_stroke = Unicode('orangered', sync=True)

    selected = List(sync=True)
    enable_hover = Bool(True, sync=True)
    enable_select = Bool(True, sync=True)
    tooltip_widget = Instance(DOMWidget,
                              allow_none=True,
                              sync=True,
                              **widget_serialization)

    def __init__(self, **kwargs):
        super(MarketMap, self).__init__(**kwargs)
        self._hover_handlers = CallbackDispatcher()
        self.on_msg(self._handle_custom_msgs)

    def on_hover(self, callback, remove=False):
        self._hover_handlers.register_callback(callback, remove=remove)

    def _handle_custom_msgs(self, _, content, buffers=None):
        if content.get('event', '') == 'hover':
            self._hover_handlers(self, content)

    _view_name = Unicode('MarketMap', sync=True)
    _view_module = Unicode('nbextensions/bqplot/MarketMap', sync=True)
    _model_name = Unicode('MarketMapModel', sync=True)
    _model_module = Unicode('nbextensions/bqplot/MarketMapModel', sync=True)
Exemple #20
0
class DataGrid(DOMWidget):
    """A Grid Widget with filter, sort and selection capabilities.

    Attributes
    ----------
    base_row_size : int (default: 20)
        Default row height
    base_column_size : int (default: 64)
        Default column width
    base_row_header_size : int (default: 64)
        Default row header width
    base_column_header_size : int (default: 20)
        Default column header height
    header_visibility : {'all', 'row', 'column', 'none'} (default: 'all')
        Header visibility mode
        'all': both row and column headers visible
        'row': only row headers visible
        'column': only column headers visible
        'none': neither row and column headers visible
    dataframe : pandas dataframe
        Data to display on Data Grid.
    renderers : dict
        Custom renderers to use for cell rendering. Keys of dictionary specify
        column name, and value specifies the renderer
    default_renderer : CellRenderer (default: TextRenderer)
        Default renderer to use for cell rendering
    header_renderer : CellRenderer (default: TextRenderer)
        Renderer to use for header cell rendering
    corner_renderer : CellRenderer (default: TextRenderer)
        Renderer to use for corner header cell rendering
    selection_mode : {'row', 'column', 'cell', 'none'} (default: 'none')
        Selection mode used when user clicks on grid or makes selections
        programmatically.
        'row': Selecting a cell will select all the cells on the same row
        'column': Selecting a cell will select all the cells on the same column
        'cell': Individual cell selection
        'none': Selection disabled
    selections : list of dict
        List of all selections. Selections are represented as rectangular
        regions. Rectangles are defined as dictionaries with keys:
        'r1': start row, 'c1': start column, 'r2': end row, 'c2': end column.
        Start of rectangle is top-left corner and end is bottom-right corner
    editable : boolean (default: false)
        Boolean indicating whether cell grid can be directly edited
    column_widths : Dict of strings to int (default: {})
        Dict to specify custom column sizes
        The keys (strings) indicate the names of the columns
        The values (integers) indicate the widths
    auto_fit_columns : Bool (default: True)
        Specify whether column width should automatically be
        determined by the grid
    auto_fit_params : Dict. Specify column auto fit parameters.
        Supported parameters:
        1) area: where to resize column widths - 'row-header',
                'body' or 'all' (default)
        2) padding: add padding to resized column widths (15 pixels by default)
        3) numCols: cap the number of columns to be resized (None)
    grid_style : Dict of {propertyName: string | VegaExpr | Dict}
        Dict to specify global grid styles.
        The keys (strings) indicate the styling property
        The values (css color properties or Vega Expression) indicate the values
        See below for all supported styling properties
    index_name : str (default: "key")
        String to specify the index column name. **Only set when the grid
        is constructed and is not an observable traitlet**

    Accessors (not observable traitlets)
    ---------
    selected_cells : list of dict
        List of selected cells. Each cell is represented as a dictionary
        with keys 'r': row and 'c': column
    selected_cell_values : list
        List of values for all selected cells.
    selected_cell_iterator : iterator
        An iterator to traverse selected cells one by one.

    Supported styling properties:
        void_color : color of the area where the grid is not painted
            on the canvas
        background_color : background color for all body cells
        row_background_color : row-wise background color (can take
            a string or Vega Expression)
        column_background_color : column-wise background color (can take a
            string of Vega Expression)
        grid_line_color : color of both vertical and horizontal grid lines
        vertical_grid_line_color : vertical grid line color
        horizontal_grid_line_color : horizontal grid line color
        header_background_color : background color for all non-body cells
            (index and columns)
        header_grid_line_color : grid line color for all non-body
            cells (index and columns)
        header_vertical_grid_line_color : vertical grid line color
            for all non-body cells
        header_horizontal_grid_line_color : horizontal grid line color
            for all non-body cells
        selection_fill_color : fill color of selected area
        selection_border_color : border color of selected area
        header_selection_fill_color : fill color of headers intersecting with
            selected area at column or row
        header_selection_border_color : border color of headers
            intersecting with selected area at column or row
        cursor_fill_color : fill color of cursor
        cursor_border_color : border color of cursor
        scroll_shadow : Dict of color parameters for scroll shadow (vertical and
            horizontal). Takes three paramaters:
            size : size of shadow in pixels
            color1 : gradient color 1
            color2 : gradient color 2
            color3 : gradient color 3
    """

    _model_name = Unicode("DataGridModel").tag(sync=True)
    _model_module = Unicode(module_name).tag(sync=True)
    _model_module_version = Unicode(module_version).tag(sync=True)
    _view_name = Unicode("DataGridView").tag(sync=True)
    _view_module = Unicode(module_name).tag(sync=True)
    _view_module_version = Unicode(module_version).tag(sync=True)

    base_row_size = Int(20).tag(sync=True)
    base_column_size = Int(64).tag(sync=True)
    base_row_header_size = Int(64).tag(sync=True)
    base_column_header_size = Int(20).tag(sync=True)

    header_visibility = Enum(default_value="all",
                             values=["all", "row", "column",
                                     "none"]).tag(sync=True)

    _transforms = List(Dict()).tag(sync=True, **widget_serialization)
    _visible_rows = List(Int()).tag(sync=True)
    _data = Dict().tag(sync=True, **_data_serialization)

    renderers = Dict(Instance(CellRenderer)).tag(sync=True,
                                                 **widget_serialization)
    default_renderer = Instance(CellRenderer).tag(sync=True,
                                                  **widget_serialization)
    header_renderer = Instance(CellRenderer,
                               allow_none=True).tag(sync=True,
                                                    **widget_serialization)
    corner_renderer = Instance(CellRenderer,
                               allow_none=True).tag(sync=True,
                                                    **widget_serialization)
    selection_mode = Enum(default_value="none",
                          values=["row", "column", "cell",
                                  "none"]).tag(sync=True)
    selections = List(Dict()).tag(sync=True, **widget_serialization)
    editable = Bool(False).tag(sync=True)
    column_widths = Dict({}).tag(sync=True)
    grid_style = Dict(allow_none=True).tag(sync=True, **widget_serialization)
    auto_fit_columns = Bool(False).tag(sync=True)
    auto_fit_params = Dict({
        "area": "all",
        "padding": 30,
        "numCols": None
    },
                           allow_none=False).tag(sync=True,
                                                 **widget_serialization)

    def __init__(self, dataframe, **kwargs):
        # Setting default index name if not explicitly
        # set by the user.
        if "index_name" in kwargs:
            self._index_name = kwargs["index_name"]
        else:
            self._index_name = None

        self.data = dataframe
        super().__init__(**kwargs)
        self._cell_click_handlers = CallbackDispatcher()
        self._cell_change_handlers = CallbackDispatcher()
        self.on_msg(self.__handle_custom_msg)

    def __handle_custom_msg(self, _, content, buffers):  # noqa: U101,U100
        if content["event_type"] == "cell-changed":
            row = content["row"]
            column = self._column_index_to_name(self._data,
                                                content["column_index"])
            value = content["value"]
            # update data on kernel
            self._data["data"][row][column] = value
            # notify python listeners
            self._cell_change_handlers({
                "row": row,
                "column": column,
                "column_index": content["column_index"],
                "value": value,
            })
        elif content["event_type"] == "cell-click":
            # notify python listeners
            self._cell_click_handlers({
                "region":
                content["region"],
                "column":
                content["column"],
                "column_index":
                content["column_index"],
                "row":
                content["row"],
                "primary_key_row":
                content["primary_key_row"],
                "cell_value":
                content["cell_value"],
            })

    @property
    def data(self):
        trimmed_primary_key = self._data["schema"]["primaryKey"][:-1]
        df = pd.DataFrame(self._data["data"])
        final_df = df.set_index(trimmed_primary_key)
        final_df = final_df[final_df.columns[:-1]]
        return final_df

    @staticmethod
    def generate_data_object(dataframe,
                             guid_key="ipydguuid",
                             index_name="key"):
        dataframe[guid_key] = pd.RangeIndex(0, dataframe.shape[0])

        # Renaming default index name from 'index' to 'key' on
        # single index DataFrames. This allows users to use
        # 'index' as a column name. If 'key' exists, we add _x
        # suffix to id, where { x | 0 <= x < inf }
        if not isinstance(dataframe.index, pd.MultiIndex):
            if index_name in dataframe.columns:
                index = 0
                new_index_name = f"{index_name}_{index}"
                while new_index_name in dataframe.columns:
                    index += 1
                    new_index_name = f"{index_name}_{index}"
                dataframe = dataframe.rename_axis(new_index_name)
            else:
                dataframe = dataframe.rename_axis(index_name)

        schema = pd.io.json.build_table_schema(dataframe)
        reset_index_dataframe = dataframe.reset_index()
        data = reset_index_dataframe.to_dict(orient="records")

        # Check for multiple primary keys
        key = reset_index_dataframe.columns[:dataframe.index.nlevels].tolist()

        num_index_levels = len(key) if isinstance(key, list) else 1

        # Check for nested columns in schema, if so, we need to update the
        # schema to represent the actual column name values
        if isinstance(schema["fields"][-1]["name"], tuple):
            num_column_levels = len(dataframe.columns.levels)
            primary_key = key.copy()

            for i in range(num_index_levels):
                new_name = [""] * num_column_levels
                new_name[0] = schema["fields"][i]["name"]
                schema["fields"][i]["name"] = tuple(new_name)
                primary_key[i] = tuple(new_name)

            schema["primaryKey"] = primary_key
            uuid_pk = list(key[-1])
            uuid_pk[0] = guid_key
            schema["primaryKey"].append(tuple(uuid_pk))

        else:
            schema["primaryKey"] = key
            schema["primaryKey"].append(guid_key)

        schema["primaryKeyUuid"] = guid_key

        return {
            "data": data,
            "schema": schema,
            "fields": [{
                field["name"]: None
            } for field in schema["fields"]],
        }

    @data.setter
    def data(self, dataframe):
        # Reference for the original frame column and index names
        # This is used to when returning the view data model
        self.__dataframe_reference_index_names = dataframe.index.names
        self.__dataframe_reference_columns = dataframe.columns
        dataframe = dataframe.copy()

        # Primary key used
        index_key = self.get_dataframe_index(dataframe)

        self._data = self.generate_data_object(dataframe, "ipydguuid",
                                               index_key)

    def get_dataframe_index(self, dataframe):
        """Returns a primary key to be used in ipydatagrid's
        view of the passed DataFrame"""

        # Passed index_name takes highest priority
        if self._index_name is not None:
            return self._index_name

        # Dataframe with names index used by default
        if dataframe.index.name is not None:
            return dataframe.index.name

        # If no index_name param, nor named-index DataFrame
        # have been passed, revert to default "key"
        return "key"

    def get_cell_value(self, column_name, primary_key_value):
        """Gets the value for a single or multiple cells by column name and index name.

        Tuples should be used to index into multi-index columns."""
        row_indices = self._get_row_index_of_primary_key(primary_key_value)
        return [self._data["data"][row][column_name] for row in row_indices]

    def set_cell_value(self, column_name, primary_key_value, new_value):
        """Sets the value for a single cell by column name and primary key.

        Note: This method returns a boolean to indicate if the operation
        was successful.
        """
        row_indices = self._get_row_index_of_primary_key(primary_key_value)
        # Bail early if key could not be found
        if not row_indices:
            return False

        # Iterate over all indices
        outcome = True
        for row_index in row_indices:
            has_column = column_name in self._data["data"][row_index]
            if has_column and row_index is not None:
                self._data["data"][row_index][column_name] = new_value
                self._notify_cell_change(row_index, column_name, new_value)
            else:
                outcome = False
        return outcome

    def get_cell_value_by_index(self, column_name, row_index):
        """Gets the value for a single cell by column name and row index."""
        return self._data["data"][row_index][column_name]

    def set_cell_value_by_index(self, column_name, row_index, new_value):
        """Sets the value for a single cell by column name and row index.

        Note: This method returns a boolean to indicate if the operation
        was successful.
        """
        has_column = column_name in self._data["data"][row_index]
        if has_column and 0 <= row_index < len(self._data["data"]):
            self._data["data"][row_index][column_name] = new_value
            self._notify_cell_change(row_index, column_name, new_value)
            return True
        return False

    def _notify_cell_change(self, row, column, value):
        column_index = self._column_name_to_index(column)
        # notify python listeners
        self._cell_change_handlers({
            "row": row,
            "column": column,
            "column_index": column_index,
            "value": value,
        })
        # notify front-end
        self.comm.send(
            data={
                "method": "custom",
                "content": {
                    "event_type": "cell-changed",
                    "row": row,
                    "column": column,
                    "column_index": column_index,
                    "value": value,
                },
            })

    def get_visible_data(self):
        """Returns a dataframe of the current View."""
        data = deepcopy(self._data)
        if self._visible_rows:
            data["data"] = [data["data"][i] for i in self._visible_rows]

        at = self._data["schema"]["primaryKey"]
        return_df = pd.DataFrame(data["data"]).set_index(at)
        return_df.index = return_df.index.droplevel(return_df.index.nlevels -
                                                    1)
        return_df.index.names = self.__dataframe_reference_index_names
        return_df.columns = self.__dataframe_reference_columns
        return return_df

    def transform(self, transforms):
        """Apply a list of transformation to this DataGrid."""
        # TODO: Validate this input, or let it fail on view side?
        self._transforms = transforms

    def revert(self):
        """Revert all transformations."""
        self._transforms = []

    @default("default_renderer")
    def _default_renderer(self):
        return TextRenderer()

    def clear_selection(self):
        """Clears all selections."""
        self.selections.clear()
        self.send_state("selections")

    def select(self,
               row1,
               column1,
               row2=None,
               column2=None,
               clear_mode="none"):
        """
        Select an individual cell or rectangular cell region.
        Parameters
        ----------
        row1 : int
            Row index for individual cell selection or
            start row index for rectangular region selection.
        column1 : int
            Column index for individual cell selection or
            start column index for rectangular region selection.
        row2 : int or None, optional (default: None)
            End row index for rectangular region selection.
        column2 : int or None, optional (default: None)
            End column index for rectangular region selection.
        clear_mode : string, optional, {'all', 'current', 'none'}
                    (default: 'none')
            Clear mode to use when there are pre-existing selections.
            'all' removes all pre-existing selections
            'current' removes last pre-existing selection
            'none' keeps pre-existing selections
        """
        if row2 is None or column2 is None:
            row2, column2 = row1, column1

        if clear_mode == "all":
            self.selections.clear()
        elif clear_mode == "current" and len(self.selections) > 0:
            self.selections.pop()

        self.selections.append({
            "r1": min(row1, row2),
            "c1": min(column1, column2),
            "r2": max(row1, row2),
            "c2": max(column1, column2),
        })
        self.send_state("selections")

    @property
    def selected_cells(self):
        """
        List of selected cells. Each cell is represented as a dictionary
        with keys 'r': row and 'c': column
        """
        return SelectionHelper(self._data, self.selections,
                               self.selection_mode).all()

    @property
    def selected_cell_values(self):
        """
        List of values for all selected cells.
        """
        # Copy of the front-end data model
        view_data = self.get_visible_data()

        # Get primary key from dataframe
        index_key = self.get_dataframe_index(view_data)

        # Serielize to JSON table schema
        view_data_object = self.generate_data_object(view_data, "ipydguuid",
                                                     index_key)

        return SelectionHelper(view_data_object, self.selections,
                               self.selection_mode).all_values()

    @property
    def selected_cell_iterator(self):
        """
        An iterator to traverse selected cells one by one.
        """
        return SelectionHelper(self._data, self.selections,
                               self.selection_mode)

    @validate("selections")
    def _validate_selections(self, proposal):
        selections = proposal["value"]

        for rectangle in selections:
            r1 = min(rectangle["r1"], rectangle["r2"])
            c1 = min(rectangle["c1"], rectangle["c2"])
            r2 = max(rectangle["r1"], rectangle["r2"])
            c2 = max(rectangle["c1"], rectangle["c2"])
            rectangle["r1"] = r1
            rectangle["c1"] = c1
            rectangle["r2"] = r2
            rectangle["c2"] = c2

        return selections

    @validate("editable")
    def _validate_editable(self, proposal):
        value = proposal["value"]
        if value and self.selection_mode == "none":
            self.selection_mode = "cell"
        return value

    @validate("_transforms")
    def _validate_transforms(self, proposal):
        transforms = proposal["value"]
        field_len = len(self._data["schema"]["fields"])
        for transform in transforms:
            if transform["columnIndex"] > field_len:
                raise ValueError("Column index is out of bounds.")
        return transforms

    @validate("_data")
    def _validate_data(self, proposal):
        table_schema = proposal["value"]
        column_list = [f["name"] for f in table_schema["schema"]["fields"]]
        if len(column_list) != len(set(column_list)):
            msg = "The dataframe must not contain duplicate column names."
            raise ValueError(msg)
        return table_schema

    def on_cell_change(self, callback, remove=False):
        """Register a callback to execute when a cell value changed.

        The callback will be called with one argument, the dictionary
        containing cell information with keys
        "row", "column", "column_index", "value".

        Parameters
        ----------
        remove: bool (optional)
            Set to true to remove the callback from the list of callbacks.
        """
        self._cell_change_handlers.register_callback(callback, remove=remove)

    def on_cell_click(self, callback, remove=False):
        """Register a callback to execute when a cell is clicked.

        The callback will be called with one argument, the dictionary
        containing cell information with following keys:
          "region", "column", "column_index", "row", "primary_key_row",
          "cell_value"

        Parameters
        ----------
        remove: bool (optional)
            Set to true to remove the callback from the list of callbacks.
        """
        self._cell_click_handlers.register_callback(callback, remove=remove)

    @staticmethod
    def _column_index_to_name(data, column_index):
        if "schema" not in data or "fields" not in data["schema"]:
            return None
        col_headers = DataGrid._get_col_headers(data)
        return (None if len(col_headers) <= column_index else
                col_headers[column_index])

    @staticmethod
    def _get_col_headers(data):
        primary_keys = ([] if "primaryKey" not in data["schema"] else
                        data["schema"]["primaryKey"])
        col_headers = [
            field["name"] for field in data["schema"]["fields"]
            if field["name"] not in primary_keys
        ]
        return col_headers

    def _column_name_to_index(self, column_name):
        if "schema" not in self._data or "fields" not in self._data["schema"]:
            return None
        col_headers = self._get_col_headers(self._data)
        try:
            return col_headers.index(column_name)
        except ValueError:
            pass

    def _get_row_index_of_primary_key(self, value):
        value = value if isinstance(value, list) else [value]
        schema = self._data["schema"]
        key = schema["primaryKey"][:-1]  # Omitting ipydguuid
        if len(value) != len(key):
            raise ValueError(
                "The provided primary key value must be the same length "
                "as the primary key.")

        row_indices = [
            at for at, row in enumerate(self._data["data"])
            if all(row[key[j]] == value[j] for j in range(len(key)))
        ]
        return row_indices

    @staticmethod
    def _get_cell_value_by_numerical_index(data, column_index, row_index):
        """Gets the value for a single cell by column index and row index."""
        column = DataGrid._column_index_to_name(data, column_index)
        if column is None:
            return None
        return data["data"][row_index][column]
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self._click_handlers = CallbackDispatcher()
     self.on_msg(self._handle_button_msg)
Exemple #22
0
 def __init__(self, func=None, disabled=False):
     self._disabled = disabled
     self._func = func
     self._dispatcher = CallbackDispatcher()
Exemple #23
0
class Event(CoreWidget):
    _model_name = Unicode('EventModel').tag(sync=True)
    _model_module = Unicode('ipyevents').tag(sync=True)
    _model_module_version = Unicode(EXTENSION_SPEC_VERSION).tag(sync=True)
    source = InstanceDict(DOMWidget).tag(sync=True, **widget_serialization)
    watched_events = List().tag(sync=True)
    ignore_modifier_key_events = Bool(False).tag(sync=True)
    prevent_default_action = Bool(False).tag(sync=True)
    xy_coordinate_system = Unicode(allow_none=True,
                                   default=None).tag(sync=True)
    xy = List().tag(sync=True)
    _supported_mouse_events = List([
        'click', 'auxclick', 'dblclick', 'mouseenter', 'mouseleave',
        'mousedown', 'mouseup', 'mousemove', 'wheel', 'contextmenu',
        'dragstart', 'drag', 'dragend', 'dragenter', 'dragover', 'dragleave',
        'drop'
    ]).tag(sync=True)
    _supported_key_events = List(['keydown', 'keyup']).tag(sync=True)

    _xy_coordinate_system_allowed = [
        None,  # Not tracking mouse x/y
        'data',  # "natural" coordinates for the widget (e.g. image)
        'client',  # Relative to the visible part of the web page
        'offset',  # Relative to the padding edge of widget
        'page',  # Relative to the whole document
        'relative',  # Relative to the widget
        'screen'  # Relative to the screen
    ]

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._dom_handlers = CallbackDispatcher()
        self.on_msg(self._handle_mouse_msg)

    @property
    def supported_key_events(self):
        return self._supported_key_events

    @property
    def supported_mouse_events(self):
        return self._supported_mouse_events

    @validate('watched_events')
    def _validate_watched_events(self, proposal):
        value = proposal['value']
        supported_events = (self._supported_mouse_events +
                            self._supported_key_events)
        bad_events = [v for v in value if v not in supported_events]
        if bad_events:
            message = ('The event(s) {bad} are not supported. The supported '
                       'events are:\n {good}'.format(bad=bad_events,
                                                     good=supported_events))
            raise ValueError(message)
        return value

    @validate('xy_coordinate_system')
    def _xy_coordinate_system(self, proposal):
        value = proposal['value']
        if value not in self._xy_coordinate_system_allowed:
            message = ('The coordinates {bad} are not supported. The '
                       'supported coordinates are:'
                       '\n {good}'.format(
                           bad=value, good=self._xy_coordinate_system_allowed))
            raise ValueError(message)
        return value

    def on_dom_event(self, callback, remove=False):
        """Register a callback to execute when a DOM event occurs.

        The callback will be called with one argument, an dict whose keys
        depend on the type of event.

        Parameters
        ----------
        remove: bool (optional)
            Set to true to remove the callback from the list of callbacks.
        """
        self._dom_handlers.register_callback(callback, remove=remove)

    def reset_callbacks(self):
        """Remove any previously defined callback."""
        self._dom_handlers.callbacks.clear()

    def _handle_mouse_msg(self, _, content, buffers):
        self._dom_handlers(content)
Exemple #24
0
 def __init__(self, **kwargs):
     super().__init__(**kwargs)
     self._dom_handlers = CallbackDispatcher()
     self.on_msg(self._handle_mouse_msg)
Exemple #25
0
class Event(CoreWidget):
    """
    Add browser event handling to a jupyter widget.

    Parameters
    ----------

    source : ipywidgets-compatible widget
        The widget to be watched for events.

    watched_events : list
        List of the browser events to observe on the source.

    ignore_modifier_key_events : bool
        If ``True``, ignore key presses of modifier keys
        ('Shift', 'Control', 'Alt', 'Meta'). Useful when keys mouse events
        with modifiers are watched but you want ot ignore the modifiers by
        themselves. Default is ``False``.

    prevent_default_actions : bool
        If ``True``, do not carry out default action associated with browser
        event. One use is to prevent the browser's display of a context menu
        when right-clicking. Default is ``False``.

    xy_coordinate_system : str or ``None``
        If not ``None``, set the ``xy`` attribute to the current mouse
        position. Use `data` to get the coordinates in whatever is most
        "natural" for the widget (e.g. pixel location in an image). The
        full list of allowed coordinate systems is available through
        the ``supported_xy_coordinates`` attribute of the
        `~ipyevents.Event` widget.

    throttle_or_debounce : {``None``, 'throttle', 'debounce'}
        Method to use, if any, for limiting event rate. 'throttle is primarily
        useful for 'mousemove' and 'wheel' events. 'debounce' can be useful
        for limiting repeated key strokes or clicks. In a nutshell, throtttling
        sets a limit on the rate at which events will be passed while
        debouncing imposes a minimum time between events before a new event is
        passed. Default is ``None``.

    wait : int
        The wait time, in milliseconds, for throttling or debouncing.

    Properties
    ----------

    xy : tuple of int or float
        Location of mouse, only set if `~ipyevents.Event.xy_coordinate_system`
        is not ``None``.

    supported_key_events
        List of keyboard events that can be watched.

    supported_mouse_events
        List of mouse events that can be watched.

    supported_xy_coordinates
        List of supported xy coordinate systems that can be returned
        in `~ipyevents.Event.xy`.
    """
    _model_name = Unicode('EventModel').tag(sync=True)
    _model_module = Unicode('ipyevents').tag(sync=True)
    _model_module_version = Unicode(EXTENSION_SPEC_VERSION).tag(sync=True)
    source = InstanceDict(DOMWidget).tag(sync=True, **widget_serialization)
    watched_events = List().tag(sync=True)
    ignore_modifier_key_events = Bool(False).tag(sync=True)
    prevent_default_action = Bool(False).tag(sync=True)
    xy_coordinate_system = Unicode(allow_none=True).tag(sync=True,
                                                        default=None)
    xy = List().tag(sync=True)
    wait = Integer().tag(sync=True, default=0)
    throttle_or_debounce = Unicode(allow_none=True).tag(sync=True,
                                                        default=None)
    _supported_mouse_events = List([
        'click', 'auxclick', 'dblclick', 'mouseenter', 'mouseleave',
        'mousedown', 'mouseup', 'mousemove', 'wheel', 'contextmenu',
        'dragstart', 'drag', 'dragend', 'dragenter', 'dragover', 'dragleave',
        'drop'
    ]).tag(sync=True)
    _supported_key_events = List(['keydown', 'keyup']).tag(sync=True)

    _xy_coordinate_system_allowed = [
        None,  # Not tracking mouse x/y
        'data',  # "natural" coordinates for the widget (e.g. image)
        'client',  # Relative to the visible part of the web page
        'offset',  # Relative to the padding edge of widget
        'page',  # Relative to the whole document
        'relative',  # Relative to the widget
        'screen'  # Relative to the screen
    ]

    _throttle_debounce_allowed = [
        None,  # No throttling or debounce
        'throttle',  # Throttle the rate at which events are
        # passed from front end to back.
        'debounce'  # Debounce events, i.e. impose minimum delay before
        # triggering events from the front end to the back.
    ]

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._dom_handlers = CallbackDispatcher()
        self.on_msg(self._handle_mouse_msg)

    @property
    def supported_key_events(self):
        return self._supported_key_events

    @property
    def supported_mouse_events(self):
        return self._supported_mouse_events

    @property
    def supported_xy_coordinates(self):
        return self._xy_coordinate_system_allowed

    @validate('watched_events')
    def _validate_watched_events(self, proposal):
        value = proposal['value']
        supported_events = (self._supported_mouse_events +
                            self._supported_key_events)
        bad_events = [v for v in value if v not in supported_events]
        if bad_events:
            message = ('The event(s) {bad} are not supported. The supported '
                       'events are:\n {good}'.format(bad=bad_events,
                                                     good=supported_events))
            raise ValueError(message)
        return value

    @validate('xy_coordinate_system')
    def _xy_coordinate_system(self, proposal):
        value = proposal['value']
        if value not in self._xy_coordinate_system_allowed:
            message = ('The coordinates {bad} are not supported. The '
                       'supported coordinates are:'
                       '\n {good}'.format(
                           bad=value, good=self._xy_coordinate_system_allowed))
            raise ValueError(message)
        return value

    @validate('wait')
    def _validate_wait(self, proposal):
        value = proposal['value']
        if value < 0:
            message = ('wait must be set to a non-negative integer. ')
            raise ValueError(message)
        elif not self.throttle_or_debounce:
            self.throttle_or_debounce = 'throttle'

        return value

    @validate('throttle_or_debounce')
    def _validate_throttle_debounce(self, proposal):
        value = proposal['value']
        if value not in self._throttle_debounce_allowed:
            message = (
                'The event rate limiting method {bad} is not supported. '
                'The supported methods are:'
                '\n {good}'.format(bad=value,
                                   good=self._throttle_debounce_allowed))
            raise ValueError(message)
        return value

    def on_dom_event(self, callback, remove=False):
        """Register a callback to execute when a DOM event occurs.

        The callback will be called with one argument, an dict whose keys
        depend on the type of event.

        Parameters
        ----------
        remove: bool (optional)
            Set to true to remove the callback from the list of callbacks.
        """
        self._dom_handlers.register_callback(callback, remove=remove)

    def reset_callbacks(self):
        """Remove any previously defined callback."""
        self._dom_handlers.callbacks.clear()

    def _handle_mouse_msg(self, _, content, buffers):
        self._dom_handlers(content)
class NlDownloadLink(DOMWidget, CoreWidget):
    """A widget to download content as file with filename.


    Parameters
    ----------
    content: str
        content of the file as bytes
    filename: str
        file name
    mimetype: str
        text/csv by default
    description: str
        description for link
    tooltip: str
        tooltip to display when link hovered
    disabled: bool
        boolean value to indicate if the link is disabled
    """

    _view_name = Unicode("DownloadLinkView").tag(sync=True)
    _model_name = Unicode('DownloadLinkModel').tag(sync=True)
    _view_module = Unicode("neurolang-ipywidgets").tag(sync=True)
    _model_module = Unicode('neurolang-ipywidgets').tag(sync=True)

    _view_module_version = Unicode("0.1.0").tag(sync=True)
    _model_module_version = Unicode('^0.1.0').tag(sync=True)

    # Widget specific properties
    content = Bytes().tag(sync=True, **content_serialization)
    mimetype = Unicode("text/csv").tag(sync=True)
    filename = Unicode().tag(sync=True)
    description = Unicode().tag(sync=True)
    tooltip = Unicode("Download").tag(sync=True)
    disabled = Bool(False).tag(sync=True)

    # below lines are copied from button widget to handle click on the link

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._click_handlers = CallbackDispatcher()
        self.on_msg(self._handle_button_msg)

    # this is necessary when data is big and it content should not be set at when widget is initialized
    def on_click(self, callback, remove=False):
        """Register a callback to execute when the button is clicked.
        The callback will be called with one argument, the clicked button
        widget instance.
        Parameters
        ----------
        remove: bool (optional)
            Set to true to remove the callback from the list of callbacks.
        """
        self._click_handlers.register_callback(callback, remove=remove)

    def click(self):
        """Programmatically trigger a click event.
        This will call the callbacks registered to the clicked button
        widget instance.
        """
        self._click_handlers(self)

    def _handle_button_msg(self, _, content, buffers):
        """Handle a msg from the front-end.
        Parameters
        ----------
        content: dict
            Content of the msg.
        """
        if content.get('event', '') == 'click':
            self.click()
Exemple #27
0
 def __init__(self, *value, **kwargs):
     if value:
         kwargs["value"] = value[0]
     super().__init__(**kwargs)
     self._click_handlers = CallbackDispatcher()
     self.on_msg(self._handle_click_msg)
Exemple #28
0
 def __init__(self, **kwargs):
     super(MarketMap, self).__init__(**kwargs)
     self._hover_handlers = CallbackDispatcher()
     self.on_msg(self._handle_custom_msgs)
Exemple #29
0
class MarketMap(DOMWidget):

    """Class to generate a waffle wrapped map of the list of data provided.

    Attributes
    ----------
    names: numpy.ndarray of strings or objects convertible to strings (default: [])
        primary key for the data of the map. One rectangle is created for each
        unique entry in this array
    groups: numpy.ndarray (default: [])
        attribute on which the groupby is run. If this is an empty arrray, then
        there is no group by for the map.
    display_text: numpy.ndarray (default: [])
        data to be displayed on each rectangle of the map.If this is empty it
        defaults to the names attribute.
    ref_data: PandasDataFrame
        Additional data associated with each element of the map. The data in
        this data frame can be displayed as a tooltip.
    color: numpy.ndarray (default: [])
        Data to represent the color for each of the cells. If the value of the
        data is NaN for a cell, then the color of the cell is the color of the
        group it belongs to in absence of data for color
    scales: Dictionary of , scales holding a scale for each data attribute
        - If the map has data being passed as color, then a corresponding color
        scale is required
    axes: List of axes
        Ability to add an axis for the scales which are used to scale data
        represented in the map
    on_hover: custom event
        This event is received when the mouse is hovering over a cell. Returns
        the data of the cell and the ref_data associated with the cell.
    tooltip_widget: Instance of a widget
        Widget to be displayed as the tooltip. This can be combined with the
        on_hover event to display the chart corresponding to the cell being
        hovered on.
    tooltip_fields: list
        names of the fields from the ref_data dataframe which should be
        displayed in the tooltip.
    tooltip_formats: list
        formats for each of the fields for the tooltip data. Order should match
        the order of the tooltip_fields
    show_groups: bool
        attribute to determine if the groups should be displayed. If set to
        True, the finer elements are blurred

    Map Drawing Attributes
    ------------------
    map_width: int
        minimum width of the entire map
    map_height: int
        minimum height of the entire map
    map_margin: dict
        margin for the market map plot area with respect to the entire display
        area
    preserve_aspect: bool
        boolean to control if the aspect ratio should be preserved or not
        during a resize
    cols: int
        Suggestion for no of columns in the map.If not specified, value is
        inferred from the no of rows and no of cells
    rows: int
        No of rows in the map.If not specified, value is inferred from the no
        of cells and no of columns.
        If both rows and columns are not specified, then a square is
        constructed basing on the no of cells.
        The above two attributes are suggestions which are respected unless
        they are not feasible. One required condition is that, the number of
        columns is odd when row_groups is greater than 1.
    row_groups: int
        No of groups the rows should be divided into. This can be used to draw
        more square cells for each of the groups

    Display Attributes
    ------------------
    colors: list of colors
        colors for each of the groups which are cycled over to cover all the
        groups
    stroke: color
        Stroke of each of the cells of the market map
    group_stroke: color
        Stroke of the border for the group of cells corresponding to a group
    selected_stroke: color
        stroke for the selected cells
    hovered_stroke: color
        stroke for the cell being hovered on

    Other Attributes
    ----------------
    enable_select: bool
        boolean to control the ability to select the cells of the map by
        clicking
    enable_hover: bool
        boolean to control if the map should be aware of which cell is being
        hovered on. If it is set to False, tooltip will not be displayed
    """
    map_width = Int(1080, sync=True)
    map_height = Int(800, sync=True)

    names = NdArray(sync=True)
    groups = NdArray(sync=True)
    display_text = NdArray(sync=True)
    ref_data = PandasDataFrame(sync=True)

    tooltip_fields = List(sync=True)
    tooltip_formats = List(sync=True)
    show_groups = Bool(False, sync=True)

    cols = Int(sync=True, allow_none=True)
    rows = Int(sync=True, allow_none=True)

    row_groups = Int(1, sync=True)
    colors = List(CATEGORY10, sync=True)
    scales = Dict(sync=True, allow_none=True,
                  **widget_serialization)
    axes = List(sync=True, allow_none=True,
                **widget_serialization)
    color = NdArray(sync=True)
    map_margin = Dict(dict(top=50, right=50, left=50, bottom=50), sync=True)
    preserve_aspect = Bool(False, sync=True,
                           display_name='Preserve aspect ratio')

    stroke = Unicode('white', sync=True)
    group_stroke = Unicode('black', sync=True)
    selected_stroke = Unicode('dodgerblue', sync=True)
    hovered_stroke = Unicode('orangered', sync=True)

    selected = List(sync=True)
    enable_hover = Bool(True, sync=True)
    enable_select = Bool(True, sync=True)
    tooltip_widget = Instance(DOMWidget, allow_none=True, sync=True,
                              **widget_serialization)

    def __init__(self, **kwargs):
        super(MarketMap, self).__init__(**kwargs)
        self._hover_handlers = CallbackDispatcher()
        self.on_msg(self._handle_custom_msgs)

    def on_hover(self, callback, remove=False):
        self._hover_handlers.register_callback(callback, remove=remove)

    def _handle_custom_msgs(self, _, content, buffers=None):
        if content.get('event', '') == 'hover':
            self._hover_handlers(self, content)

    _view_name = Unicode('MarketMap', sync=True)
    _view_module = Unicode('nbextensions/bqplot/MarketMap', sync=True)
    _model_name = Unicode('MarketMapModel', sync=True)
    _model_module = Unicode('nbextensions/bqplot/MarketMapModel', sync=True)
Exemple #30
0
class DeckGLWidget(DOMWidget):
    """
    Jupyter environment widget that takes JSON and
    renders a deck.gl visualization based on provided properties.

    You may set a Mapbox API key as an environment variable to use Mapbox maps in your visualization

    Attributes
    ----------
        json_input : str, default ''
            JSON as a string meant for reading into deck.gl JSON API
        mapbox_key : str, default ''
            API key for Mapbox map tiles
        height : int, default 500
            Height of Jupyter notebook cell, in pixels
        width : int or str, default "100%"
            Width of Jupyter notebook cell, in pixels or, if a string, a CSS width
        tooltip : bool or dict of {str: str}, default True
            See the ``Deck`` constructor.
        google_maps_key : str, default ''
            API key for Google Maps
        selected_data : list of dict, default []
            Data selected on click, if the pydeck Jupyter widget is enabled for server use
    """

    _model_name = Unicode("JupyterTransportModel").tag(sync=True)
    _model_module = Unicode(module_name).tag(sync=True)
    _model_module_version = Unicode(module_version).tag(sync=True)
    _view_name = Unicode("JupyterTransportView").tag(sync=True)
    _view_module = Unicode(module_name).tag(sync=True)
    _view_module_version = Unicode(module_version).tag(sync=True)
    google_maps_key = Unicode("", allow_none=True).tag(sync=True)
    mapbox_key = Unicode("", allow_none=True).tag(sync=True)
    json_input = Unicode("").tag(sync=True)
    data_buffer = Any(default_value=None,
                      allow_none=True).tag(sync=True,
                                           **data_buffer_serialization)
    custom_libraries = Any(allow_none=True).tag(sync=True)
    tooltip = Any(True).tag(sync=True)
    height = Int(500).tag(sync=True)
    width = Any("100%").tag(sync=True)

    def __init__(self, **kwargs):
        super(DeckGLWidget, self).__init__(**kwargs)
        self._hover_handlers = CallbackDispatcher()
        self._click_handlers = CallbackDispatcher()
        self._resize_handlers = CallbackDispatcher()
        self._view_state_handlers = CallbackDispatcher()
        self.on_msg(self._handle_custom_msgs)

        self.handler_exception = None
        self.on_click(store_selection)
        self.selected_data = []

    def on_hover(self, callback, remove=False):
        self._hover_handlers.register_callback(callback, remove=remove)

    def on_resize(self, callback, remove=False):
        self._resize_handlers.register_callback(callback, remove=remove)

    def on_view_state_change(self,
                             callback,
                             debouce_seconds=0.2,
                             remove=False):
        callback = debounce(debouce_seconds)(
            callback) if debouce_seconds > 0 else callback
        self._view_state_handlers.register_callback(callback, remove=remove)

    def on_click(self, callback, remove=False):
        self._click_handlers.register_callback(callback, remove=remove)

    def _handle_custom_msgs(self, _, content, buffers=None):
        event_type = content.get('event', '')
        if event_type == 'hover':
            self._hover_handlers(self, content)
        elif event_type == 'resize':
            self._resize_handlers(self, content)
        elif event_type == 'view-state-change':
            self._view_state_handlers(self, content)
        elif event_type == 'click':
            self._click_handlers(self, content)
Exemple #31
0
class Mark(Widget):

    """The base mark class.

    Traitlet mark attributes may be decorated with metadata.

    **Data Attribute Decoration**

    Data attributes are decorated with the following values:

    scaled: bool
        Indicates whether the considered attribute is a data attribute which
        must be associated with a scale in order to be taken into account.
    rtype: string
        Range type of the associated scale.
    atype: string
        Key in bqplot's axis registry of the recommended axis type to represent
        this scale. When not specified, the default is 'bqplot.Axis'.

    Attributes
    ----------
    display_name: string
        Holds a user-friendly name for the trait attribute.
    mark_types: dict (class-level attribute)
        A registry of existing mark types.
    scales: Dict of scales (default: {})
        A dictionary of scales holding scales for each data attribute.
        - If a mark holds a scaled attribute named 'x', the scales dictionary
        must have a corresponding scale for the key 'x'.
        - The scale's range type should be equal to the scaled attribute's
        range type (rtype).
    scales_metadata: Dict (default: {})
        A dictionary of dictionaries holding metadata on the way scales are
        used by the mark. For example, a linear scale may be used to count
        pixels horizontally or vertically. The content of this dictionnary
        may change dynamically. It is an instance-level attribute.
    preserve_domain: dict (default: {})
        Indicates if this mark affects the domain(s) of the specified scale(s).
        The keys of this dictionary are the same as the ones of the "scales"
        attribute, and values are boolean. If a key is missing, it is
        considered as False.
    display_legend: bool (default: False)
        Display toggle for the mark legend in the general figure legend
    labels: list of unicode strings (default: [])
        Labels of the items of the mark. This attribute has different meanings
        depending on the type of mark.
    apply_clip: bool (default: True)
        Indicates whether the items that are beyond the limits of the chart
        should be clipped.
    visible: bool (default: True)
        Visibility toggle for the mark.
    selected_style: dict (default: {})
        CSS style to be applied to selected items in the mark.
    unselected_style: dict (default: {})
        CSS style to be applied to items that are not selected in the mark,
        when a selection exists.
    selected: list of integers or None (default: None)
        Indices of the selected items in the mark.
    tooltip: DOMWidget or None (default: None)
        Widget to be displayed as tooltip when elements of the scatter are
        hovered on
    tooltip_style: Dictionary (default: {'opacity': 0.9})
        Styles to be applied to the tooltip widget
    enable_hover: Bool (default: True)
        Boolean attribute to control the hover interaction for the scatter. If
        this is false, the on_hover custom mssg is not sent back to the python
        side
    interactions: Dictionary (default: {'hover': 'tooltip'})
        Dictionary listing the different interactions for each mark. The key is
        the event which triggers the interaction and the value is the kind of
        interactions. Keys and values can only take strings from separate enums
        for each mark.
    tooltip_location : {'mouse', 'center'} (default: 'mouse')
        Enum specifying the location of the tooltip. 'mouse' places the tooltip
        at the location of the mouse when the tooltip is activated and 'center'
        places the tooltip at the center of the figure. If tooltip is linked to
        a click event, 'mouse' places the tooltip at the location of the click
        that triggered the tooltip to be visible.
    """
    mark_types = {}
    scales = Dict(trait=Instance(Scale)).tag(sync=True, **widget_serialization)
    scales_metadata = Dict().tag(sync=True)
    preserve_domain = Dict().tag(sync=True)
    display_legend = Bool().tag(sync=True, display_name='Display legend')
    labels = List(trait=Unicode()).tag(sync=True, display_name='Labels')
    apply_clip = Bool(True).tag(sync=True)
    visible = Bool(True).tag(sync=True)
    selected_style = Dict().tag(sync=True)
    unselected_style = Dict().tag(sync=True)
    selected = List(None, allow_none=True).tag(sync=True)

    enable_hover = Bool(True).tag(sync=True)
    tooltip = Instance(DOMWidget, allow_none=True, default_value=None).tag(sync=True, **widget_serialization)
    tooltip_style = Dict({'opacity': 0.9}).tag(sync=True)
    interactions = Dict({'hover': 'tooltip'}).tag(sync=True)
    tooltip_location = Enum(['mouse', 'center'], default_value='mouse').tag(sync=True)

    _model_name = Unicode('MarkModel').tag(sync=True)
    _model_module = Unicode('bqplot').tag(sync=True)
    _view_module = Unicode('bqplot').tag(sync=True)
    _ipython_display_ = None

    def _get_dimension_scales(self, dimension, preserve_domain=False):
        """
        Return the list of scales corresponding to a given dimension.

        The preserve_domain optional argument specifies whether one should
        filter out the scales for which preserve_domain is set to True.
        """
        if preserve_domain:
            return [
                self.scales[k] for k in self.scales if (
                    k in self.scales_metadata
                    and self.scales_metadata[k].get('dimension') == dimension
                    and not self.preserve_domain.get(k)
                )
            ]
        else:
            return [
                self.scales[k] for k in self.scales if (
                    k in self.scales_metadata
                    and self.scales_metadata[k].get('dimension') == dimension
                )
            ]

    def _scales_validate(self, scales, scales_trait):
        """
        Validates the `scales` based on the mark's scaled attributes metadata.

        First checks for missing scale and then for 'rtype' compatibility.
        """
        # Validate scales' 'rtype' versus data attribute 'rtype' decoration
        # At this stage it is already validated that all values in self.scales
        # are instances of Scale.
        for name in self.trait_names(scaled=True):
            trait = self.traits()[name]
            if name not in scales:
                # Check for missing scale
                if not trait.allow_none:
                    raise TraitError("Missing scale for data attribute %s." %
                                     name)
            else:
                # Check scale range type compatibility
                if scales[name].rtype != trait.get_metadata('rtype'):
                    raise TraitError("Range type mismatch for scale %s." %
                                     name)
        return scales

    def _selected_default(self):
        return None

    def __init__(self, **kwargs):
        super(Mark, self).__init__(**kwargs)
        self._hover_handlers = CallbackDispatcher()
        self._click_handlers = CallbackDispatcher()
        self._legend_click_handlers = CallbackDispatcher()
        self._legend_hover_handlers = CallbackDispatcher()
        self._element_click_handlers = CallbackDispatcher()
        self._bg_click_handlers = CallbackDispatcher()
        self.on_msg(self._handle_custom_msgs)

    def on_hover(self, callback, remove=False):
        self._hover_handlers.register_callback(callback, remove=remove)

    def on_click(self, callback, remove=False):
        self._click_handlers.register_callback(callback, remove=remove)

    def on_legend_click(self, callback, remove=False):
        self._legend_click_handlers.register_callback(callback, remove=remove)

    def on_legend_hover(self, callback, remove=False):
        self._legend_hover_handlers.register_callback(callback, remove=remove)

    def on_element_click(self, callback, remove=False):
        self._element_click_handlers.register_callback(callback, remove=remove)

    def on_background_click(self, callback, remove=False):
        self._bg_click_handlers.register_callback(callback, remove=remove)

    def _handle_custom_msgs(self, _, content, buffers=None):
        if content.get('event', '') == 'hover':
            self._hover_handlers(self, content)
        if content.get('event', '') == 'click':
            self._click_handlers(self, content)
        elif content.get('event', '') == 'legend_click':
            self._legend_click_handlers(self, content)
        elif content.get('event', '') == 'legend_hover':
            self._legend_hover_handlers(self, content)
        elif content.get('event', '') == 'element_click':
            self._element_click_handlers(self, content)
        elif content.get('event', '') == 'background_click':
            self._bg_click_handlers(self, content)
class RegularTableWidget(DOMWidget):
    _model_name = Unicode("RegularTableModel").tag(sync=True)
    _model_module = Unicode("ipyregulartable").tag(sync=True)
    _model_module_version = Unicode("^" + __version__).tag(sync=True)
    _view_name = Unicode("RegularTableView").tag(sync=True)
    _view_module = Unicode("ipyregulartable").tag(sync=True)
    _view_module_version = Unicode("^" + __version__).tag(sync=True)

    datamodel = Instance(DataModel)

    height = Integer(default_value=250).tag(sync=True)

    css = Dict(default_value={}).tag(sync=True)
    styler = Dict(default_value={}).tag(sync=True)

    _data = Dict(default_value={}).tag(sync=True)
    _editable = Bool(default_value=False).tag(sync=True)

    def __init__(self, datamodel=None, log_js_errors=True):
        # super
        super(RegularTableWidget, self).__init__()

        # install data model
        if datamodel is None:
            # Demo
            self.datamodel = TwoBillionRows()
        elif isinstance(datamodel, (DataModel, )):
            self.datamodel = datamodel
        elif isinstance(datamodel, np.ndarray):
            self.datamodel = NumpyDataModel(datamodel)
        elif isinstance(datamodel, pd.Series):
            self.datamodel = SeriesDataModel(datamodel)
        elif isinstance(datamodel, pd.DataFrame):
            self.datamodel = DataFrameDataModel(datamodel)
        else:
            raise Exception("Unsupported data model: {}".format(datamodel))

        # set self for draw callbacks
        self.datamodel._setWidget(self)

        # for click events
        self._click_handlers = CallbackDispatcher()

        # for edit events
        self._edit_handlers = CallbackDispatcher()

        # hook in custom messages
        self.on_msg(self._handle_custom_msg)

        # log js errors?
        self._log_js_errors = log_js_errors

    def on_click(self, callback, remove=False):
        self._click_handlers.register_callback(callback, remove=remove)

    def on_edit(self, callback, remove=False):
        self._edit_handlers.register_callback(callback, remove=remove)

    def click(self, value):
        self._click_handlers(self, value)

    def edit(self, value):
        self._edit_handlers(self, value)

    @observe("datamodel")
    def _datamodel_changed(self, change):
        self.draw()

    def _jserrors(self, error):
        if error and self._log_js_errors:
            raise Exception(error)

    def _handle_custom_msg(self, content, buffers=None):
        if content.get("event", "") == "click":
            self.click(content.get("value", ""))

        elif content.get("event", "") == "dataslice":
            self.dataslice(*content.get("value", []))

        elif content.get("event", "") == "editable":
            self.editable(*content.get("value", []))

        elif content.get("event", "") == "write":
            self.datamodel.write(*content.get("value", []))
            self.edit(content.get("value", ""))

        elif content.get("event", "") == "errors":
            self._jserrors(content.get("value", ""))

    def dataslice(self, x0, y0, x1, y1):
        self._data = {
            "num_rows": self.datamodel.rows(),
            "num_columns": self.datamodel.columns(),
            "column_headers": self.datamodel.columnheaders(x0, y0, x1, y1),
            "row_headers": self.datamodel.rowheaders(x0, y0, x1, y1),
            "data": self.datamodel.dataslice(x0, y0, x1, y1),
        }
        self.post({"type": "data"})
        return self._data

    def editable(self, x, y):
        self._editable = self.datamodel.editable(x, y)
        self.post({"type": "editable"})
        return self._editable

    def post(self, msg):
        self.send(msg)

    def draw(self):
        self.send({"type": "draw"})

    def setData(self, data):
        self.datamodel.setData(data)
        self.draw()

    @validate("css")
    def _validate_css(self, proposal):
        proposal = proposal["value"]

        if not isinstance(proposal, dict):
            raise TraitError("css needs to be dict")

        for key in proposal.keys():
            if key not in _STYLER_KEYS:
                raise TraitError("Unrecognized key: {}".format(key))

        return proposal

    @validate("styler")
    def _validate_styler(self, proposal):
        proposal = proposal["value"]

        if not isinstance(proposal, dict):
            raise TraitError("styler needs to be dict")

        for key in proposal.keys():
            if key not in _STYLER_KEYS:
                raise TraitError("Unrecognized key: {}".format(key))
            if not isinstance(proposal[key], dict):
                raise TraitError("styler values need to be dict")
            if not list(proposal[key].keys()) == ["expression", "style"]:
                raise TraitError("Invalid trait: {}".format(proposal[key]))

        return proposal
Exemple #33
0
class Scatter(Mark):

    """Scatter mark.

    In the case of the Scatter mark, scales for 'x' and 'y' MUST be provided.
    The scales of other data attributes are optional. In the case where another
    data attribute than 'x' or 'y' is provided but the corresponding scale is
    missing, the data attribute is ignored.

    Attributes
    ----------
    icon: string (class-level attribute)
        Font-awesome icon for that mark
    name: string (class-level attribute)
        User-friendly name of the mark
    marker: {'circle', 'cross', 'diamond', 'square', 'triangle-down', 'triangle-up', 'arrow', 'rectangle', 'ellipse'}
        Marker shape
    default_colors: list of colors (default: ['DeepSkyBlue'])
        List of colors of the markers. If the list is shorter than the number
        of points, the colors are reused.
    stroke: Color or None (default: None)
        Stroke color of the marker
    stroke_width: Float (default: 1.5)
        Stroke width of the marker
    default_opacities: list of floats (default: [1.0])
        Default opacities of the markers. If the list is shorter than the number
        of points, the opacities are reused.
    default_skew: float (default: 0.5)
        Default skew of the marker.
        This number is validated to be between 0 and 1.
    default_size: nonnegative int (default: 64)
        Default marker size in pixel.
        If size data is provided with a scale, default_size stands for the
        maximal marker size (i.e. the maximum value for the 'size' scale range)
    names: numpy.ndarray (default: [])
        Labels for the points of the chart
    display_names: bool (default: True)
        Controls whether names are displayed for points in the scatter

    Data Attributes

    x: numpy.ndarray (default: [])
        abscissas of the data points (1d array)
    y: numpy.ndarray (default: [])
        ordinates of the data points (1d array)
    color: numpy.ndarray or None (default: [])
        color of the data points (1d array). Defaults to default_color when not
        provided or when a value is NaN
    opacity: numpy.ndarray or None (default: [])
        opacity of the data points (1d array). Defaults to default_opacity when
        not provided or when a value is NaN
    size: numpy.ndarray or None (default: [])
        size of the data points. Defaults to default_size when not provided or
        when a value is NaN
    skew: numpy.ndarray or None (default: [])
        skewness of the markers representing the data points. Defaults to
        default_skew when not provided or when a value is NaN
    rotation: numpy.ndarray or None (default: [])
        orientation of the markers representing the data points.
        The rotation scale's range is [0, 180]
        Defaults to 0 when not provided or when a value is NaN.

    Notes
    -----
    The fields which can be passed to the default tooltip are:
        All the data attributes
        index: index of the marker being hovered on
    The following are the events which can trigger interactions:
        click: left click of the mouse
        hover: mouse-over an element
    The following are the interactions which can be linked to the above events:
        tooltip: display tooltip
        add: add new points to the scatter (can only linked to click)
    """
    # Mark decoration
    icon = 'fa-cloud'
    name = 'Scatter'

    # Scaled attribtes
    x = NdArray().tag(sync=True, min_dim=1, max_dim=1, scaled=True,
                rtype='Number', atype='bqplot.Axis')
    y = NdArray().tag(sync=True, min_dim=1, max_dim=1,
                scaled=True, rtype='Number', atype='bqplot.Axis')
    color = NdArray(None, allow_none=True).tag(sync=True, scaled=True,
                    rtype='Color', atype='bqplot.ColorAxis', min_dim=1, max_dim=1)
    opacity = NdArray(None, allow_none=True).tag(sync=True, scaled=True,
                      rtype='Number', min_dim=1, max_dim=1)
    size = NdArray(None, allow_none=True).tag(sync=True, scaled=True,
                   rtype='Number', min_dim=1, max_dim=1)
    skew = NdArray(None, allow_none=True).tag(sync=True, scaled=True, rtype='Number',
                   min_dim=1, max_dim=1)
    rotation = NdArray(None, allow_none=True).tag(sync=True, scaled=True,
                       rtype='Number', min_dim=1, max_dim=1)

    # Other attributes
    scales_metadata = Dict({
        'x': {'orientation': 'horizontal', 'dimension': 'x'},
        'y': {'orientation': 'vertical', 'dimension': 'y'},
        'color': {'dimension': 'color'},
        'size': {'dimension': 'size'},
        'opacity': {'dimension': 'opacity'}
    }).tag(sync=True)
    marker = Enum(['circle', 'cross', 'diamond', 'square', 'triangle-down',
                   'triangle-up', 'arrow', 'rectangle', 'ellipse'],
                  default_value='circle').tag(sync=True, display_name='Marker')
    default_colors = List(trait=Color(default_value=None, allow_none=True),
                          default_value=['DeepSkyBlue']).tag(sync=True,
                          display_name='Colors')
    stroke = Color(None, allow_none=True).tag(sync=True, display_name='Stroke color')
    stroke_width = Float(1.5).tag(sync=True, display_name='Stroke width')
    default_opacities = List(trait=Float(1.0, min=0, max=1, allow_none=True)).tag(sync=True, display_name='Opacities')
    default_skew = Float(0.5, min=0, max=1).tag(sync=True)
    default_size = Int(64).tag(sync=True, display_name='Default size')

    names = NdArray().tag(sync=True)
    display_names = Bool(True).tag(sync=True, display_name='Display names')
    fill = Bool(True).tag(sync=True)
    drag_color = Color(None, allow_none=True).tag(sync=True)
    names_unique = Bool(True).tag(sync=True)

    enable_move = Bool().tag(sync=True)
    enable_delete = Bool().tag(sync=True)
    restrict_x = Bool().tag(sync=True)
    restrict_y = Bool().tag(sync=True)
    update_on_move = Bool().tag(sync=True)

    def __init__(self, **kwargs):
        self._drag_end_handlers = CallbackDispatcher()
        super(Scatter, self).__init__(**kwargs)

    def on_drag_end(self, callback, remove=False):
        self._drag_end_handlers.register_callback(callback, remove=remove)

    def _handle_custom_msgs(self, _, content, buffers=None):
        if content.get('event', '') == 'drag_end':
            self._drag_end_handlers(self, content)
        super(Scatter, self)._handle_custom_msgs(self, content)

    _view_name = Unicode('Scatter').tag(sync=True)
    _model_name = Unicode('ScatterModel').tag(sync=True)
Exemple #34
0
 def __init__(self, **kwargs):
     super(Scatter, self).__init__(**kwargs)
     self._drag_end_handlers = CallbackDispatcher()
     self.on_msg(self._handle_custom_msgs)
Exemple #35
0
 def __init__(self, **kwargs):
     super(MarketMap, self).__init__(**kwargs)
     self._hover_handlers = CallbackDispatcher()
     self.on_msg(self._handle_custom_msgs)
Exemple #36
0
 def __init__(self, **kwargs):
     self._drag_start_handlers = CallbackDispatcher()
     self._drag_handlers = CallbackDispatcher()
     self._drag_end_handlers = CallbackDispatcher()
     super(Scatter, self).__init__(**kwargs)
Exemple #37
0
class IPyXterm(DOMWidget):
    # Name of the widget view class in front-end
    _view_name = Unicode('IPyXtermView').tag(sync=True)
    # Name of the widget model class in front-end
    _model_name = Unicode('IPyXtermModel').tag(sync=True)
    # Name of the front-end module containing widget view
    _view_module = Unicode('jupyter-xterm-widget').tag(sync=True)
    # Name of the front-end module containing widget model
    _model_module = Unicode('jupyter-xterm-widget').tag(sync=True)
    # Version of the front-end module containing widget view
    _view_module_version = Unicode('^0.1.0').tag(sync=True)
    # Version of the front-end module containing widget model
    _model_module_version = Unicode('^0.1.0').tag(sync=True)

    # Widget specific property.
    # Widget properties are defined as traitlets. Any property tagged with `sync=True`
    # is automatically synced to the frontend *any* time it changes in Python.
    # It is synced back to Python from the frontend *any* time the model is touched.

    # Display Properties

    # State Properties
    status = Bool(False).tag(sync=True)
    pid = Int(0).tag(sync=True)
    fd = Int(0).tag(sync=True)
    io_file = Instance('_io.FileIO', allow_none=True).tag(sync=True)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._submission_callbacks = CallbackDispatcher()
        self.on_msg(self._handle_string_msg)

        # Defining
        self.status = False
        self.pid, self.fd = pty.fork()

        term_thread = threading.Thread(target=self.thread_tty)
        term_thread.start()

        while not self.io_file:
            print('Waiting for io_file')
            time.sleep(1)

        #if self.pid == pty.CHILD:
        #    os.execvp('bash', ['bash'])
        #else:
        #    term_thread = threading.Thread(target=self.thread_tty)
        #    term_thread.start()
        #tty.setraw(self.fd, termios.TCSANOW)
        #self.io_file = os.fdopen(self.fd, 'wb+', buffering=0)
        #flags = fcntl(self.io_file, F_GETFL)
        #fcntl(self.io_file, F_SETFL, flags | os.O_NONBLOCK)

    def thread_tty(self):
        if self.pid == pty.CHILD:
            os.execvp('bash', ['bash'])
        else:
            tty.setraw(self.fd, termios.TCSANOW)
            self.io_file = os.fdopen(self.fd, 'wb+', buffering=0)
            flags = fcntl(self.io_file, F_GETFL)
            fcntl(self.io_file, F_SETFL, flags | os.O_NONBLOCK)

    def _handle_string_msg(self, _, content, buffers):
        if content.get('event', '') == 'submit':
            self._submission_callbacks(self)

    def on_submit(self, callback, remove=False):
        self._submission_callbacks.register_callback(callback, remote=remove)

    def close(self):
        if not self.status:
            os.kill(self.pid, signal.SIGHUP)

    def __del__(self):
        self.close()

    #def __init__(self, **kwargs):
    #    super(HelloWorld, self).__init__(**kwargs)
    #
    #    self.closed = False
    #    self.pid, self.fd = pty.fork()
    #    if self.pid == pty.CHILD:
    #        os.execvp('bash', ['bash'])
    #    else:
    #        tty.setraw(self.fd, termios.TCSANOW)
    #        self.file = os.fdopen(self.fd, 'wb+', buffering=0)
    #        flags = fcntl(self.file, F_GETFL)
    #        fcntl(self.file, F_SETFL, flags | os.O_NONBLOCK)


#
#def transmit(self, data):
#    os.write(self.fd, base64.b64decode(data))
#    self.receive()
#
#def receive(self):
#    try:
#        data = os.read(self.fd, 8192)
#    except OSError:
#        data = b''
#    sys.stdout.write(base64.b64encode(data))
#
#def update_window_size(self, rows, cols):
#    TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
#    s = struct.pack('HHHH', rows, cols, 0, 0)
#    ioctl(self.fd, TIOCSWINSZ, s)
#    self.receive()
#
#def close(self):
#    if not self.closed:
#        os.kill(self.pid, signal.SIGHUP)
#
#def __del__(self):
#    self.close()
Exemple #38
0
class Scatter(Mark):

    """Scatter mark.

    In the case of the Scatter mark, scales for 'x' and 'y' MUST be provided.
    The scales of other data attributes are optional. In the case where another
    data attribute than 'x' or 'y' is provided but the corresponding scale is
    missing, the data attribute is ignored.

    Attributes
    ----------

    icon: string (class-level attribute)
        Font-awesome icon for that mark
    name: string (class-level attribute)
        User-friendly name of the mark
    marker: {'circle', 'cross', 'diamond', 'square', 'triangle-down', 'triangle-up', 'arrow', 'rectangle', 'ellipse'}
        Marker shape
    default_colors: list of colors (default: ['DeepSkyBlue'])
        List of colors of the markers. If the list is shorter than the number
        of points, the colors are reused.
    stroke: Color or None (default: None)
        Stroke color of the marker
    stroke_width: Float (default: 1.5)
        Stroke width of the marker
    default_opacities: list of floats (default: [1.0])
        Default opacities of the markers. If the list is shorter than the number
        of points, the opacities are reused.
    default_skew: float (default: 0.5)
        Default skew of the marker.
        This number is validated to be between 0 and 1.
    default_size: nonnegative int (default: 64)
        Default marker size in pixel.
        If size data is provided with a scale, default_size stands for the
        maximal marker size (i.e. the maximum value for the 'size' scale range)
    names: numpy.ndarray (default: [])
        Labels for the points of the chart
    display_names: bool (default: True)
        Controls whether names are displayed for points in the scatter

    Data Attributes

    x: numpy.ndarray (default: [])
        abscissas of the data points (1d array)
    y: numpy.ndarray (default: [])
        ordinates of the data points (1d array)
    color: numpy.ndarray or None (default: [])
        color of the data points (1d array). Defaults to default_color when not
        provided or when a value is NaN
    opacity: numpy.ndarray or None (default: [])
        opacity of the data points (1d array). Defaults to default_opacity when
        not provided or when a value is NaN
    size: numpy.ndarray or None (default: [])
        size of the data points. Defaults to default_size when not provided or
        when a value is NaN
    skew: numpy.ndarray or None (default: [])
        skewness of the markers representing the data points. Defaults to
        default_skew when not provided or when a value is NaN
    rotation: numpy.ndarray or None (default: [])
        orientation of the markers representing the data points.
        The rotation scale's range is [0, 180]
        Defaults to 0 when not provided or when a value is NaN.

    Notes
    -----

    The fields which can be passed to the default tooltip are:
        All the data attributes
        index: index of the marker being hovered on
    The following are the events which can trigger interactions:
        click: left click of the mouse
        hover: mouse-over an element
    The following are the interactions which can be linked to the above events:
        tooltip: display tooltip
        add: add new points to the scatter (can only linked to click)
    """

    # Mark decoration
    icon = "fa-cloud"
    name = "Scatter"

    # Scaled attribtes
    x = NdArray(sync=True, min_dim=1, max_dim=1, scaled=True, rtype="Number", atype="bqplot.Axis")
    y = NdArray(sync=True, min_dim=1, max_dim=1, scaled=True, rtype="Number", atype="bqplot.Axis")
    color = NdArray(
        None, allow_none=True, sync=True, scaled=True, rtype="Color", atype="bqplot.ColorAxis", min_dim=1, max_dim=1
    )
    opacity = NdArray(None, allow_none=True, sync=True, scaled=True, rtype="Number", min_dim=1, max_dim=1)
    size = NdArray(None, allow_none=True, sync=True, scaled=True, rtype="Number", min_dim=1, max_dim=1)
    skew = NdArray(None, allow_none=True, sync=True, scaled=True, rtype="Number", min_dim=1, max_dim=1)
    rotation = NdArray(None, allow_none=True, sync=True, scaled=True, rtype="Number", min_dim=1, max_dim=1)

    # Other attributes
    scales_metadata = Dict(
        {
            "x": {"orientation": "horizontal", "dimension": "x"},
            "y": {"orientation": "vertical", "dimension": "y"},
            "color": {"dimension": "color"},
            "size": {"dimension": "size"},
            "opacity": {"dimension": "opacity"},
        },
        sync=True,
    )
    marker = Enum(
        ["circle", "cross", "diamond", "square", "triangle-down", "triangle-up", "arrow", "rectangle", "ellipse"],
        default_value="circle",
        sync=True,
        display_name="Marker",
    )
    default_colors = List(
        trait=Color(default_value=None, allow_none=True),
        default_value=["DeepSkyBlue"],
        sync=True,
        display_name="Colors",
    )
    stroke = Color(None, allow_none=True, sync=True, display_name="Stroke color")
    stroke_width = Float(1.5, sync=True, display_name="Stroke width")
    default_opacities = List(
        trait=Float(default_value=1.0, min=0, max=1, allow_none=True), sync=True, display_name="Opacities"
    )
    default_skew = Float(default_value=0.5, min=0, max=1, sync=True)
    default_size = Int(64, sync=True, display_name="Default size")

    names = NdArray(sync=True)
    display_names = Bool(True, sync=True, display_name="Display names")
    fill = Bool(True, sync=True)
    drag_color = Color(None, allow_none=True, sync=True)
    names_unique = Bool(True, sync=True)

    enable_move = Bool(False, sync=True)
    enable_delete = Bool(False, sync=True)
    restrict_x = Bool(False, sync=True)
    restrict_y = Bool(False, sync=True)
    update_on_move = Bool(False, sync=True)

    def __init__(self, **kwargs):
        super(Scatter, self).__init__(**kwargs)
        self._drag_end_handlers = CallbackDispatcher()
        self.on_msg(self._handle_custom_msgs)

    def on_drag_end(self, callback, remove=False):
        self._drag_end_handlers.register_callback(callback, remove=remove)

    def _handle_custom_msgs(self, _, content, buffers=None):
        super(Scatter, self)._handle_custom_msgs(self, content)
        if content.get("event", "") == "drag_end":
            self._drag_end_handlers(self, content)

    _view_name = Unicode("Scatter", sync=True)
    _view_module = Unicode("nbextensions/bqplot/Scatter", sync=True)
    _model_name = Unicode("ScatterModel", sync=True)
    _model_module = Unicode("nbextensions/bqplot/ScatterModel", sync=True)
Exemple #39
0
 def __init__(self, **kwargs):
     super(Mark, self).__init__(**kwargs)
     self._hover_handlers = CallbackDispatcher()
     self._click_handlers = CallbackDispatcher()
     self._legend_click_handlers = CallbackDispatcher()
     self._legend_hover_handlers = CallbackDispatcher()
     self._element_click_handlers = CallbackDispatcher()
     self._bg_click_handlers = CallbackDispatcher()
     self.on_msg(self._handle_custom_msgs)