diff --git a/panel/models/reactive_html.py b/panel/models/reactive_html.py
index 416943db21..185406e27b 100644
--- a/panel/models/reactive_html.py
+++ b/panel/models/reactive_html.py
@@ -7,7 +7,7 @@
import bokeh.core.properties as bp
import param as pm
-from bokeh.models import HTMLBox, LayoutDOM
+from bokeh.models import ColumnDataSource, HTMLBox, LayoutDOM
from bokeh.model import DataModel
from bokeh.events import ModelEvent
@@ -141,10 +141,15 @@ def find_attrs(html):
PARAM_MAPPING = {
+ pm.Array: lambda p, kwargs: bp.Array(**kwargs),
pm.Boolean: lambda p, kwargs: bp.Bool(**kwargs),
pm.CalendarDate: lambda p, kwargs: bp.Date(**kwargs),
pm.CalendarDateRange: lambda p, kwargs: bp.Tuple(bp.Date, bp.Date, **kwargs),
pm.Color: lambda p, kwargs: bp.Color(**kwargs),
+ pm.DataFrame: lambda p, kwargs: (
+ bp.ColumnData(bp.Any, bp.Seq(bp.Any), **kwargs),
+ [(bp.PandasDataFrame, lambda x: ColumnDataSource._data_from_df(x))]
+ ),
pm.DateRange: lambda p, kwargs: bp.Tuple(bp.Datetime, bp.Datetime, **kwargs),
pm.Date: lambda p, kwargs: bp.Datetime(**kwargs),
pm.Dict: lambda p, kwargs: bp.Dict(bp.String, bp.Any, **kwargs),
@@ -175,11 +180,15 @@ def construct_data_model(parameterized, name=None, ignore=[], types={}):
nullable = getattr(p, 'allow_None', False)
kwargs = {'default': p.default, 'help': p.doc}
if prop is None:
- properties[pname] = bp.Any(**kwargs)
- elif nullable:
- properties[pname] = bp.Nullable(prop(p, {}), **kwargs)
+ bk_prop, accepts = bp.Any(**kwargs), []
else:
- properties[pname] = prop(p, kwargs)
+ bkp = prop(p, {} if nullable else kwargs)
+ bk_prop, accepts = bkp if isinstance(bkp, tuple) else (bkp, [])
+ if nullable:
+ bk_prop = bp.Nullable(bk_prop, **kwargs)
+ for bkp, convert in accepts:
+ bk_prop = bk_prop.accepts(bkp, convert)
+ properties[pname] = bk_prop
name = name or parameterized.name
return type(name, (DataModel,), properties)