Failed compilation of Bokeh surface3d example

Hi to all.

I test the 3d example of Bokeh surface3d demo.
I just copy and paste the code from website to Spyder IDE.
When running the source code i unfortunately get compilation errors, see below.

How to fix the code in order to keep it running?

My setup is Win10, Python 3.11, Spyder 5.3.2. and node.js 19.7.0.
Additionally i installed vis-graph3d by “npm install vis-graph3d”, maybe v6.0.2.
I’m in Python but not in JS.

Thank you.
Andreas

import numpy as np

from bokeh.core.properties import Instance, String
from bokeh.io import show
from bokeh.models import ColumnDataSource, LayoutDOM
from bokeh.util.compiler import TypeScript

TS_CODE = """
// This custom model wraps one part of the third-party vis.js library:
//
//     http://visjs.org/index.html
//
// Making it easy to hook up python data analytics tools (NumPy, SciPy,
// Pandas, etc.) to web presentations using the Bokeh server.

import {LayoutDOM, LayoutDOMView} from "models/layouts/layout_dom"
import {ColumnDataSource} from "models/sources/column_data_source"
import {LayoutItem} from "core/layout"
import * as p from "core/properties"

declare namespace vis {
  class Graph3d {
    constructor(el: HTMLElement, data: object, OPTIONS: object)
    setData(data: vis.DataSet): void
  }

  class DataSet {
    add(data: unknown): void
  }
}

// This defines some default options for the Graph3d feature of vis.js
// See: http://visjs.org/graph3d_examples.html for more details.
const OPTIONS = {
  width: '600px',
  height: '600px',
  style: 'surface',
  showPerspective: true,
  showGrid: true,
  keepAspectRatio: true,
  verticalRatio: 1.0,
  legendLabel: 'stuff',
  cameraPosition: {
    horizontal: -0.35,
    vertical: 0.22,
    distance: 1.8,
  },
}
// To create custom model extensions that will render on to the HTML canvas
// or into the DOM, we must create a View subclass for the model.
//
// In this case we will subclass from the existing BokehJS ``LayoutDOMView``
export class Surface3dView extends LayoutDOMView {
  model: Surface3d

  private _graph: vis.Graph3d

  initialize(): void {
    super.initialize()

    const url = "https://cdnjs.cloudflare.com/ajax/libs/vis/4.16.1/vis.min.js"
    const script = document.createElement("script")
    script.onload = () => this._init()
    script.async = false
    script.src = url
    document.head.appendChild(script)
  }

  private _init(): void {
    // Create a new Graph3s using the vis.js API. This assumes the vis.js has
    // already been loaded (e.g. in a custom app template). In the future Bokeh
    // models will be able to specify and load external scripts automatically.
    //
    // BokehJS Views create <div> elements by default, accessible as this.el.
    // Many Bokeh views ignore this default <div>, and instead do things like
    // draw to the HTML canvas. In this case though, we use the <div> to attach
    // a Graph3d to the DOM.
    this._graph = new vis.Graph3d(this.el, this.get_data(), OPTIONS)

    // Set a listener so that when the Bokeh data source has a change
    // event, we can process the new data
    this.connect(this.model.data_source.change, () => {
      this._graph.setData(this.get_data())
    })
  }

  // This is the callback executed when the Bokeh data has an change. Its basic
  // function is to adapt the Bokeh data source to the vis.js DataSet format.
  get_data(): vis.DataSet {
    const data = new vis.DataSet()
    const source = this.model.data_source
    for (let i = 0; i < source.get_length()!; i++) {
      data.add({
        x: source.data[this.model.x][i],
        y: source.data[this.model.y][i],
        z: source.data[this.model.z][i],
      })
    }
    return data
  }

  get child_models(): LayoutDOM[] {
    return []
  }

  _update_layout(): void {
    this.layout = new LayoutItem()
    this.layout.set_sizing(this.box_sizing())
  }
}

// We must also create a corresponding JavaScript BokehJS model subclass to
// correspond to the python Bokeh model subclass. In this case, since we want
// an element that can position itself in the DOM according to a Bokeh layout,
// we subclass from ``LayoutDOM``
export namespace Surface3d {
  export type Attrs = p.AttrsOf<Props>

  export type Props = LayoutDOM.Props & {
    x: p.Property<string>
    y: p.Property<string>
    z: p.Property<string>
    data_source: p.Property<ColumnDataSource>
  }
}

export interface Surface3d extends Surface3d.Attrs {}

export class Surface3d extends LayoutDOM {
  properties: Surface3d.Props
  __view_type__: Surface3dView

  constructor(attrs?: Partial<Surface3d.Attrs>) {
    super(attrs)
  }

  // The ``__name__`` class attribute should generally match exactly the name
  // of the corresponding Python class. Note that if using TypeScript, this
  // will be automatically filled in during compilation, so except in some
  // special cases, this shouldn't be generally included manually, to avoid
  // typos, which would prohibit serialization/deserialization of this model.
  static __name__ = "Surface3d"

  static {
    // This is usually boilerplate. In some cases there may not be a view.
    this.prototype.default_view = Surface3dView

    // The @define block adds corresponding "properties" to the JS model. These
    // should basically line up 1-1 with the Python model class. Most property
    // types have counterparts, e.g. ``bokeh.core.properties.String`` will be
    // ``String`` in the JS implementatin. Where the JS type system is not yet
    // as rich, you can use ``p.Any`` as a "wildcard" property type.
    this.define<Surface3d.Props>(({String, Ref}) => ({
      x:            [ String ],
      y:            [ String ],
      z:            [ String ],
      data_source:  [ Ref(ColumnDataSource) ],
    }))
  }
}
"""

