Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Amazing work - quick question #6

Open
ellisonbg opened this issue Nov 1, 2022 · 13 comments
Open

Amazing work - quick question #6

ellisonbg opened this issue Nov 1, 2022 · 13 comments

Comments

@ellisonbg
Copy link

First congrats on this work, really amazing to see this. Have you looked at integrating ipydatagrid? What would that take?

@maartenbreddels
Copy link
Contributor

Hi Brian,

Thanks!
sorry for the late reply, github notifications were turned off by default on this repo.

I wasn't sure if ipydatagrid would work, but this seems to work fine:

#!wget https://raw.githubusercontent.com/bloomberg/ipydatagrid/main/examples/cars.json
from ipydatagrid import DataGrid, TextRenderer, BarRenderer, Expr
from json import load
import pandas as pd

with open("./cars.json") as fobj:
    data = load(fobj)
df = pd.DataFrame(data["data"]).set_index("index")
df = df[sorted(df.columns)]

from bqplot import LinearScale, LogScale, ColorScale, OrdinalColorScale, OrdinalScale
from py2vega.functions.color import rgb
import reacton
import reacton.ipywidgets as w

def horsepower_coloring(cell):
    if cell.value < 100:
        return "red"
    elif cell.value < 150:
        return "orange"
    else:
        return "green"


def weight_coloring(cell):
    scaled_value = 1 if cell.value > 4500 else cell.value / 4500
    color_value = scaled_value * 255

    return rgb(color_value, 0, 0)


@reacton.component
def DataGridTest():
    acc_max, set_acc_max = reacton.use_state(20)
    use_log, set_use_log = reacton.use_state(False)
    renderers = {
        "Acceleration": BarRenderer.element(
            horizontal_alignment="center",
            bar_color=ColorScale(min=0, max=acc_max, scheme="viridis"),
            bar_value=LogScale(min=1, max=acc_max) if use_log else LinearScale(min=0, max=acc_max),
        ),
        "Cylinders": TextRenderer.element(
            background_color=Expr('"grey" if cell.row % 2 else default_value')
        ),
        "Displacement": TextRenderer.element(
            text_color=ColorScale(min=97, max=455),
            font=Expr(
                "'16px sans-serif' if cell.value > 400 else '12px sans-serif'"
            ),
        ),
        "Horsepower": TextRenderer.element(
            text_color="black", background_color=Expr(horsepower_coloring)
        ),
        "Miles_per_Gallon": TextRenderer.element(
            background_color=Expr('"grey" if cell.value is None else default_value')
        ),
        "Name": TextRenderer.element(
            background_color=Expr(
                'rgb(0, 100, 255) if "chevrolet" in cell.value or "ford" in cell.value else default_value'
            )
        ),
        "Origin": TextRenderer.element(
            text_color="black",
            background_color=OrdinalColorScale.element(domain=["USA", "Japan", "Europe"]),
            horizontal_alignment=Expr(
                "'right' if cell.value in ['USA', 'Japan'] else 'left'"
            ),
        ),
        "Weight_in_lbs": TextRenderer.element(
            text_color="black", background_color=Expr(weight_coloring)
        ),
        "Year": TextRenderer.element(text_color="black", background_color="green"),
    }
    
    with w.VBox() as main:
        w.IntSlider(value=acc_max, on_value=set_acc_max, description="Max acc.")
        w.Checkbox(value=use_log, on_value=set_use_log, description="Log acc.")
        DataGrid.element(
            dataframe=df, base_row_size=32, base_column_size=150, renderers=renderers
        )
    return main
display(DataGridTest())

Here I've added a slider and a checkbox to change settings, which would be difficult to do without Reacton (toggling the checkbox would require manually deleting the scale widget, and creating the new one without Reacton).

Note that there is no wrapper generated for ipydatagrid, but we add the .element(..) method to the base widget class to support any 3rd party widgets.

A problem I see with ipydatagrid is that the arguments of the constructor do not match the traits, which is something Reacton assumes.

