Repository: holoviz/panel

Issue:
pn.panel and pn.pane.DataFrame highly problematic
panel==0.14.3

I was trying to help a colleague get into Panel and wanted to write a getting started tutorial for my team. 

In my team the Pandas DataFrame is the starting point for much of our work. So great support for displaying DataFrames is key

I wanted to describe the basic concepts and I believe(d) that `pn.panel` is key. Its the `print` statement of Panel and similar to `st.write` in Streamlit.

But when you use `pn.panel` on DataFrames they don't display nicely. Neither in a Notebook or in a server App. And its almost impossible to get them to do this if you have lots of data as you cannot control the scrollbars.

Please make `pn.panel` and `pn.pane.DataFrame` an easy to use starting point.

## Examples

### Example 1

I've seen colleagues see this many times. They don't understand what goes on and how to solve this because they are not used to seeing tables overlap in other web pages they visit. They are sort of stuck. And as a beginner you don't know which part of the documentation to find the solution in if any.

Here I would recommend the `pn.pane.DataFrame` to automatically figure out if horizontal or vertical scroll is needed. Even better I would like Panel to have `sizing_mode='stretch_width` by default. I think its a general design mistake to have fixed width by default. I would really, really recommend changing this default for Panel 1.0.

![image](https://user-images.githubusercontent.com/42288570/217723134-b9fd31ba-d43d-415b-889e-5eff0a7badb4.png)

You can solve the horizontal issue by adding `width=800` or `sizing_mode='stretch_width'`. But it is a complication that other Frameworks don't have as they just make things responsive by default.

### Example 2

If you set the `width` and `height` in the notebook a vertical scrollbar appears. That is nice and the behaviour I would have hoped to experience by default.

![image](https://user-images.githubusercontent.com/42288570/217723974-fbc41225-b63e-4225-b78e-4109d6c8f40e.png)

But the problem is that the scrollbar is not added by Panel. Its added by Jupyter. Thus if you start using the DataFrame pane in a Column you start having the overflow problem again.

![image](https://user-images.githubusercontent.com/42288570/217724277-31c1a210-7c14-41de-ab9e-d1344d0aa275.png)

### Example 3

Ok so you can try to add scroll to the column. But only both which leads to the below problem. Where you can see the whole table width.

![image](https://user-images.githubusercontent.com/42288570/217724505-4588bcac-6594-4bb6-ad54-a15002e05cab.png)

### Example 4

Ok so you can make the Column Wider

![image](https://user-images.githubusercontent.com/42288570/217724824-1f75d442-3d59-45e7-93ff-9999657a5330.png)

But then you have the ugly not needed indication of a horizontal scrollbar. And you had to add a 2x`width`, 1x`heigth` and 1x`scroll` parameters to get to something that at least is functional.

### Example 5

There is no help in the `pn.pane.DataFrame` guide as it only contains example with a few rows and columns. And even that is not given a proper width.

![image](https://user-images.githubusercontent.com/42288570/217725571-ef044c2c-81c3-4ac9-aecf-0aa2047a8465.png)


### Example 6

Just for fun I tried setting the height of the `Column` and something is clearly wrong.

![image](https://user-images.githubusercontent.com/42288570/217726259-9e4b2862-b88f-463f-8b7b-4e164b422f07.png)

### Recommended Actions

- Make `pn.panel` and `pn.pane.DataFrame` able to display larger dataframes nicely by default. Something has lots of columns and rows.
- Add parameter to `pn.pane.DataFrame` to control the scroll: None, Automatic, Horizontal, Vertical, Both.
- Add an example to the `pn.pane.DataFrame` demonstrating that it now works.

As an alternative you could consider dropping the `pn.pane.DataFrame` and use `pn.widgets.Tabulator`. Its much, much more useful.

It would be an added bonus if the number formatting was changed to something that works in a business. I almost never see scientific notation used.


Discussion:
We will release a dev release of Panel soon. Some of your requests are already fixed in it. Here is example 1:
![image](https://user-images.githubusercontent.com/19758978/217802246-bae0bd8b-990a-4677-8da3-932423bb8a33.png)

It is important to clarify that the pane uses the Pandas `to_html` method when outputting the dataframe. It is the same output you see when you just output the Dataframe directly in the notebook.

Of course, Tabulator is more useful, but it is a much more complex tool if you just want to see your DataFrame. I could be wrong, but `pn.panel` always gives you a `pane` and not a `widget`.

For the scientific numbers, you can use `formatters` if you want to format them, but the reason for scientific numbers is if the numbers are too big to show: `pd.DataFrame([121978.1805])` vs `pd.DataFrame([1219780.1805])`. Again this is related to the `to_html` method.

`pn.Column("My App", table, "Some other thing")` is still wrong on Panel 1.0.
Thanks for the explanations 👍 . Its great to see the improvement. I hope someone (including) me one day will improve this even further. For the end user this should just be easy to use and the end result useful.
I've found that changing to `pn.panel(data, style={"overflow": "auto"}, sizing_mode="stretch_both")` solves most issues. But I dream that this would just work for users.

```python
import panel as pn
from bokeh.sampledata.airports import data

pn.extension(sizing_mode="stretch_width")

table = pn.panel(data, style={"overflow": "auto"}, sizing_mode="stretch_both", max_height=500).servable()
pn.layout.Divider().servable()
pn.Column("Hello", table, "hello", height=300).servable()
```

![image](https://user-images.githubusercontent.com/42288570/217854771-3788dd18-1cc9-42ac-ab03-f45ee4fdc23f.png)
And changing `table-layout` to `auto` does the last part. Furthermore we need to enable `col_space` to be a dict. Pandas now supports that.

```python
import panel as pn
from bokeh.sampledata.airport_routes import airports

RAW_CSS = """
table.panel-df {
    table-layout: auto;
}
"""

pn.extension(raw_css = [RAW_CSS], sizing_mode="stretch_width")

table = pn.pane.DataFrame(airports.head(100), style={"overflow": "auto", "padding-right": "5px"}, sizing_mode="stretch_both", max_height=500, col_space=dict(TZ="100px")).servable()
pn.layout.Divider().servable()
pn.Column("Hello", table, "hello", height=300).servable()
```

![image](https://user-images.githubusercontent.com/42288570/217867224-fe8dcf50-1f02-4add-8916-2993550b9fbc.png)


Resolving patch:
diff --git a/panel/pane/markup.py b/panel/pane/markup.py
--- a/panel/pane/markup.py
+++ b/panel/pane/markup.py
@@ -23,7 +23,6 @@
     from bokeh.model import Model
     from pyviz_comms import Comm  # type: ignore
 
-
 class HTMLBasePane(ModelPane):
     """
     Baseclass for Panes which render HTML inside a Bokeh Div.
@@ -114,7 +113,7 @@ class DataFrame(HTML):
     classes = param.List(default=['panel-df'], doc="""
         CSS class(es) to apply to the resulting html table.""")
 
-    col_space = param.ClassSelector(default=None, class_=(str, int), doc="""
+    col_space = param.ClassSelector(default=None, class_=(str, int, dict), doc="""
         The minimum width of each column in CSS length units. An int
         is assumed to be px units.""")
 
@@ -247,8 +246,10 @@ def _transform_object(self, obj: Any) -> Dict[str, Any]:
 
     def _init_params(self) -> Dict[str, Any]:
         params = HTMLBasePane._init_params(self)
+
         if self._stream:
             params['object'] = self._object
+
         return params
 
 


Test patch: