Update an image

I want to update an image using a slider in this page I can update 3d figure but i cannot update imageusing souce data using this line

plot.image(image='z', source=source_2, x=0, y=0, dw=max(xx), dh=max(yy), palette="Spectral11", level="image")

I have got error in js console

Uncaught (in promise) TypeError: n is not iterable
    a https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:174
    _set_data https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:467
    set_data https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:352
    set_data https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:348
    lazy_initialize https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:348
    c https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:278
    build_views https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:278
    build_renderer_views https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:519
    lazy_initialize https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:519
    c https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:278
    build_views https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:278
    build_child_views https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:496
    lazy_initialize https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:496
    c https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:278
    build_view https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:278
    f https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:584
    add_document_standalone https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:584
    w https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:163
    embed_items https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:163
    safely https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:595

My code is here

I have read this post but I cannot apply answer without this error

I’d like to look at this but ~200 lines of code in the middle of ~900 lines of code is just way more than I have bandwidth for. If you can pare things down to a complete Minimal Reproducible Example (guessing ~10s of lines of code) then I can look more closely. Otherwise all I can suggest is that setting the env var BOKEH_MINIFIED=no might provide a better JS “stacktrace”.

minimal example I hope so
the django page

code is

def image_var_slider(request: HttpRequest) -> HttpResponse:
    nu = 2
    b_ok, val = ts_crs.get_arg_post(request, ['nu'])
    if b_ok:
        nu = float(val[0])
    xc, yc  = 150, 150
    x = np.arange(0, 2 * xc, 2) 
    y = np.arange(0, 2 * yc, 2)
    x2d, y2d = np.meshgrid(x, y)
    z = 32+31*np.sin(2 * np.pi * nu/1000 * ((x2d - xc) ** 2+(y2d - yc) ** 2) ** (0.5))
    return JsonResponse(dict(img=z.tolist(),x2d=x2d.tolist(),y2d=y2d.tolist()))

def image_var(request: HttpRequest):
    nu = 2 
    xc, yc  = 150, 150
    x = np.arange(0, 2 * xc, 2) 
    y = np.arange(0, 2 * yc, 2)
    x2d, y2d = np.meshgrid(x, y)
    z = 32+31*np.sin(2 * np.pi * nu/1000 * ((x2d - xc) ** 2+(y2d - yc) ** 2) ** (0.5))
    plot = figure(width=600, height=600,name="Mes_donnees")

    nu_slider = Slider(start=0., end=100, value=nu, step=1, title=r"nu")
    source_2 = ColumnDataSource(data=dict(x2d=x2d, y2d=y2d, z=z))
    callback = CustomJS(args=dict(source2=source_2, freq=nu_slider),
                        code=CODE_TOKEN + """
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "/index/image_var_change", true);
        xhr.setRequestHeader('mode', 'same-origin');
        var dataForm = new FormData();
        dataForm.append('csrfmiddlewaretoken', csrfToken);
        dataForm.append('nu', freq.value);
        xhr.responseType = 'json';
        xhr.onload = function() {    
            reponse =  xhr.response
            source2.data.z = reponse['img'];
            source2.data.x2d = reponse['x2d'];
            source2.data.y2d = reponse['y2d'];
    nu_slider.js_on_change('value', callback)

    plot.image(image='z', source=source_2, x=0, y=0, dw=max(x), dh=max(y), palette="Spectral11", level="image")
    #plot.image(image=[z], x=0, y=0, dw=max(x), dh=max(y), palette="Spectral11", level="image")
    layout = column(nu_slider,plot)
    script1, div1  = components(layout, "Graphique")
    return render(request,'image_var.html',{'script1':script1, 'div':div1})

@LaurentBerger A minimal reproducer is something I can copy and paste into a new file, and immediately run without changes. The above is missing imports, only defines functions, and seems to assume django. I need something I can run, myself, in order to investigate.

I made some progress.
I have got a minimal example without django. It works

import numpy as np

from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource, Slider, Toolbar, Legend, LegendItem, Div
from bokeh.document import Document
from bokeh.embed import server_document
from bokeh.layouts import column, row
from bokeh.embed import file_html, components
from bokeh.models import CustomJS, RangeSlider, ImageURL
from bokeh.models import BoxSelectTool, LassoSelectTool, BoxZoomTool
from bokeh.models import Ascii, LayoutDOM
from bokeh.core.properties import Any, Dict, Instance, String

nu = 2 
xc, yc  = 150, 150
x = np.arange(0, 2 * xc, 100) 
y = np.arange(0, 2 * yc, 100)
x2d, y2d = np.meshgrid(x, y)
z = 32+31*np.sin(2 * np.pi * nu/1000 * ((x2d - xc) ** 2+(y2d - yc) ** 2) ** (0.5))
source_2 = ColumnDataSource(data=dict( x2d=[x2d],y2d=[y2d],z=[z]))

plot = figure(tooltips=[("x", "$x"), ("y", "$y"), ("value", "@z")])
plot.x_range.range_padding = plot.y_range.range_padding = 0

# must give a vector of image data for image parameter
plot.image(image='z',source=source_2, x=0, y=0, dw=max(x), dh=max(y), palette="Spectral11", level="image")

nu_slider = Slider(start=0., end=100, value=nu, step=1, title=r"nu")
callback = CustomJS(args=dict(source=source_2), code="""
    const data = source.data;
    const nu = cb_obj.value
    const x2d = data['x2d']
    const y2d = data['y2d']
    const z = data['z']
    for (let i = 0; i < z[0].length; i++) {
        z[0][i] = Math.sin(6.28*nu/1000*(x2d[0][i]+y2d[0][i]))

layout = column(nu_slider,plot)

plot.grid.grid_line_width = 0.5


Now I try with django prevous problem is solved. but I have got a new error in javascript console
Uncaught DOMException: Index or size is negative or greater than the allowed amount bokeh-2.4.2.min.js:467 in firefox and in edge error message is

       Uncaught DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The source width is 0.
    at p._set_image_data_from_buffer (https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:467:2268)
    at p._set_data (https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:467:1195)
    at p.set_data (https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:352:4213)
    at x.set_data (https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:348:3369)
    at x.update_data (https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:348:3214)
    at x.t (https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:348:1840)
    at x.s (https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:207:468)
    at r.emit (https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:180:651)
    at r.emit (https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:180:736)
    at XMLHttpRequest.xhr.onload (eval at get func (https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js:424:252), <anonymous>:37:28)

I read this post I don’t understand I didn’t change x or y scale in my image

I made a basic example of this a long time ago → Dynamically updating multiple 2D numpy arrays in Image Glyph

It’s CustomJS based but maybe it’ll help.

Thanks but I tried to apply patch
here for source
here for image
here for json
here for js call back
but still same error

You seem to be expecting a literal 2D array. JS does not have those. On the JS side, image arrays are flattened (1D) arrays.

I check array sizes and use good name for variable and it works! thanks

1 Like