Source code for vaex.jupyter
# -*- coding: utf-8 -*-
import os
import logging
import time
from .utils import debounced, flush, gather, kernel_tick, interactive_selection, interactive_cleanup # noqa
import vaex
import IPython.display
base_path = os.path.dirname(__file__)
logger = logging.getLogger("vaex.jupyter")
def _add_toolbar(viz):
from .widgets import ToolsToolbar, tools_items_default
from traitlets import link
interact_items = [k for k in tools_items_default if k['value'] in viz.TOOLS_SUPPORTED]
toolbar = ToolsToolbar(supports_transforms=viz.supports_transforms,
supports_normalize=viz.supports_normalize,
interact_items=interact_items)
viz.children = [toolbar, ] + viz.children
link((viz, 'tool'), (toolbar, 'interact_value'))
link((viz, 'transform'), (toolbar, 'transform_value'))
link((viz, 'normalize'), (toolbar, 'normalize'))
link((viz, 'selection_mode'), (toolbar, 'selection_mode'))
return toolbar
[docs]class DataFrameAccessorWidget(object):
[docs] def __init__(self, df):
self.df = df
import vaex.jupyter.grid
self.grid = vaex.jupyter.model.GridCalculator(df, [])
self._last_grid = None
[docs] @debounced(delay_seconds=0.1, reentrant=False)
async def execute_debounced(self):
"""Schedules an execution of dataframe tasks in the near future (debounced)."""
try:
logger.debug("Execute tasks... tasks=%r", self.df.executor.tasks)
await self.df.execute_async()
logger.debug("Execute tasks done")
except vaex.execution.UserAbort:
pass # this is fine
except Exception:
logger.exception("Error while executing tasks")
def clear(self):
self.grid = vaex.jupyter.model.GridCalculator(self.df, [])
[docs] def data_array(self, axes=[], selection=None, shared=False, display_function=IPython.display.display, **kwargs):
'''Create a :func:`vaex.jupyter.model.DataArray` model and :func:`vaex.jupyter.view.DataArray` widget and links them.
This is a convenience method to create the model and view, and hook them up.
'''
import vaex.jupyter.model
import vaex.jupyter.view
if selection is not None:
selection = selection.copy()
model = vaex.jupyter.model.DataArray(df=self.df, axes=axes, selection=selection, **kwargs)
if shared:
grid = self.grid
else:
grid = vaex.jupyter.model.GridCalculator(self.df, [])
grid.model_add(model)
view = vaex.jupyter.view.DataArray(model=model, display_function=display_function)
return view
def axis_model(self, expression, limits=None):
return self._axes([expression], limits=[limits])[0]
def _axes(self, expressions, limits):
limits = self.df.limits(expressions, limits)
axes = [vaex.jupyter.model.Axis(df=self.df, expression=expression, min=min, max=max) for expression, (min, max) in zip(expressions, limits)]
return axes
def histogram(self, x, limits=None, selection=None, selection_interact='default', toolbar=True, shared=False, **kwargs):
import vaex.jupyter.model
import vaex.jupyter.view
if selection is not None:
selection = selection.copy()
x, = self._axes([x], limits)
model = vaex.jupyter.model.Histogram(df=self.df, x=x, selection=selection, selection_interact=selection_interact, **kwargs)
if shared:
grid = self.grid
else:
grid = vaex.jupyter.model.GridCalculator(self.df, [])
grid.model_add(model)
viz = vaex.jupyter.view.Histogram(model=model)
if toolbar:
viz.toolbar = _add_toolbar(viz)
return viz
def pie(self, x, limits=None, shared=False, **kwargs):
import vaex.jupyter.model
import vaex.jupyter.view
x, = self._axes([x], limits)
model = vaex.jupyter.model.Histogram(df=self.df, x=x, **kwargs)
if shared:
grid = self.grid
else:
grid = vaex.jupyter.model.GridCalculator(self.df, [])
grid.model_add(model)
viz = vaex.jupyter.view.PieChart(model=model)
return viz
def heatmap(self, x, y, limits=None, selection=None, selection_interact='default', transform='log', toolbar=True, shape=256, shared=False, **kwargs):
import vaex.jupyter.model
import vaex.jupyter.view
x, y = self._axes([x, y], limits)
if selection is not None:
selection = selection.copy()
model = vaex.jupyter.model.Heatmap(df=self.df, x=x, y=y, selection=selection, shape=shape, **kwargs)
if shared:
grid = self.grid
else:
grid = vaex.jupyter.model.GridCalculator(self.df, [])
self._last_grid = grid
grid.model_add(model)
viz = vaex.jupyter.view.Heatmap(model=model, transform=transform)
if toolbar:
viz.toolbar = _add_toolbar(viz)
return viz
[docs] def expression(self, value=None, label='Custom expression'):
'''Create a widget to edit a vaex expression.
If value is an :class:`vaex.jupyter.model.Axis` object, its expression will be (bi-directionally) linked to the widget.
:param value: Valid expression (string or Expression object), or Axis
'''
from .widgets import ExpressionTextArea
import vaex.jupyter.model
if isinstance(value, vaex.jupyter.model.Axis):
expression_value = str(value.expression)
else:
expression_value = str(value) if value is not None else None
expression_widget = ExpressionTextArea(df=self.df, v_model=expression_value, label=label)
if isinstance(value, vaex.jupyter.model.Axis):
import traitlets
traitlets.link((value, 'expression'), (expression_widget, 'value'))
return expression_widget
def column(self, value=None, label='Choose a column'):
from .widgets import ColumnPicker
if isinstance(value, vaex.jupyter.model.Axis):
expression_value = str(value.expression)
else:
expression_value = str(value) if value is not None else None
column_widget = ColumnPicker(df=self.df, value=expression_value, label=label)
if isinstance(value, vaex.jupyter.model.Axis):
import traitlets
traitlets.link((value, 'expression'), (column_widget, 'value'))
return column_widget
def selection_expression(self, initial_value=None, name='default'):
from .widgets import ExpressionSelectionTextArea
if initial_value is None:
if not self.df.has_selection(name):
raise ValueError(f'No selection with name {name!r}')
else:
initial_value = self.df.get_selection(name).boolean_expression
return ExpressionSelectionTextArea(df=self.df, selection_name=name, v_model=str(initial_value) if initial_value is not None else None)
def progress_circular(self, width=10, size=70, color='#82B1FF', text='', auto_hide=False):
from .widgets import ProgressCircularNoAnimation
progress_circular = ProgressCircularNoAnimation(width=width, size=size, color=color, text=text, value=0)
@self.df.executor.signal_begin.connect
def progress_begin():
if auto_hide:
progress_circular.hidden = False
@self.df.executor.signal_progress.connect
def update_progress(value):
progress_circular.value = value*100
return True
@self.df.executor.signal_end.connect
def progress_update():
if auto_hide:
progress_circular.hidden = True
return progress_circular
def counter_processed(self, postfix="rows processed", update_interval=0.2):
from .widgets import Counter
counter_processed = Counter(value=0, postfix=postfix)
last_time = 0
@self.df.executor.signal_begin.connect
def progress_begin():
nonlocal last_time
last_time = time.time()
@self.df.executor.signal_progress.connect
def update_progress(value):
nonlocal last_time
number = int(value * len(self.df))
current_time = time.time()
if (current_time - last_time) > update_interval or value in [0, 1]:
counter_processed.value = number
last_time = current_time
return True
return counter_processed
def counter_selection(self, selection, postfix="rows selected", update_interval=0.2, lazy=False):
from .widgets import Counter
selected = self.df.count(selection=selection).item() if self.df.has_selection(name=selection) else 0
counter_selected = Counter(value=selected, postfix=postfix)
dirty = False
@self.df.signal_selection_changed.connect
def selection_changed(df, name):
nonlocal dirty
if name == selection:
# we only need to run once
if not dirty:
dirty = True
def update_value(value):
nonlocal dirty
dirty = False
try:
value = value.item()
except: # noqa
pass
counter_selected.value = value
# if lazy is True, this will only schedule the calculation, not yet execute it
if lazy:
vaex.delayed(update_value)(self.df.count(selection=selection, delay=True))
else:
update_value(self.df.count(selection=selection))
return counter_selected
# from .widgets import Tools
# from traitlets import link
# viz = [] if viz is None else viz
# viz = [viz] if not isinstance(viz, (tuple, list)) else viz
# tools = Tools(value=initial_value, children=[k.widget for k in viz])
# for v in viz:
# link((tools, 'value'), (v, 'tool'))
# return tools
# def card(plot, title=None, subtitle=None, **kwargs):
# from .widget import Card
# return Card(main=plot, title=title, subtitle,
def add_namespace():
pass