diff --git a/panel/layout/tabs.py b/panel/layout/tabs.py index ec69035a0e..24076c4679 100644 --- a/panel/layout/tabs.py +++ b/panel/layout/tabs.py @@ -151,7 +151,7 @@ def _get_objects(self, model, old_objects, doc, root, comm=None): continue elif self.dynamic and i != self.active: child = BkSpacer(**{k: v for k, v in pane.param.get_param_values() - if k in Layoutable.param}) + if k in Layoutable.param and v is not None}) else: try: child = pane._get_model(doc, root, model, comm) diff --git a/panel/models/ace.ts b/panel/models/ace.ts index 06963a1ca5..84f182bd72 100644 --- a/panel/models/ace.ts +++ b/panel/models/ace.ts @@ -135,15 +135,15 @@ export class AcePlot extends HTMLBox { static init_AcePlot(): void { this.prototype.default_view = AcePlotView - this.define({ - code: [ p.String ], - filename: [ p.String ], - language: [ p.String ], - theme: [ p.String, 'chrome' ], - annotations: [ p.Array, [] ], - readonly: [ p.Boolean, false ], - print_margin: [ p.Boolean, false ] - }) + this.define(({Any, Array, Boolean, String}) => ({ + code: [ String, '' ], + filename: [ String ], + language: [ String ], + theme: [ String, 'chrome' ], + annotations: [ Array(Any), [] ], + readonly: [ Boolean, false ], + print_margin: [ Boolean, false ] + })) this.override({ height: 300, diff --git a/panel/models/audio.ts b/panel/models/audio.ts index f36dd8c22e..937a7e6b30 100644 --- a/panel/models/audio.ts +++ b/panel/models/audio.ts @@ -130,13 +130,13 @@ export class Audio extends HTMLBox { static init_Audio(): void { this.prototype.default_view = AudioView - this.define({ - loop: [ p.Boolean, false ], - paused: [ p.Boolean, true ], - time: [ p.Number, 0 ], - throttle: [ p.Number, 250 ], - value: [ p.Any, '' ], - volume: [ p.Number, null ], - }) + this.define(({Any, Boolean, Int, Number}) => ({ + loop: [ Boolean, false ], + paused: [ Boolean, true ], + time: [ Number, 0 ], + throttle: [ Number, 250 ], + value: [ Any, '' ], + volume: [ Int ], + })) } } diff --git a/panel/models/card.ts b/panel/models/card.ts index e602188dcd..6ecdff9dd5 100644 --- a/panel/models/card.ts +++ b/panel/models/card.ts @@ -130,16 +130,16 @@ export class Card extends Column { static init_Card(): void { this.prototype.default_view = CardView - this.define({ - active_header_background: [ p.String, null ], - button_css_classes: [ p.Array, [] ], - collapsed: [ p.Boolean, true ], - collapsible: [ p.Boolean, true ], - header_background: [ p.String, null ], - header_color: [ p.String, null ], - header_css_classes: [ p.Array, [] ], - header_tag: [ p.String, "div" ], - tag: [ p.String, "div" ], - }) + this.define(({Array, Boolean, Nullable, String}) => ({ + active_header_background: [ Nullable(String), null ], + button_css_classes: [ Array(String), [] ], + collapsed: [ Boolean, true ], + collapsible: [ Boolean, true ], + header_background: [ Nullable(String), null ], + header_color: [ Nullable(String), null ], + header_css_classes: [ Array(String), [] ], + header_tag: [ String, "div" ], + tag: [ String, "div" ], + })) } } diff --git a/panel/models/comm_manager.ts b/panel/models/comm_manager.ts index cfe88a309f..d58d94f3bb 100644 --- a/panel/models/comm_manager.ts +++ b/panel/models/comm_manager.ts @@ -135,12 +135,12 @@ export class CommManager extends Model { static init_CommManager(): void { this.prototype.default_view = CommManagerView - this.define({ - plot_id: [ p.String, null ], - comm_id: [ p.String, null ], - client_comm_id: [ p.String, null], - timeout: [ p.Number, 5000 ], - debounce: [ p.Number, 50], - }) + this.define(({Int, String}) => ({ + plot_id: [ String ], + comm_id: [ String ], + client_comm_id: [ String ], + timeout: [ Int, 5000 ], + debounce: [ Int, 50 ], + })) } } diff --git a/panel/models/deckgl.ts b/panel/models/deckgl.ts index 3db09dc0a7..028a2d93b8 100644 --- a/panel/models/deckgl.ts +++ b/panel/models/deckgl.ts @@ -1,6 +1,7 @@ import {div} from "@bokehjs/core/dom" import * as p from "@bokehjs/core/properties" import {HTMLBox} from "@bokehjs/models/layouts/html_box" +import {ColumnDataSource} from "@bokehjs/models/sources/column_data_source" import {transform_cds_to_records} from "./data" import {PanelHTMLBoxView, set_size} from "./layout" @@ -190,7 +191,7 @@ export namespace DeckGLPlot { export type Attrs = p.AttrsOf export type Props = HTMLBox.Props & { data: p.Property - data_sources: p.Property + data_sources: p.Property initialViewState: p.Property layers: p.Property mapbox_api_key: p.Property @@ -215,17 +216,17 @@ export class DeckGLPlot extends HTMLBox { static init_DeckGLPlot(): void { this.prototype.default_view = DeckGLPlotView; - this.define({ - data: [p.Any], - data_sources: [ p.Array, [] ], - clickState: [ p.Any ], - hoverState: [ p.Any ], - initialViewState: [p.Any], - layers: [ p.Array, [] ], - mapbox_api_key: [p.String], - tooltip: [ p.Any ], - viewState: [ p.Any ], - }) + this.define(({Any, Array, String, Ref}) => ({ + data: [ Any ], + data_sources: [ Array(Ref(ColumnDataSource)), [] ], + clickState: [ Any, {} ], + hoverState: [ Any, {} ], + initialViewState: [ Any, {} ], + layers: [ Array(Any), [] ], + mapbox_api_key: [ String, '' ], + tooltip: [ Any, {} ], + viewState: [ Any, {} ], + })) this.override({ height: 400, diff --git a/panel/models/echarts.ts b/panel/models/echarts.ts index d62ab22602..ae80708634 100644 --- a/panel/models/echarts.ts +++ b/panel/models/echarts.ts @@ -61,10 +61,10 @@ export class ECharts extends HTMLBox { static init_ECharts(): void { this.prototype.default_view = EChartsView - this.define({ - data: [ p.Any ], - theme: [ p.String, "default" ], - renderer: [ p.String, "canvas"] - }) + this.define(({Any, String}) => ({ + data: [ Any, {} ], + theme: [ String, "default" ], + renderer: [ String, "canvas" ] + })) } } diff --git a/panel/models/file_download.ts b/panel/models/file_download.ts index fdaedb820e..fc1edc1ed0 100644 --- a/panel/models/file_download.ts +++ b/panel/models/file_download.ts @@ -217,15 +217,15 @@ export class FileDownload extends InputWidget { static init_FileDownload(): void { this.prototype.default_view = FileDownloadView - this.define({ - auto: [ p.Boolean, false ], - clicks: [ p.Number, 0 ], - data: [ p.NullString, null ], - label: [ p.String, "Download" ], - filename: [ p.String, null ], - button_type: [ p.ButtonType, "default" ], // TODO (bev) - _transfers: [ p.Number, 0 ], - }) + this.define(({Boolean, Int, Nullable, String}) => ({ + auto: [ Boolean, false ], + clicks: [ Int, 0 ], + data: [ Nullable(String), null ], + label: [ String, "Download" ], + filename: [ Nullable(String), null ], + button_type: [ ButtonType, "default" ], // TODO (bev) + _transfers: [ Int, 0 ], + })) this.override({ title: "", diff --git a/panel/models/ipywidget.ts b/panel/models/ipywidget.ts index 01de9bb387..8e65cdc24f 100644 --- a/panel/models/ipywidget.ts +++ b/panel/models/ipywidget.ts @@ -74,8 +74,8 @@ export class IPyWidget extends HTMLBox { static init_IPyWidget(): void { this.prototype.default_view = IPyWidgetView - this.define({ - bundle: [ p.Any, {} ], - }) + this.define(({Any}) => ({ + bundle: [ Any, {} ], + })) } } diff --git a/panel/models/json.ts b/panel/models/json.ts index 3d00c0179a..8e4ac077f1 100644 --- a/panel/models/json.ts +++ b/panel/models/json.ts @@ -1,3 +1,4 @@ +import {Enum} from "@bokehjs/core/kinds" import * as p from "@bokehjs/core/properties" import {Markup} from "@bokehjs/models/widgets/markup" import JSONFormatter from "json-formatter-js" @@ -35,15 +36,14 @@ export class JSONView extends PanelMarkupView { } } -type Theme = "light" | "dark" -const Theme: Theme[] = ["dark", "light"] +export const JSONTheme = Enum("dark", "light") export namespace JSON { export type Attrs = p.AttrsOf export type Props = Markup.Props & { - depth: p.Property + depth: p.Property hover_preview: p.Property - theme: p.Property<"light" | "dark"> + theme: p.Property } } @@ -60,10 +60,10 @@ export class JSON extends Markup { static init_JSON(): void { this.prototype.default_view = JSONView - this.define({ - depth: [p.Number, 1], - hover_preview: [p.Boolean, false], - theme: [p.Enum(Theme), "dark"], - }) + this.define(({Boolean, Int, Nullable}) => ({ + depth: [ Nullable(Int), 1 ], + hover_preview: [ Boolean, false ], + theme: [ JSONTheme, "dark" ], + })) } } diff --git a/panel/models/layout.py b/panel/models/layout.py index 7ec2d0bc1f..362a8567b6 100644 --- a/panel/models/layout.py +++ b/panel/models/layout.py @@ -1,10 +1,10 @@ -from bokeh.core.properties import String, List, Bool +from bokeh.core.properties import Bool, List, Nullable, String from bokeh.models import Column class Card(Column): - active_header_background = String(help="Background color of active Card header.") + active_header_background = Nullable(String, help="Background color of active Card header.") button_css_classes = List(String, help="CSS classes to add to the Card collapse button.") @@ -12,9 +12,9 @@ class Card(Column): collapsible = Bool(True, help="Whether the Card should have a button to collapse it.") - header_background = String(help="Background color of the Card header.") + header_background = Nullable(String, help="Background color of the Card header.") - header_color = String(help="Color of the header text and butotn.") + header_color = Nullable(String, help="Color of the header text and button.") header_css_classes = List(String, help="CSS classes to add to the Card header.") diff --git a/panel/models/location.ts b/panel/models/location.ts index d18445ea0d..d414aab13d 100644 --- a/panel/models/location.ts +++ b/panel/models/location.ts @@ -77,15 +77,15 @@ export class Location extends Model { static init_Location(): void { this.prototype.default_view = LocationView; - this.define({ - href: [p.String, ''], - hostname: [p.String, ''], - pathname: [p.String, ''], - protocol: [p.String, ''], - port: [p.String, ''], - search: [p.String, ''], - hash: [p.String, ''], - reload: [p.Boolean, false], - }) + this.define(({Boolean, String}) => ({ + href: [ String, "" ], + hostname: [ String, "" ], + pathname: [ String, "" ], + protocol: [ String, "" ], + port: [ String, "" ], + search: [ String, "" ], + hash: [ String, "" ], + reload: [ Boolean, false ], + })) } } diff --git a/panel/models/markup.py b/panel/models/markup.py index d75ebbd518..0b916f66e9 100644 --- a/panel/models/markup.py +++ b/panel/models/markup.py @@ -3,7 +3,7 @@ """ from __future__ import absolute_import, division, unicode_literals -from bokeh.core.properties import Bool, Either, Int, Float, String +from bokeh.core.properties import Bool, Either, Int, Float, Nullable, String from bokeh.models.widgets import Markup @@ -18,7 +18,7 @@ class JSON(Markup): A bokeh model that renders JSON as tree. """ - depth = Either(Int, Float, default=1, help="Depth to which the JSON tree is expanded.") + depth = Either(Nullable(Int), Float, default=1, help="Depth to which the JSON tree is expanded.") hover_preview = Bool(default=False, help="Whether to show a hover preview for collapsed nodes.") diff --git a/panel/models/player.ts b/panel/models/player.ts index 7e73ce690e..e5737ec91f 100644 --- a/panel/models/player.ts +++ b/panel/models/player.ts @@ -1,3 +1,4 @@ +import {Enum} from "@bokehjs/core/kinds" import * as p from "@bokehjs/core/properties" import {div} from "@bokehjs/core/dom" import {Widget, WidgetView} from "@bokehjs/models/widgets/widget" @@ -182,8 +183,6 @@ export class PlayerView extends WidgetView { this.loop_state.appendChild(reflect) this.loop_state.appendChild(reflect_label) - - this.groupEl.appendChild(this.sliderEl) this.groupEl.appendChild(button_div) if (this.model.show_loop_controls) @@ -309,6 +308,8 @@ export class PlayerView extends WidgetView { } } +export const LoopPolicy = Enum("once", "loop", "reflect") + export namespace Player { export type Attrs = p.AttrsOf export type Props = Widget.Props & { @@ -317,12 +318,13 @@ export namespace Player { start: p.Property end: p.Property step: p.Property - loop_policy: p.Property + loop_policy: p.Property value: p.Property show_loop_controls: p.Property } } + export interface Player extends Player.Attrs {} export class Player extends Widget { @@ -338,16 +340,16 @@ export class Player extends Widget { static init_Player(): void { this.prototype.default_view = PlayerView - this.define({ - direction: [ p.Number, 0 ], - interval: [ p.Number, 500 ], - start: [ p.Number, ], - end: [ p.Number, ], - step: [ p.Number, 1 ], - loop_policy: [ p.Any, "once" ], - value: [ p.Any, 0 ], - show_loop_controls: [ p.Boolean, true ], - }) + this.define(({Boolean, Int}) => ({ + direction: [ Int, 0 ], + interval: [ Int, 500 ], + start: [ Int ], + end: [ Int ], + step: [ Int, 1 ], + loop_policy: [ LoopPolicy, "once" ], + value: [ Int, 0 ], + show_loop_controls: [ Boolean, true ], + })) this.override({width: 400}) } diff --git a/panel/models/singleselect.ts b/panel/models/singleselect.ts index 8513c7f2f4..ba97ae655b 100644 --- a/panel/models/singleselect.ts +++ b/panel/models/singleselect.ts @@ -106,10 +106,10 @@ export class SingleSelect extends InputWidget { static init_SingleSelect(): void { this.prototype.default_view = SingleSelectView - this.define({ - value: [ p.String, "" ], - options: [ p.Array, [] ], - size: [ p.Number, 4 ], // 4 is the HTML default - }) + this.define(({Any, Array, Int, String}) => ({ + value: [ String, "" ], + options: [ Array(Any), [] ], + size: [ Int, 4 ], // 4 is the HTML default + })) } } diff --git a/panel/models/state.ts b/panel/models/state.ts index fd80707e4f..afca65194c 100644 --- a/panel/models/state.ts +++ b/panel/models/state.ts @@ -94,11 +94,11 @@ export class State extends Model { static init_State(): void { this.prototype.default_view = StateView - this.define({ - json: [ p.Boolean, false ], - state: [ p.Any, {} ], - widgets: [ p.Any, {} ], - values: [ p.Any, [] ], - }) + this.define(({Any, Boolean}) => ({ + json: [ Boolean, false ], + state: [ Any, {} ], + widgets: [ Any, {} ], + values: [ Any, [] ], + })) } } diff --git a/panel/models/tabulator.py b/panel/models/tabulator.py index 7ba1772e98..3381dad648 100644 --- a/panel/models/tabulator.py +++ b/panel/models/tabulator.py @@ -4,7 +4,7 @@ See http://tabulator.info/ """ from bokeh.core.properties import ( - Any, Bool, Dict, Enum, Instance, Int, List, String + Any, Bool, Dict, Enum, Instance, Int, List, Nullable, String ) from bokeh.models import ColumnDataSource from bokeh.models.layouts import HTMLBox @@ -37,7 +37,7 @@ class DataTabulator(HTMLBox): filename = String(default="table.csv") - follow = Bool() + follow = Bool(True) frozen_rows = List(Int) @@ -51,9 +51,9 @@ class DataTabulator(HTMLBox): styles = Dict(Int, Dict(Int, List(String))) - pagination = String() + pagination = Nullable(String) - page = Int() + page = Nullable(Int) page_size = Int() diff --git a/panel/models/tabulator.ts b/panel/models/tabulator.ts index 04ae34b536..851dffdff8 100644 --- a/panel/models/tabulator.ts +++ b/panel/models/tabulator.ts @@ -1,5 +1,6 @@ import {HTMLBox} from "@bokehjs/models/layouts/html_box" import {div} from "@bokehjs/core/dom" +import {Enum} from "@bokehjs/core/kinds" import * as p from "@bokehjs/core/properties"; import {ColumnDataSource} from "@bokehjs/models/sources/column_data_source"; import {TableColumn} from "@bokehjs/models/widgets/tables" @@ -485,9 +486,10 @@ export class DataTabulatorView extends PanelHTMLBoxView { this.model.source.patch({[field]: [[index, value]]}); this._tabulator_cell_updating = false } - } +export const TableLayout = Enum("fit_data", "fit_data_fill", "fit_data_stretch", "fit_data_table", "fit_columns") + export namespace DataTabulator { export type Attrs = p.AttrsOf export type Props = HTMLBox.Props & { @@ -500,7 +502,7 @@ export namespace DataTabulator { frozen_rows: p.Property groupby: p.Property hidden_columns: p.Property - layout: p.Property<"fit_data" | "fit_data_fill" | "fit_data_stretch" | "fit_data_table" | "fit_columns"> + layout: p.Property max_page: p.Property page: p.Property page_size: p.Property @@ -528,26 +530,26 @@ export class DataTabulator extends HTMLBox { static init_DataTabulator(): void { this.prototype.default_view = DataTabulatorView; - this.define({ - configuration: [p.Any, ], - columns: [ p.Array, [] ], - download: [ p.Boolean, true ], - editable: [ p.Boolean, true ], - filename: [ p.String, 'table.csv'], - follow: [p.Boolean, ], - frozen_rows: [ p.Array, []], - groupby: [ p.Array, [] ], - hidden_columns: [ p.Array, [] ], - layout: [ p.Any, "fit_data" ], - max_page: [ p.Number, 0 ], - pagination: [ p.String, null ], - page: [ p.Number, 0], - page_size: [ p.Number, 0], - source: [ p.Any, ], - sorters: [ p.Array, []], - styles: [ p.Any, ], - theme: [ p.String, "simple"], - theme_url: [p.String, "https://unpkg.com/tabulator-tables@4.9.3/dist/css/"] - }) + this.define(({Any, Array, Boolean, Nullable, Number, Ref, String}) => ({ + configuration: [ Any, {} ], + columns: [ Array(Ref(TableColumn)), [] ], + download: [ Boolean, true ], + editable: [ Boolean, true ], + filename: [ String, "table.csv" ], + follow: [ Boolean, true ], + frozen_rows: [ Array(Number), [] ], + groupby: [ Array(String), [] ], + hidden_columns: [ Array(String), [] ], + layout: [ TableLayout, "fit_data" ], + max_page: [ Number, 0 ], + pagination: [ Nullable(String), null ], + page: [ Number, 0 ], + page_size: [ Number, 0 ], + source: [ Ref(ColumnDataSource) ], + sorters: [ Array(Any), [] ], + styles: [ Any, {} ], + theme: [ String, "simple" ], + theme_url: [ String, "https://unpkg.com/tabulator-tables@4.9.3/dist/css/"] + })) } } diff --git a/panel/models/vega.py b/panel/models/vega.py index 8897a985c8..2573fea54c 100644 --- a/panel/models/vega.py +++ b/panel/models/vega.py @@ -1,7 +1,7 @@ """ Defines custom VegaPlot bokeh model to render Vega json plots. """ -from bokeh.core.properties import Dict, String, Any, Instance +from bokeh.core.properties import Any, Dict, Instance, Nullable, String from bokeh.models import LayoutDOM, ColumnDataSource from ..util import classproperty, bundled_files @@ -41,6 +41,6 @@ def __js_skip__(cls): 'exports': {'vega-embed': 'vegaEmbed', 'vega': 'vega', 'vega-lite': 'vl'} } - data = Dict(String, Any) + data = Nullable(Dict(String, Any)) data_sources = Dict(String, Instance(ColumnDataSource)) diff --git a/panel/models/vega.ts b/panel/models/vega.ts index 2a01677134..f975c55415 100644 --- a/panel/models/vega.ts +++ b/panel/models/vega.ts @@ -94,9 +94,9 @@ export class VegaPlot extends HTMLBox { static init_VegaPlot(): void { this.prototype.default_view = VegaPlotView - this.define({ - data: [ p.Any ], - data_sources: [ p.Any ], - }) + this.define(({Any}) => ({ + data: [ Any, {} ], + data_sources: [ Any, {} ], + })) } } diff --git a/panel/models/video.ts b/panel/models/video.ts index fdeabde529..65c6eb11af 100644 --- a/panel/models/video.ts +++ b/panel/models/video.ts @@ -138,13 +138,13 @@ export class Video extends HTMLBox { static init_Video(): void { this.prototype.default_view = VideoView - this.define({ - loop: [ p.Boolean, false ], - paused: [ p.Boolean, true ], - time: [ p.Number, 0 ], - throttle: [ p.Number, 250 ], - value: [ p.Any, '' ], - volume: [ p.Number, null ], - }) + this.define(({Any, Boolean, Int, Number}) => ({ + loop: [ Boolean, false ], + paused: [ Boolean, true ], + time: [ Number, 0 ], + throttle: [ Int, 250 ], + value: [ Any, '' ], + volume: [ Int ], + })) } } diff --git a/panel/models/videostream.ts b/panel/models/videostream.ts index a98c4ed427..8f1ae55067 100644 --- a/panel/models/videostream.ts +++ b/panel/models/videostream.ts @@ -117,13 +117,13 @@ export class VideoStream extends HTMLBox { static init_VideoStream(): void { this.prototype.default_view = VideoStreamView - this.define({ - format: [ p.String, 'png' ], - paused: [ p.Boolean, false ], - snapshot: [ p.Boolean, false ], - timeout: [ p.Number, 0 ], - value: [ p.Any, ] - }) + this.define(({Any, Boolean, Number, String}) => ({ + format: [ String, 'png' ], + paused: [ Boolean, false ], + snapshot: [ Boolean, false ], + timeout: [ Number, 0 ], + value: [ Any ] + })) this.override({ height: 240, diff --git a/panel/models/vtk.py b/panel/models/vtk.py index f00fb9d1da..fe7015b282 100644 --- a/panel/models/vtk.py +++ b/panel/models/vtk.py @@ -2,9 +2,10 @@ """ Defines custom VTKPlot bokeh model to render VTK objects. """ -from bokeh.core.properties import (String, Bool, Dict, Any, Override, - Instance, Int, Float, PositiveInt, - Enum, List) +from bokeh.core.properties import ( + String, Bool, Dict, Any, Override, Instance, Int, Float, PositiveInt, + Enum, List, Nullable +) from bokeh.core.has_props import abstract from bokeh.core.enums import enumeration from bokeh.models import HTMLBox, Model, ColorMapper @@ -100,7 +101,7 @@ class VTKJSPlot(AbstractVTKPlot): Bokeh model for plotting a 3D scene saved in the `.vtk-js` format """ - data = String(help="""The serialized vtk.js data""") + data = Nullable(String, help="""The serialized vtk.js data""") enable_keybindings = Bool(default=False) @@ -117,7 +118,7 @@ class VTKVolumePlot(AbstractVTKPlot): controller_expanded = Bool(default=True, help=""" If True the volume controller panel options is expanded in the view""") - data = Dict(String, Any) + data = Nullable(Dict(String, Any)) diffuse = Float(default=0.7) diff --git a/panel/models/vtk/util.ts b/panel/models/vtk/util.ts index f918f30484..2926f5b577 100644 --- a/panel/models/vtk/util.ts +++ b/panel/models/vtk/util.ts @@ -1,4 +1,5 @@ import {linspace} from "@bokehjs/core/util/array" +import {Enum} from "@bokehjs/core/kinds" export const ARRAY_TYPES = { uint8: Uint8Array, @@ -95,11 +96,16 @@ declare type RGBnode = { b: number } -export declare type ColorMapper = { +export type ColorMapper = { palette: string[] low: number high: number } + + +export const Interpolation = Enum("fast_linear", "linear", "nearest") +export type Interpolation = typeof Interpolation["__type__"] + export declare type CSSProperties = {[key: string]: string} export declare type VolumeType = { diff --git a/panel/models/vtk/vtkjs.ts b/panel/models/vtk/vtkjs.ts index d2088b8e63..e7d0f13465 100644 --- a/panel/models/vtk/vtkjs.ts +++ b/panel/models/vtk/vtkjs.ts @@ -72,9 +72,9 @@ export class VTKJSPlot extends AbstractVTKPlot { static init_VTKJSPlot(): void { this.prototype.default_view = VTKJSPlotView - this.define({ - data: [ p.String ], - enable_keybindings: [ p.Boolean, false ], - }) + this.define(({Boolean, Nullable, String}) => ({ + data: [ Nullable(String) ], + enable_keybindings: [ Boolean, false ], + })) } } diff --git a/panel/models/vtk/vtklayout.ts b/panel/models/vtk/vtklayout.ts index 13876f3edc..dd9df5a269 100644 --- a/panel/models/vtk/vtklayout.ts +++ b/panel/models/vtk/vtklayout.ts @@ -381,7 +381,7 @@ export namespace AbstractVTKPlot { export type Props = HTMLBox.Props & { axes: p.Property camera: p.Property - data: p.Property + data: p.Property enable_keybindings: p.Property orientation_widget: p.Property color_mappers: p.Property diff --git a/panel/models/vtk/vtkvolume.ts b/panel/models/vtk/vtkvolume.ts index f7846e60b2..9a37abcaf0 100644 --- a/panel/models/vtk/vtkvolume.ts +++ b/panel/models/vtk/vtkvolume.ts @@ -2,15 +2,16 @@ import * as p from "@bokehjs/core/properties" import {AbstractVTKPlot, AbstractVTKView} from "./vtklayout" import { + ColorMapper, + Interpolation, VolumeType, vtkns, data2VTKImageData, hexToRGB, vtkLutToMapper, - ColorMapper, } from "./util" -declare type InterpolationType = "fast_linear" | "linear" | "nearest" + export class VTKVolumePlotView extends AbstractVTKView { model: VTKVolumePlot protected _controllerWidget: any @@ -344,7 +345,7 @@ export class VTKVolumePlotView extends AbstractVTKView { this._vtk_renwin.getRenderer().addVolume(actor) } - _set_interpolation(interpolation: InterpolationType): void { + _set_interpolation(interpolation: Interpolation): void { if (interpolation == "fast_linear") { this.volume.getProperty().setInterpolationTypeToFastLinear() this.image_actor_i.getProperty().setInterpolationTypeToLinear() @@ -379,7 +380,7 @@ export namespace VTKVolumePlot { display_slices: p.Property display_volume: p.Property edge_gradient: p.Property - interpolation: p.Property + interpolation: p.Property mapper: p.Property render_background: p.Property rescale: p.Property @@ -406,26 +407,26 @@ export class VTKVolumePlot extends AbstractVTKPlot { static init_VTKVolumePlot(): void { this.prototype.default_view = VTKVolumePlotView - this.define({ - ambient: [ p.Number, 0.2 ], - colormap: [ p.String ], - data: [ p.Instance ], - diffuse: [ p.Number, 0.7 ], - display_slices: [ p.Boolean, false ], - display_volume: [ p.Boolean, true ], - edge_gradient: [ p.Number, 0.2 ], - interpolation: [ p.Any, 'fast_linear'], - mapper: [ p.Instance ], - render_background: [ p.String, '#52576e' ], - rescale: [ p.Boolean, false ], - sampling: [ p.Number, 0.4 ], - shadow: [ p.Boolean, true ], - slice_i: [ p.Int, 0 ], - slice_j: [ p.Int, 0 ], - slice_k: [ p.Int, 0 ], - specular: [ p.Number, 0.3 ], - specular_power: [ p.Number, 8.0 ], - controller_expanded: [ p.Boolean, true ], - }) + this.define(({Any, Array, Boolean, Int, Number, String, Struct}) => ({ + ambient: [ Number, 0.2 ], + colormap: [ String ], + data: [ Any ], + diffuse: [ Number, 0.7 ], + display_slices: [ Boolean, false ], + display_volume: [ Boolean, true ], + edge_gradient: [ Number, 0.2 ], + interpolation: [ Interpolation, 'fast_linear'], + mapper: [ Struct({palette: Array(String), low: Number, high: Number}) ], + render_background: [ String, '#52576e' ], + rescale: [ Boolean, false ], + sampling: [ Number, 0.4 ], + shadow: [ Boolean, true ], + slice_i: [ Int, 0 ], + slice_j: [ Int, 0 ], + slice_k: [ Int, 0 ], + specular: [ Number, 0.3 ], + specular_power: [ Number, 8.0 ], + controller_expanded: [ Boolean, true ], + })) } } diff --git a/panel/models/widgets.py b/panel/models/widgets.py index 945fb49b52..4fbcc429f5 100644 --- a/panel/models/widgets.py +++ b/panel/models/widgets.py @@ -93,7 +93,7 @@ class Video(HTMLBox): value = Any(help="Encoded file data") - volume = Int(0, help="""The volume of the video player.""") + volume = Int(help="""The volume of the video player.""") class VideoStream(HTMLBox): diff --git a/panel/package-lock.json b/panel/package-lock.json index df9e535268..6e506bdb92 100644 --- a/panel/package-lock.json +++ b/panel/package-lock.json @@ -20,9 +20,9 @@ "devDependencies": {} }, "node_modules/@bokeh/bokehjs": { - "version": "2.3.0-dev.11", - "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-2.3.0-dev.11.tgz", - "integrity": "sha512-k7IKiYsiHOcQS0UZqzLLzdBucKkmjif5ogMG5pzKp1zR9AKy7SfpB5PPTvfcTasbP3HgLRZdNsLjD3YboPVdRA==", + "version": "2.3.0-dev.12", + "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-2.3.0-dev.12.tgz", + "integrity": "sha512-9T1CWvJonH53qe0ZlsL0pHhcQwACqHJ8JT6VipRUl53D2G3/GYYwUdEXxz4Tw4bdjXEFxGMoVSbLOGkgsrWh3g==", "dependencies": { "@bokeh/numbro": "^1.6.2", "@bokeh/slickgrid": "~2.4.2701", @@ -38,7 +38,6 @@ "hammerjs": "^2.0.4", "nouislider": "^14.6.3", "proj4": "^2.6.3", - "proxy-polyfill": "^0.3.2", "sprintf-js": "^1.1.2", "timezone": "^1.0.23", "tslib": "^2.0.3", @@ -46,7 +45,7 @@ }, "engines": { "node": ">=14", - "npm": ">=7.1" + "npm": ">=7.4" } }, "node_modules/@bokeh/bokehjs/node_modules/tslib": { @@ -298,11 +297,6 @@ "wkt-parser": "^1.2.4" } }, - "node_modules/proxy-polyfill": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/proxy-polyfill/-/proxy-polyfill-0.3.2.tgz", - "integrity": "sha512-ENKSXOMCewnQTOyqrQXxEjIhzT6dy572mtehiItbDoIUF5Sv5UkmRUc8kowg2MFvr232Uo8rwRpNg3V5kgTKbA==" - }, "node_modules/redux": { "version": "4.0.5", "license": "MIT", @@ -345,9 +339,9 @@ }, "dependencies": { "@bokeh/bokehjs": { - "version": "2.3.0-dev.11", - "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-2.3.0-dev.11.tgz", - "integrity": "sha512-k7IKiYsiHOcQS0UZqzLLzdBucKkmjif5ogMG5pzKp1zR9AKy7SfpB5PPTvfcTasbP3HgLRZdNsLjD3YboPVdRA==", + "version": "2.3.0-dev.12", + "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-2.3.0-dev.12.tgz", + "integrity": "sha512-9T1CWvJonH53qe0ZlsL0pHhcQwACqHJ8JT6VipRUl53D2G3/GYYwUdEXxz4Tw4bdjXEFxGMoVSbLOGkgsrWh3g==", "requires": { "@bokeh/numbro": "^1.6.2", "@bokeh/slickgrid": "~2.4.2701", @@ -363,7 +357,6 @@ "hammerjs": "^2.0.4", "nouislider": "^14.6.3", "proj4": "^2.6.3", - "proxy-polyfill": "^0.3.2", "sprintf-js": "^1.1.2", "timezone": "^1.0.23", "tslib": "^2.0.3", @@ -574,11 +567,6 @@ "wkt-parser": "^1.2.4" } }, - "proxy-polyfill": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/proxy-polyfill/-/proxy-polyfill-0.3.2.tgz", - "integrity": "sha512-ENKSXOMCewnQTOyqrQXxEjIhzT6dy572mtehiItbDoIUF5Sv5UkmRUc8kowg2MFvr232Uo8rwRpNg3V5kgTKbA==" - }, "redux": { "version": "4.0.5", "requires": { diff --git a/panel/pane/plotly.py b/panel/pane/plotly.py index 9825373bd3..179142c44e 100644 --- a/panel/pane/plotly.py +++ b/panel/pane/plotly.py @@ -214,8 +214,9 @@ def _get_model(self, doc, root=None, parent=None, comm=None): properties['sizing_mode'] = 'stretch_both' model = PlotlyPlot( - data=data, layout=layout, config=self.config, data_sources=sources, - _render_count=self._render_count, **properties + data=data, layout=layout, config=self.config or {}, + data_sources=sources, _render_count=self._render_count, + **properties ) if root is None: diff --git a/panel/pane/vtk/vtk.py b/panel/pane/vtk/vtk.py index b66cf8252e..e06c75aff4 100644 --- a/panel/pane/vtk/vtk.py +++ b/panel/pane/vtk/vtk.py @@ -36,7 +36,7 @@ class AbstractVTK(PaneBase): __abstract = True - axes = param.Dict(doc=""" + axes = param.Dict(default={}, doc=""" Parameters of the axes to construct in the 3d view. Must contain at least ``xticker``, ``yticker`` and ``zticker``. @@ -650,10 +650,10 @@ def _get_model(self, doc, root=None, parent=None, comm=None): VTKVolumePlot = getattr(sys.modules['panel.models.vtk'], 'VTKVolumePlot') props = self._process_param_change(self._init_properties()) - volume_data = self._volume_data + if self._volume_data is not None: + props['data'] = self._volume_data - model = VTKVolumePlot(data=volume_data, - **props) + model = VTKVolumePlot(**props) if root is None: root = model self._link_props(model, ['colormap', 'orientation_widget', 'camera', 'mapper', 'controller_expanded'], doc, root, comm) @@ -820,10 +820,11 @@ def _get_model(self, doc, root=None, parent=None, comm=None): else: VTKJSPlot = getattr(sys.modules['panel.models.vtk'], 'VTKJSPlot') - vtkjs = self._get_vtkjs() - data = base64encode(vtkjs) if vtkjs is not None else vtkjs props = self._process_param_change(self._init_properties()) - model = VTKJSPlot(data=data, **props) + vtkjs = self._get_vtkjs() + if vtkjs is not None: + props['data'] = base64encode(vtkjs) + model = VTKJSPlot(**props) if root is None: root = model self._link_props(model, ['camera', 'enable_keybindings', 'orientation_widget'], doc, root, comm) diff --git a/panel/tests/test_param.py b/panel/tests/test_param.py index 02fa2202f7..fe71c90635 100644 --- a/panel/tests/test_param.py +++ b/panel/tests/test_param.py @@ -656,14 +656,12 @@ class Test(param.Parameterized): assert len(model.children) == 2 _, number = model.children - number.value_throttled = 3 + pane._widgets['a']._process_events({'value_throttled': 3}) assert number.value != 3 - assert number.value_throttled == 3 assert test.a == 3 test.a = 4 assert number.value != 4 - assert number.value_throttled == 4 assert test.a == 4 diff --git a/panel/tests/widgets/test_select.py b/panel/tests/widgets/test_select.py index 89aa1aa642..40f1231654 100644 --- a/panel/tests/widgets/test_select.py +++ b/panel/tests/widgets/test_select.py @@ -74,7 +74,7 @@ def test_select_change_options(document, comm): select.options = {} assert select.value == None - assert widget.value == None + assert widget.value == '' def test_select_non_hashable_options(document, comm): diff --git a/panel/tests/widgets/test_slider.py b/panel/tests/widgets/test_slider.py index 4aa40aebb0..3e306d7816 100644 --- a/panel/tests/widgets/test_slider.py +++ b/panel/tests/widgets/test_slider.py @@ -5,7 +5,6 @@ from bokeh.models import Div as BkDiv, Slider as BkSlider, Column as BkColumn -import param from panel.widgets import (DateSlider, DateRangeSlider, DiscreteSlider, FloatSlider, IntSlider, RangeSlider) @@ -22,7 +21,6 @@ def test_float_slider(document, comm): assert widget.start == 0.1 assert widget.end == 0.5 assert widget.value == 0.4 - assert widget.value_throttled == 0.4 slider._process_events({'value': 0.2}) assert slider.value == 0.2 @@ -31,8 +29,6 @@ def test_float_slider(document, comm): slider.value = 0.3 assert widget.value == 0.3 - slider.value_throttled = 0.3 - assert widget.value_throttled == 0.3 def test_int_slider(document, comm): @@ -47,7 +43,6 @@ def test_int_slider(document, comm): assert widget.start == 0 assert widget.end == 3 assert widget.value == 1 - assert widget.value_throttled == 1 slider._process_events({'value': 2}) assert slider.value == 2 @@ -63,7 +58,6 @@ def test_int_slider(document, comm): slider_2 = IntSlider(start=1, end=3, name='Slider_2') widget_2 = slider_2.get_root(document, comm=comm) assert widget_2.value == widget_2.start - assert widget_2.value_throttled == widget_2.start def test_range_slider(document, comm): @@ -78,7 +72,6 @@ def test_range_slider(document, comm): assert widget.start == 0 assert widget.end == 3 assert widget.value == (0, 3) - assert widget.value_throttled == (0, 3) slider._process_events({'value': (0, 2)}) assert slider.value == (0, 2) @@ -87,8 +80,6 @@ def test_range_slider(document, comm): slider.value = (0, 1) assert widget.value == (0, 1) - slider.value_throttled = (0, 1) - assert widget.value_throttled == (0, 1) def test_date_slider(document, comm): @@ -101,7 +92,6 @@ def test_date_slider(document, comm): assert isinstance(widget, date_slider._widget_type) assert widget.title == 'DateSlider' assert widget.value == 1536019200000 - assert widget.value_throttled == 1536019200000 assert widget.start == 1535760000000.0 assert widget.end == 1536537600000.0 @@ -109,8 +99,7 @@ def test_date_slider(document, comm): widget.value = (datetime(2018, 9, 3)-epoch).total_seconds()*1000 date_slider._process_events({'value': widget.value}) assert date_slider.value == date(2018, 9, 3) - widget.value_throttled = (datetime(2018, 9, 3)-epoch).total_seconds()*1000 - date_slider._process_events({'value_throttled': widget.value}) + date_slider._process_events({'value_throttled': (datetime(2018, 9, 3)-epoch).total_seconds()*1000}) assert date_slider.value_throttled == date(2018, 9, 3) # Test raw timestamp value: @@ -121,8 +110,6 @@ def test_date_slider(document, comm): date_slider.value = date(2018, 9, 6) assert widget.value == 1536192000000 - date_slider.value_throttled = date(2018, 9, 6) - assert widget.value_throttled == 1536192000000 def test_date_range_slider(document, comm): @@ -135,7 +122,6 @@ def test_date_range_slider(document, comm): assert isinstance(widget, date_slider._widget_type) assert widget.title == 'DateRangeSlider' assert widget.value == (1535846400000, 1536019200000) - assert widget.value_throttled == (1535846400000, 1536019200000) assert widget.start == 1535760000000 assert widget.end == 1536537600000 @@ -144,16 +130,13 @@ def test_date_range_slider(document, comm): (datetime(2018, 9, 6)-epoch).total_seconds()*1000) date_slider._process_events({'value': widget.value}) assert date_slider.value == (datetime(2018, 9, 3), datetime(2018, 9, 6)) - widget.value_throttled = ((datetime(2018, 9, 3)-epoch).total_seconds()*1000, + value_throttled = ((datetime(2018, 9, 3)-epoch).total_seconds()*1000, (datetime(2018, 9, 6)-epoch).total_seconds()*1000) - date_slider._process_events({'value_throttled': widget.value_throttled}) + date_slider._process_events({'value_throttled': value_throttled}) assert date_slider.value == (datetime(2018, 9, 3), datetime(2018, 9, 6)) date_slider.value = (datetime(2018, 9, 4), datetime(2018, 9, 6)) assert widget.value == (1536019200000, 1536192000000) - date_slider.value_throttled = (datetime(2018, 9, 4), datetime(2018, 9, 6)) - assert widget.value_throttled == (1536019200000, 1536192000000) - def test_discrete_slider(document, comm): @@ -167,7 +150,6 @@ def test_discrete_slider(document, comm): assert isinstance(label, BkDiv) assert isinstance(widget, BkSlider) assert widget.value == 1 - assert widget.value_throttled == 1 assert widget.start == 0 assert widget.end == 3 assert widget.step == 1 @@ -181,9 +163,6 @@ def test_discrete_slider(document, comm): discrete_slider.value = 100 assert widget.value == 3 - with param.edit_constant(discrete_slider): - discrete_slider.value_throttled = 100 - assert widget.value_throttled == 3 def test_discrete_slider_label_update(document, comm): @@ -211,7 +190,6 @@ def test_discrete_date_slider(document, comm): assert isinstance(label, BkDiv) assert isinstance(widget, BkSlider) assert widget.value == 1 - assert widget.value_throttled == 1 assert widget.start == 0 assert widget.end == 2 assert widget.step == 1 @@ -225,9 +203,6 @@ def test_discrete_date_slider(document, comm): discrete_slider.value = dates['2016-01-01'] assert widget.value == 0 - with param.edit_constant(discrete_slider): - discrete_slider.value_throttled = dates['2016-01-01'] - assert widget.value_throttled == 0 def test_discrete_slider_options_dict(document, comm): @@ -242,7 +217,6 @@ def test_discrete_slider_options_dict(document, comm): assert isinstance(label, BkDiv) assert isinstance(widget, BkSlider) assert widget.value == 1 - assert widget.value_throttled == 1 assert widget.start == 0 assert widget.end == 3 assert widget.step == 1 @@ -256,6 +230,3 @@ def test_discrete_slider_options_dict(document, comm): discrete_slider.value = 100 assert widget.value == 3 - with param.edit_constant(discrete_slider): - discrete_slider.value_throttled = 100 - assert widget.value_throttled == 3 diff --git a/panel/widgets/input.py b/panel/widgets/input.py index 6e237b377f..c9e4960a95 100644 --- a/panel/widgets/input.py +++ b/panel/widgets/input.py @@ -256,6 +256,9 @@ class IntInput(_SpinnerBase, _IntInputBase): value_throttled = param.Integer(default=None, constant=True) + _rename = dict(_NumericInputBase._rename, value_throttled=None) + + class FloatInput(_SpinnerBase, _FloatInputBase): @@ -263,6 +266,8 @@ class FloatInput(_SpinnerBase, _FloatInputBase): value_throttled = param.Number(default=None, constant=True) + _rename = dict(_NumericInputBase._rename, value_throttled=None) + class NumberInput(_SpinnerBase): diff --git a/panel/widgets/select.py b/panel/widgets/select.py index c7e5058774..e72e9062d5 100644 --- a/panel/widgets/select.py +++ b/panel/widgets/select.py @@ -73,8 +73,9 @@ def _process_param_change(self, msg): msg['value'] = unicode_values[indexOf(val, values)] elif values: self.value = self.values[0] - elif self.value is not None: + else: self.value = None + msg['value'] = '' if 'options' in msg: if isinstance(self.options, dict): @@ -89,7 +90,7 @@ def _process_param_change(self, msg): if values: if not isIn(val, values): self.value = values[0] - elif val is not None: + else: self.value = None return msg @@ -102,8 +103,8 @@ def _process_property_change(self, msg): if 'value' in msg: if not self.values: pass - elif msg['value'] is None: - msg['value'] = self.values[0] + elif msg['value'] == '': + msg['value'] = self.values[0] if self.values else None else: if isIn(msg['value'], self.unicode_values): idx = indexOf(msg['value'], self.unicode_values) diff --git a/panel/widgets/slider.py b/panel/widgets/slider.py index 17f52a4fc0..d48fcb7044 100644 --- a/panel/widgets/slider.py +++ b/panel/widgets/slider.py @@ -118,6 +118,8 @@ class FloatSlider(ContinuousSlider): step = param.Number(default=0.1) + _rename = {'name': 'title', 'value_throttled': None} + class IntSlider(ContinuousSlider): @@ -131,6 +133,8 @@ class IntSlider(ContinuousSlider): step = param.Integer(default=1) + _rename = {'name': 'title', 'value_throttled': None} + def _process_property_change(self, msg): msg = super(_SliderBase, self)._process_property_change(msg) if 'value' in msg: @@ -151,6 +155,8 @@ class DateSlider(_SliderBase): end = param.Date(default=None) + _rename = {'name': 'title', 'value_throttled': None} + _source_transforms = {'value': None, 'value_throttled': None, 'start': None, 'end': None} _widget_type = _BkDateSlider @@ -345,6 +351,8 @@ class RangeSlider(_SliderBase): step = param.Number(default=0.1) + _rename = {'name': 'title', 'value_throttled': None} + _widget_type = _BkRangeSlider def __init__(self, **params): @@ -400,6 +408,8 @@ class DateRangeSlider(_SliderBase): _source_transforms = {'value': None, 'value_throttled': None, 'start': None, 'end': None, 'step': None} + _rename = {'name': 'title', 'value_throttled': None} + _widget_type = _BkDateRangeSlider def __init__(self, **params): @@ -408,6 +418,12 @@ def __init__(self, **params): params.get('end', self.end)) super(DateRangeSlider, self).__init__(**params) + def _process_param_change(self, msg): + msg = super()._process_param_change(msg) + if msg.get('value') == (None, None): + del msg['value'] + return msg + def _process_property_change(self, msg): msg = super(DateRangeSlider, self)._process_property_change(msg) if 'value' in msg: diff --git a/panel/widgets/tables.py b/panel/widgets/tables.py index 50f7bc446c..abbacb0d38 100644 --- a/panel/widgets/tables.py +++ b/panel/widgets/tables.py @@ -166,8 +166,6 @@ def _get_column_definitions(self, col_names, df): col_kwargs['width'] = self.widths elif str(col) in self.widths: col_kwargs['width'] = self.widths.get(str(col)) - else: - col_kwargs['width'] = None title = self.titles.get(col, str(col)) if col in indexes and len(indexes) > 1 and self.hierarchical: diff --git a/setup.py b/setup.py index 0070222adb..7ededade3c 100644 --- a/setup.py +++ b/setup.py @@ -97,7 +97,7 @@ def run(self): ########## dependencies ########## install_requires = [ - 'bokeh >=2.3.0dev11', + 'bokeh >=2.3.0dev12', 'param >=1.10.0', 'pyviz_comms >=0.7.4', 'markdown',