# This custom extension model will have a DOM view that should layout-able in
# Bokeh layouts, so use ``LayoutDOM`` as the base class. If you wanted to create
# a custom tool, you could inherit from ``Tool``, or from ``Glyph`` if you
# wanted to create a custom glyph, etc.
class Surface3d(LayoutDOM):

    # The special class attribute ``__implementation__`` should contain a string
    # of JavaScript code that implements the browser side of the extension model.
    __implementation__ = TypeScript(TS_CODE)

    # Below are all the "properties" for this model. Bokeh properties are
    # class attributes that define the fields (and their types) that can be
    # communicated automatically between Python and the browser. Properties
    # also support type validation. More information about properties in
    # can be found here:
    #
    #    https://docs.bokeh.org/en/latest/docs/reference/core/properties.html#bokeh-core-properties

    # This is a Bokeh ColumnDataSource that can be updated in the Bokeh
    # server by Python code
    data_source = Instance(ColumnDataSource)

    # The vis.js library that we are wrapping expects data for x, y, and z.
    # The data will actually be stored in the ColumnDataSource, but these
    # properties let us specify the *name* of the column that should be
    # used for each field.
    x = String()

    y = String()

    z = String()


x = np.arange(0, 300, 10)
y = np.arange(0, 300, 10)
xx, yy = np.meshgrid(x, y)
xx = xx.ravel()
yy = yy.ravel()
value = np.sin(xx / 50) * np.cos(yy / 50) * 50 + 50

source = ColumnDataSource(data=dict(x=xx, y=yy, z=value))

surface = Surface3d(x="x", y="y", z="z", data_source=source, width=600, height=600)

show(surface)

Here is the output of Spyder when running the source code:

runfile('C:/MyPythonDir/MyScript/bokeh-3dexample.py', wdir='C:/MyPythonDir/MyScript')
Compilation failed:

bokeh-3dexample.py:Surface3d.ts:11:9 - error TS2305: Module '"core/layout"' has no exported member 'LayoutItem'.

11 import {LayoutItem} from "core/layout"
           ~~~~~~~~~~
bokeh-3dexample.py:Surface3d.ts:101:5 - error TS2532: Object is possibly 'undefined'.

101     this.layout.set_sizing(this.box_sizing())
        ~~~~~~~~~~~
bokeh-3dexample.py:Surface3d.ts:101:28 - error TS2345: Argument of type 'DOMBoxSizing' is not assignable to parameter of type 'Partial<BoxSizing>'.
  Types of property 'width_policy' are incompatible.
    Type '"auto" | SizingPolicy' is not assignable to type 'SizingPolicy | undefined'.
      Type '"auto"' is not assignable to type 'SizingPolicy | undefined'.

101     this.layout.set_sizing(this.box_sizing())
                               ~~~~~~~~~~~~~~~~~
An exception has occurred, use %tb to see the full traceback.

Traceback (most recent call last):

  File "c:\users\MyUserDir\appdata\local\programs\python\python38\lib\site-packages\bokeh\util\compiler.py", line 314, in bundle_models
    _bundle_cache[key] = bundle = _bundle_models(custom_models)

  File "c:\users\MyUserDir\appdata\local\programs\python\python38\lib\site-packages\bokeh\util\compiler.py", line 520, in _bundle_models
    custom_impls = _compile_models(custom_models)

  File "c:\users\MyUserDir\appdata\local\programs\python\python38\lib\site-packages\bokeh\util\compiler.py", line 500, in _compile_models
    raise CompilationError(compiled.error)

CompilationError: 
bokeh-3dexample.py:Surface3d.ts:11:9 - error TS2305: Module '"core/layout"' has no exported member 'LayoutItem'.

11 import {LayoutItem} from "core/layout"
           ~~~~~~~~~~
bokeh-3dexample.py:Surface3d.ts:101:5 - error TS2532: Object is possibly 'undefined'.

101     this.layout.set_sizing(this.box_sizing())
        ~~~~~~~~~~~
bokeh-3dexample.py:Surface3d.ts:101:28 - error TS2345: Argument of type 'DOMBoxSizing' is not assignable to parameter of type 'Partial<BoxSizing>'.
  Types of property 'width_policy' are incompatible.
    Type '"auto" | SizingPolicy' is not assignable to type 'SizingPolicy | undefined'.
      Type '"auto"' is not assignable to type 'SizingPolicy | undefined'.

101     this.layout.set_sizing(this.box_sizing())
                               ~~~~~~~~~~~~~~~~~


During handling of the above exception, another exception occurred:

SystemExit: 1

This link is to old documentation despite latest in the URL, which resolves to bokeh 2.4:

(see the version in the dropdown at the top of the page).

This is the corresponding link to bokeh 3.1 documentation:

@Bryan, this seems like a bug in the docs. The former link should give 404.

No version of Bokeh was specified, so I assume 3.x.

Hi thank you for help.
My Bokeh is 3.1.
The second link runs well.

Best regards,
Andreas

The issue is that “latest” is no longer a symlink that gets pointed to a fresh x.y.z docs subdirectory, it’s just an S3 prefix that we continually dump new stuff into. The structure of the docs is generally fairly consistent, so that it’s not much of an issue at most only a few old stray paths remain. But the recent docs re-org left many orphaned paths from old docs versions. I would support a once-off manual full-deletion and re-upload of latest to start. I am less sure about the risk/reward of automating delete actions on our S3 buckets.

Well, actually all the autoload script filenames are uuid-tagged, so it does end up over-accumulating quite alot over time regardless. I will make an issue. I have gone ahead and performed a manual intervention for now. (Original bad URL 404s with a force-reload)

Edit: closing the loop: Prune latest docs properly · Issue #12954 · bokeh/bokeh · GitHub

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.