<jupyter_start><jupyter_text>Spreadsheet widget for the Jupyter Notebook InstallationTo install use pip:```$ pip install ipysheet```To make it work for Jupyter lab:```$ jupyter labextension ipysheet```If you have notebook 5.2 or below, you also need to execute:```$ jupyter nbextension enable --py --sys-prefix ipysheet$ jupyter nbextension enable --py --sys-prefix ipysheet.renderer_nbext```  Getting startedAlthough ipysheet contains an object oriented interface, we recomment using the "state machine" based interface, similar to matplotlib's pyplot/pylab interface. Comparible to matplotlib pylab interface, this interface keeps track of the current sheet. Using the [cell](api.rstipysheet.easy.cell) function, [Cell](api.rstipysheet.sheet.Cell) widgets are added to the current sheet.Importing ipysheet and invoking the [sheet](api.rstipysheet.easy.sheet) function will create the default spreadsheet widget. The function returns a [Sheet](api.rstipysheet.sheet.Sheet) instance, leaving that expression as a last statement of a code cell will display it, otherwise use `display(sheet)`.Note that this documentation is a Jupyter notebook, and you can try it out directly on Binder:[![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/QuantStack/ipysheet/master?filepath=docs%2Fsource%2Findex.ipynb)<jupyter_code>import ipysheet
sheet = ipysheet.sheet()
sheet<jupyter_output><empty_output><jupyter_text>Using the [cell](api.rstipysheet.easy.cell) function, we can create [Cell](api.rstipysheet.sheet.Cell) widgets that are directly added to the current sheet.<jupyter_code>sheet = ipysheet.sheet(rows=3, columns=4)
cell1 = ipysheet.cell(0, 0, 'Hello')
cell2 = ipysheet.cell(2, 0, 'World')
cell_value = ipysheet.cell(2,2, 42.)
sheet<jupyter_output><empty_output><jupyter_text>EventsUsing link or observe we can link widgets together, or attach event handlers **Note:** The examples below contain event handler written in Python that needs a running kernel, they will not work in the pure html documentation. They do work in binder!<jupyter_code>import ipywidgets as widgets
sheet = ipysheet.sheet(rows=3, columns=2, column_headers=False, row_headers=False)
cell_a = ipysheet.cell(0, 1, 1, label_left='a')
cell_b = ipysheet.cell(1, 1, 2, label_left='b')
cell_sum = ipysheet.cell(2, 1, 3, label_left='sum', read_only=True)

# create a slider linked to cell a
slider = widgets.FloatSlider(min=-10, max=10, description='a')
widgets.jslink((cell_a, 'value'), (slider, 'value'))

# changes in a or b should trigger this function
def calculate(change):
    cell_sum.value = cell_a.value + cell_b.value

cell_a.observe(calculate, 'value')
cell_b.observe(calculate, 'value')


widgets.VBox([sheet, slider])<jupyter_output><empty_output><jupyter_text>Cell rangesInstead of referring to a single cell, we can also refer to cell ranges, rows and columns.<jupyter_code>sheet = ipysheet.sheet(rows=5, columns=4)
row = ipysheet.row(0, [0, 1, 2, 3], background_color="red")
column = ipysheet.column(1, ["a", "b", "c", "d"], row_start=1, background_color="green")
cells = ipysheet.cell_range([["hi", "ola"], ["ciao", "bonjour"], ["hallo", "guten tag"]],
                            row_start=1, column_start=2, background_color="yellow")
sheet<jupyter_output><empty_output><jupyter_text>CalculationsSince this is such a common pattern, a helper decorator [calculation](api.rstipysheet.easy.calculation) is provided, shortening the above code considerably.<jupyter_code>import ipywidgets as widgets
sheet = ipysheet.sheet(rows=3, columns=2, column_headers=False, row_headers=False)
cell_a = ipysheet.cell(0, 1, 1, label_left='a')
cell_b = ipysheet.cell(1, 1, 2, label_left='b')
cell_sum = ipysheet.cell(2, 1, 3, label_left='sum', read_only=True)

# create a slider linked to cell a
slider = widgets.FloatSlider(min=-10, max=10, description='a')
widgets.jslink((cell_a, 'value'), (slider, 'value'))

@ipysheet.calculation(inputs=[cell_a, cell_b], output=cell_sum)
def calculate(a, b):
    return a + b

widgets.VBox([sheet, slider])<jupyter_output><empty_output><jupyter_text>Renderersipysheet is build on Handsontable, which allows [custom renderers](https://docs.handsontable.com/demo-custom-renderers.html), which we also support. Note that this means ipysheet allows arbitrary JavaScript injection (TODO: make this part optional)<jupyter_code>jscode_renderer_negative = """
function (instance, td, row, col, prop, value, cellProperties) {
    Handsontable.renderers.TextRenderer.apply(this, arguments);
    if (value < 0)
        td.style.backgroundColor = 'red'
    else
        td.style.backgroundColor = 'green'
}
"""
ipysheet.renderer(code=jscode_renderer_negative, name='negative');
import random
s = ipysheet.sheet(rows=3, columns=4)
data = [[random.randint(-10, 10) for j in range(4)] for j in range(3)]
ipysheet.cell_range(data, renderer='negative')
s<jupyter_output><empty_output><jupyter_text>If [flexx](http://flexx.readthedocs.io/en/stable/pyscript/index.html) is installed, Python code can be transpiled to JavaScript at runtime.<jupyter_code>def renderer_negative(instance, td, row, col, prop, value, cellProperties):
    Handsontable.renderers.TextRenderer.apply(this, arguments);
    if value < 0:
        td.style.backgroundColor = 'orange'
    else:
        td.style.backgroundColor = ''
ipysheet.renderer(code=renderer_negative, name='negative_transpiled');
import random
s = ipysheet.sheet(rows=3, columns=4)
data = [[random.randint(-10, 10) for j in range(4)] for j in range(3)]
ipysheet.cell_range(data, renderer='negative_transpiled')
s<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12352520557740436, 'fraction_numerical': 0.013585984983911333, 'mean_word_length': 6.2007722007722, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 29, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '137631', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 1907, 'n_tokens_neox': 1835, 'n_words': 503, 'path': '2018-06-18-IFPEN-Tech/notebooks/13 - ipysheet.ipynb', 'repo_name': 'jtpio/quantstack-talks', 'size': '5594'}