I also took the opportunity to document this a bit here:
https://reacton.solara.dev/en/latest/libraries/

@dhirschfeld
Copy link

I came here to ask if this would work with the perspective-widget or if all 3rd party widgets need to be individually wrapped to work with reaction.

It sounds like it should be possible to use it so I'll try to make time to give it a go...

@maartenbreddels
Copy link
Contributor

Hi Dave,

I tried installing perspective, but it fails on osx-arm. However, the following should work (using https://reacton.solara.dev/en/latest/libraries/)

@reacton.component
def Demo():
    with w.VBox() as main:
        w.Button(...)
        PerspectiveWidget.element(table, ...)
    return main

Let me know it you run into issues!

Regards,

Maarten Breddels

@dhirschfeld
Copy link

I tried installing perspective, but it fails on osx-arm

It's got some pretty complex build deps so your best bet would be to use conda/mamba to get an osx-arm64 build, if you were interested in trying it out.

I'll try to give it a crack over the xmas break & will make sure to report back any findings on this repo...

@maartenbreddels
Copy link
Contributor

Good idea!

Although this runs, it doesn't display in my current environment due to a semver issue in lab:

import pandas as pd
import numpy as np
from datetime import date, datetime
import perspective
import reacton.ipywidgets as w
import reacton


data = pd.DataFrame({
    "int": np.arange(100),
    "float": [i * 1.5 for i in range(100)],
    "bool": [True for i in range(100)],
    "date": [date.today() for i in range(100)],
    "datetime": [datetime.now() for i in range(100)],
    "string": [str(i) for i in range(100)]
})
table = perspective.Table(data, index="float")

@reacton.component
def Demo():
    with w.VBox() as main:
        w.Button(description="Hi")
        perspective.PerspectiveWidget.element(data=table)
    return main
Demo()

@dhirschfeld
Copy link

Thanks @maartenbreddels! I'll give that a go!

If you've got a few mins spare I might get you to merge the PR conda-forge/reacton-feedstock#5 🙏
Looks like it needs a couple of minor dependency changes - I commented in the PR.

@dhirschfeld-shell
Copy link

No luck for me:

Error displaying widget
Error: Module @finos/perspective-jupyterlab, semver range ~1.7.1 is not registered as a widget module

...but that might just be an issue with my JupyterLab / environment. Will have to poke about a bit more to figure out where things are going wrong...

@maartenbreddels
Copy link
Contributor

Yeah, that is not related to Reacton. To be sure, just try to use the widget standalone.

I think I had the same issue.

@dhirschfeld
Copy link

dhirschfeld commented Dec 20, 2022

It turns out perspective isn't a prebuilt extension... and may have some other quirks.

jupyter labextension install @finos/perspective-jupyterlab@1.7.1

Anyway, after getting perspective to work, your example above still didn't work. Digging deeper it appears that perspective doesn't work when inside a VBox (or any layout element I guesss?)

image

I was able to work around that by wrapping the perspective table in an Output widget:

image

Applying the same trick to the reacton.component also appeared to work:

@reacton.component
def Demo():
    out = ipy.Output.element()
    with out:
        display(perspective.PerspectiveWidget(table))
    with w.VBox() as main:
        w.Button(description="Hi")
        out
    return main

image

@dhirschfeld
Copy link

It would seem not rendering when inside a layout widget might be a perspective bug. I'm curious if you know of anything obvious they might be doing wrong for that to not Just Work?

@maartenbreddels
Copy link
Contributor

Hmm yes, they may be missing some lumino resize events, or even better, what we should be doing from now on: bqplot/bqplot#1531 using the browser ResizeObserver . (the lumino events are also clear from that PR)

@asaboor-gh
Copy link

Myself feeling dumb after seeing this:

with w.VBox() as main:
     ...

So amazing implementation. 👏

@dhirschfeld-shell
Copy link

Thanks for the reference Maarten! I'll make sure to link to it when I open an issue on the perspective repo 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants