-
-
Notifications
You must be signed in to change notification settings - Fork 518
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
Add better and more data grids #1525
Comments
TabulatorTabulator is a MIT licensed grid which seems to look+feel great and have a very, very nice api. I believe the implementation could be something very similar to how the ECharts pane is implemented. At it's core you just need a Then you could provide an additional Then you could provide some kind of functionality to provide (parts of) the configuration with Then we should provide We should also enable streaming. Either via the stream api of ColumnDataSource, by providing a I believe it would be nice to provide some helper function which takes a DataFrame or similar and converts it into the I also believe it would be nice to provide the user with an easy way to append one of the different available themes to Take a look at the documentation. It's really, really awesome and understandable. I have started experimenting and coding for the awesome-panel-extensions package. So reach out before you start to not repeat work already done. |
JExcelMy users are often very familiar with Excel. So being able to provide an excel like grid would be awesome. I've found jExcel https://github.com/paulhodel/jexcel which at a first look looks awesome and could be implemented an a way very similar to Tabulator above. Its MIT licensed. |
I have a poc of Tabulator working. I've based it on a bokeh .ts and bokeh .py model. It works really, really great: It's responsive, Has different css styles out of the box, Is very easy to configure with lots of examples. Cannot prebuildCurrently I refer to the implementation in the bokeh .py model The problem is that if I want to use it as a prebuilt model using It's strange because if I look at the Dataframe vs ColumnDataSourceI am in doubt on the api. Currently the user can provide a Dataframe or a ColumnDataSource. If he she provides a ColumnDataSource the he/ she can use the stream and patching api of the CDS and it works great (see example above). But I am in doubt if the users will think the ColumnDataSource is friction and whether I should just provide functionality to work with DataFrames. I also don't know how the api should be if I really want to integrate with HoloViews, LinkedBrushing and Streamz. That would be nice to learn. Pane or WidgetCurrently I've implemented this as a Widget with Codeclass Tabulator(Widget):
configuration = param.Dict(doc="""The Tabulator configuration""")
data = param.Parameter(
doc="""One of pandas.DataFrame or bokeh.models.ColumnDataSource.
If specified it will transfered efficiently to the browser and added to the configuration
"""
)
_data = param.ClassSelector(
class_=ColumnDataSource, doc="Used to transfer data efficiently to frontend" ""
)
selected_indicies = param.List(doc="The list of selected row indexes")
height = param.Integer(default=300, bounds=(0, None))
_rename = {
"data": None,
"_data": "data",
}
_widget_type = _BkTabulator
def __init__(self, **params):
if "configuration" not in params:
params["configuration"] = _DEFAULT_CONFIGURATION.copy()
params["selection"] = []
super().__init__(**params)
self._update_column_data_source()
@param.depends("data", watch=True)
def _update_column_data_source(self, *events):
if self.data is None:
self._data = None
elif isinstance(self.data, pd.DataFrame):
self._data = ColumnDataSource(self.data)
elif isinstance(self.data, ColumnDataSource):
self._data = self.data
else:
raise ValueError("The `data` provided is not of a supported type!")
@classmethod
def to_columns_configuration(
cls, data: Union[pd.DataFrame, ColumnDataSource]
) -> List[Dict[str, str]]:
"""Returns a relevant configuration dictionary of the specified data source
Args:
data (Union[pd.DataFrame, ColumnDataSource]): The data source
Returns:
Dict: The configuration
Example:
>>> import pandas as pd
>>> data = {"name": ["python", "panel"]}
>>> df = pd.DataFrame(data)
>>> Tabulator.to_columns_configuration(df)
[{'title': 'Name', 'field': 'name', 'sorter': 'string', 'formatter': 'plaintext', 'hozAlign': 'left'}]
"""
col_conf = []
for field in data.columns:
dtype = str(data.dtypes[field])
conf = cls._core(field=field, dtype=dtype)
col_conf.append(conf)
return col_conf
@classmethod
def _core(cls, field: str, dtype: str) -> Dict[str, str]:
dtype_str = str(dtype)
return {
"title": cls._to_title(field),
"field": field,
"sorter": _SORTERS.get(dtype_str, "string"),
"formatter": _FORMATTERS.get(dtype_str, "plaintext"),
"hozAlign": _HOZ_ALIGNS.get(dtype_str, "left"),
}
@staticmethod
def _to_title(field: str) -> str:
return field.replace("_", " ").title()
@staticmethod
def config(css: str="default", momentjs: bool=True):
# pn.config.js_files["tabulator"]=JS_SRC
# if momentjs:
# pn.config.js_files["moment"]=MOMENT_SRC
if css:
href = CSS_HREFS[css]
if href not in pn.config.css_files:
pn.config.css_files.append(href)
@property
def selected_data(self) -> Union[pd.DataFrame, ColumnDataSource]:
"""Returns the selected rows of the data based
Raises:
NotImplementedError: [description]
Returns:
Union[pd.DataFrame, ColumnDataSource]: [description]
"""
# Selection is a list of row indices. For example [0,2]
if self.data is None:
return None
if isinstance(self.data, pd.DataFrame):
return self.data.iloc[self.selected_indicies,]
if isinstance(self.data, ColumnDataSource):
# I could not find a direct way to get a selected ColumnDataSource
selected_data = self.data.to_df().iloc[self.selected_indicies,]
return ColumnDataSource(selected_data)
raise NotImplementedError() FYI. @philippjfr . |
An alternative approach to providing more grids would be to improve the existing. Maybe it is just better documentation that we need.
|
Hi @xavArtley Thanks so much for reaching out. Yes. When using The problem is when I want to remove implemention and prebuild things with |
I succeed to make prebuilt extensions here It may be outdated but it used to work |
My code is in the repo https://github.com/MarcSkovMadsen/awesome-panel-extensions.git in the branch panel model: https://github.com/MarcSkovMadsen/awesome-panel-extensions/blob/tabulator-extension/awesome_panel_extensions/widgets/tabulator.py I If i look into I've also tested that the WebComponent model is still registered and working. So some parts of the build works. But if I `python 'tests\widgets\test_tabulator\test_tabulator_designer.py' it does not work @mattpap or @philippjfr . If you have some thoughts I would really appreciate it because I've run out of random changes/ ideas to try out. Additional Context |
You need to set |
We need to make this clearer in bokehjs, either at compilation or usage time, because skipping |
Thanks so much @mattpap . One day I would really like to learn from you or somebody else how to efficiently develop bokeh extensions. How to use integrated debugging, setup automated testing, live reload etc. Right now my development flow is too slow. One thing I should do is add some snippets in VS Code for generating the bokeh .ts and .py models. I have some for the Panel .py extensions. And it makes things much more easy. One thing I've thought about is that some of the template you can get in a front end framework like angular via |
Tabulator was merged as part of the 0.11 release and has been great! |
My Pain
I believe the current DataFrame pane and widget built on SlickGrid are not up to the task.
There are several issues
I believe nice and easy to use tables are just as important as nice plots. So I really believe the lack of nice tables/ grids is holding Panel back.
Solution
Improve current implementation or provide additional grids.
Additional Context
Below I will provide some grids for inspiration.
The text was updated successfully, but these errors were encountered: