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
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)
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)
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)
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()
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 )
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 __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 __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)
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 = []
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)
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)
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)
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, })
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)
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)
def __init__(self, **kwargs): self._drag_end_handlers = CallbackDispatcher() super(Scatter, self).__init__(**kwargs)
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)
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)
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)
def __init__(self, func=None, disabled=False): self._disabled = disabled self._func = func self._dispatcher = CallbackDispatcher()
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)
def __init__(self, **kwargs): super().__init__(**kwargs) self._dom_handlers = CallbackDispatcher() self.on_msg(self._handle_mouse_msg)
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()
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)
def __init__(self, **kwargs): super(MarketMap, self).__init__(**kwargs) self._hover_handlers = CallbackDispatcher() self.on_msg(self._handle_custom_msgs)
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)
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)
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
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)
def __init__(self, **kwargs): super(Scatter, self).__init__(**kwargs) self._drag_end_handlers = CallbackDispatcher() self.on_msg(self._handle_custom_msgs)
def __init__(self, **kwargs): self._drag_start_handlers = CallbackDispatcher() self._drag_handlers = CallbackDispatcher() self._drag_end_handlers = CallbackDispatcher() super(Scatter, self).__init__(**kwargs)
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()
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)