0

The problem: I am not able to apply a filter function to columndatasource, and even after applying it's giving my entire full array. My lack of familiarity with JS is making things worse.

So I've been trying to reproduce the results from here:

https://discourse.bokeh.org/t/possible-to-use-customjs-callback-from-a-button-to-animate-a-slider/3985

But using my own data source.

Here is the code for JS Callback:

# Create slider callback
SliderCallback = CustomJS(args = dict(sliceCDS=sliceCDS, fullCDS=fullCDS, indexCDS=indexCDS), code = """
    const new_value = cb_obj.value;

    // Take the 'Slice' column from the full data
    const slice_col = fullCDS.data['Slice'];

    // Select only the values equal to the new slice number
    const mask = slice_col.map((item) => item==new_value);

    sliceCDS.data['x'] = fullCDS.data['x'].filter(item => mask);
    sliceCDS.data['y'] = fullCDS.data['y'].filter(item => mask);
    sliceCDS.data['label'] = fullCDS.data['label'].filter(item => mask);

    //console.log('Here is the data');
    console.log(sliceCDS.data['x']);
    console.log(sliceCDS.data['y']);
    console.log(sliceCDS.data['label']);


    // Update the sliceCDS
    sliceCDS.change.emit();
    """)

# Set up slider
slider = bokeh.models.Slider(title="Slice view number: ",start=0, end=49,value=0,step=1)
slider.js_on_change('value', SliderCallback)

Here is sliceCDS(Input to JS callback):

{'x': 0   -0.001215
0    0.001454
0   -0.000191
0   -0.000377
0   -0.000008
       ...   
0    0.001993
0    0.002045
0    0.002220
0   -0.003160
0   -0.000088
Name: x, Length: 1797, dtype: float64, 'y': 0    0.000745
0    0.000171
0   -0.000004
0    0.000268
0    0.000535
       ...   
0   -0.000417
0    0.002719
0   -0.000269
0    0.000766
0    0.000250
Name: y, Length: 1797, dtype: float64, 'label': 0    0
0    0
0    0
0    0
0    0
    ..
0    9
0    9
0    9
0    9
0    9
Name: label, Length: 1797, dtype: int64, 'Slice': 0    0
0    0
0    0
0    0
0    0
    ..
0    0
0    0
0    0
0    0
0    0
Name: Slice, Length: 1797, dtype: int64}

Here is fullCDS(Input to JS callback):

{'x': 0     -0.001215
0      0.001454
0     -0.000191
0     -0.000377
0     -0.000008
        ...    
49   -12.208837
49   -11.620906
49   -16.709465
49   -13.481855
49   -12.067336
Name: x, Length: 89850, dtype: float64, 'y': 0      0.000745
0      0.000171
0     -0.000004
0      0.000268
0      0.000535
        ...    
49    28.264780
49    27.768742
49    27.019316
49    27.537040
49    24.889742
Name: y, Length: 89850, dtype: float64, 'label': 0     0
0     0
0     0
0     0
0     0
     ..
49    9
49    9
49    9
49    9
49    9
Name: label, Length: 89850, dtype: int64, 'Slice': 0      0
0      0
0      0
0      0
0      0
      ..
49    49
49    49
49    49
49    49
49    49
Name: Slice, Length: 89850, dtype: int64}

With the above code I am not able to update my sliceCDS. It still contains all 89850 rows, when it should contains only 1797 after applying .filter(). EDIT: on suggestion, I also tried the following in the function:

sliceCDS.data['x'] = fullCDS.data['x'].filter((item,idx) => mask[idx]);

and it gives me following error:

VM499:17 Uncaught TypeError: Cannot read property 'filter' of undefined

and tried with this also:

sliceCDS.data['x'] = fullCDS.data['x'].filter((item,0) => mask[0]);

which gave me this error:

VM505:31 Uncaught SyntaxError: Invalid destructuring assignment target

But if I try the method from the link given above, with names of the columns in my columndatasources as Line1 for x, Line2 for y and Line3 for label:

// Update the data for sliceCDS with a slice of data from fullCDS
    for(i=1; i<3; i++){
        sliceCDS.data['Line' + i.toString()] = fullCDS.data['Line' + i.toString()].filter((item,i) => mask[i]);
    }

The above code works just fine.

But why is the code for case mentioned in the starting not working? I am sure there's something wrong with the way I am using .filter().

raghavsikaria
  • 867
  • 17
  • 30

1 Answers1

1

You have this expression in there.

fullCDS.data['x'].filter(item => mask);

The item => mask always returns the mask, regardless of what item is. In JavaScript, an array is always truth-y, no matter the contents.

The second argument to the filter function is the index of the item. Try using the (item, idx) => mask[idx] lambda instead.

Eugene Pakhomov
  • 9,309
  • 3
  • 27
  • 53
  • Hi @Eugene, thank you for the reply. I realised the MASK part, but how to use the lambda here? For example I tried: `sliceCDS.data['x'] = fullCDS.data['x'].filter((item,0) => mask[0]);` and in the html, console error shows me: VM108:31 Uncaught SyntaxError: Invalid destructuring assignment target – raghavsikaria Apr 03 '20 at 04:02
  • 1
    Do not change what I posted - use `(item, idx) => mask[idx]` _verbatim_. `idx` is a proper variable there, not something you have to substitute yourself. – Eugene Pakhomov Apr 03 '20 at 08:03
  • I did try with that too, posted EDIT in the question. Please check that, did I use it wrong there? It gives me: `VM499:17 Uncaught TypeError: Cannot read property 'filter' of undefined` – raghavsikaria Apr 03 '20 at 08:17
  • You either somehow managed to remove the `x` column from `fullCDS.data` or the error is thrown from some other place. I cannot add anything else without the full code and complete stacktraces from exceptions. – Eugene Pakhomov Apr 03 '20 at 08:23
  • Hi @Eugene, I spent the last few hours beating my head around what you taught me. And I am so glad, it worked just fine. I was missing to comment out some JS code inside the callback function. And since this is going through python I never could realise the bug. Thanks you so much for the help. Also, since your `(item, idx) => mask[idx] verbatim` was the one that helped me, is there any way to highlight it for helping others? ( I am new to this place, so apologies for being naive) – raghavsikaria Apr 03 '20 at 18:40
  • 1
    Glad to hear it all worked out. I don't think the line needs to be highlighted any more - it's already formatted as code in the original answer above. And people that want to use an answer should generally read the comments either way IMO. – Eugene Pakhomov Apr 03 '20 at 18:45