Beispiel #1
0
    def test_js_on_change_executes(self, bokeh_model_page) -> None:
        slider = RangeSlider(start=0,
                             end=10,
                             value=(1, 5),
                             title="bar",
                             css_classes=["foo"],
                             width=300)
        slider.js_on_change('value',
                            CustomJS(code=RECORD("value", "cb_obj.value")))

        page = bokeh_model_page(slider)

        drag_range_slider(page.driver, ".foo", "lower", 150)

        results = page.results
        assert float(results['value'][0]) > 1
        assert float(results['value'][1]) == 5

        drag_range_slider(page.driver, ".foo", "lower", 150)

        results = page.results
        assert float(results['value'][0]) > 1
        assert float(results['value'][1]) > 5

        assert page.has_no_console_errors()
def generate_frame_plot(frame):
    sparse_data = json.loads(frame.frame_data)

    img = np.array(sparse_to_dense(sparse_data))
    source = ColumnDataSource(data={'data': img.flatten()})
    plot = figure(x_range=(0, 256),
                  y_range=(0, 256),
                  width=750,
                  height=750,
                  tools='hover,box_zoom,crosshair,reset,save',
                  tooltips=[("x", "$x"), ("y", "$y"), ("value", "@image")],
                  title="Frame {}".format(frame.id))
    im = plot.image(image=[img], x=0, y=0, dw=256, dh=256, palette="Viridis11")

    range_slider_callback = CustomJS(args=dict(source=source, im=im),
                                     code="""
                var image_source = im.data_source;
                var d = image_source.data['image'][0];
                var f = slider.value


                for (var i = 0; i < d.length; i++) {

                        if( source.data['data'][i] >= f[1]){
                            d[i] = f[1];
                        }else if(source.data['data'][i] <= f[0]){
                            d[i] = f[0];
                        } 
                        else{
                            d[i] = source.data['data'][i];
                        }

                }
                image_source.change.emit();
            """)

    for i, cluster in enumerate(frame.clusters):
        bbox = json.loads(cluster.bbox)
        label = Label(x=bbox[3],
                      y=bbox[2],
                      text=str(i + 1),
                      text_color='red',
                      text_font_size="8pt")
        plot.add_layout(label)
    slider = RangeSlider(start=1,
                         end=np.max(img) + 2,
                         step=1,
                         title="View Window",
                         value=(1, np.max(img)))
    slider.js_on_change('value', range_slider_callback)
    range_slider_callback.args['slider'] = slider
    plot.toolbar.logo = None
    layout = Column(slider, plot)

    return layout
def generate_cluster_plot(cluster):
    data = json.loads(cluster.intensity_image)
    bbox = json.loads(cluster.bbox)
    length = bbox[2] - bbox[0]
    width = bbox[3] - bbox[1]

    img = np.array(data)
    source = ColumnDataSource(data={'data': img.flatten()})

    plot = figure(match_aspect=True,
                  width=350,
                  height=350,
                  tools='hover,box_zoom,crosshair,reset,save',
                  tooltips=[("x", "$x"), ("y", "$y"), ("value", "@image")],
                  title="Cluster View")
    im = plot.image(image=[img],
                    x=0,
                    y=0,
                    dw=width,
                    dh=length,
                    palette="Inferno11")

    range_slider_callback = CustomJS(args=dict(source=source, im=im),
                                     code="""
                var image_source = im.data_source;
                var d = image_source.data['image'][0];
                var f = slider.value


                for (var i = 0; i < d.length; i++) {

                        if( source.data['data'][i] >= f[1]){
                            d[i] = f[1];
                        }else if(source.data['data'][i] <= f[0]){
                            d[i] = f[0];
                        } 
                        else{
                            d[i] = source.data['data'][i];
                        }

                }
                image_source.change.emit();
            """)

    # plot.sizing_mode = "fixed"
    plot.toolbar.logo = None
    slider = RangeSlider(start=1,
                         end=np.max(img) + 2,
                         step=1,
                         title="View Window",
                         value=(1, np.max(img)))
    slider.js_on_change('value', range_slider_callback)
    range_slider_callback.args['slider'] = slider

    return Column(slider, plot)
Beispiel #4
0
def create_slider(plot, startYear, endYear):
    callback = CustomJS(args=dict(plot=plot), code="""
    var a = cb_obj.value;
    plot.x_range.start = a[0];
    plot.x_range.end = a[1];
    """)

    range_slider = RangeSlider(start=startYear, end=endYear,value=(startYear, endYear), step=1, width= 440, title="Year Range")
    range_slider.js_on_change('value', callback)

    layout = column(plot,column(range_slider))
    return layout
    def test_js_on_change_executes(self, bokeh_model_page):
        slider = RangeSlider(start=0, end=10, value=(1, 5), title="bar", css_classes=["foo"], width=300)
        slider.js_on_change('value', CustomJS(code=RECORD("value", "cb_obj.value")))

        page = bokeh_model_page(slider)

        drag_slider(page.driver, ".foo",  "lower", 150)

        results = page.results
        assert float(results['value'][0]) > 1
        assert float(results['value'][1]) == 5

        drag_slider(page.driver, ".foo",  "lower", 150)

        results = page.results
        assert float(results['value'][0]) > 1
        assert float(results['value'][1]) > 5

        assert page.has_no_console_errors()
Beispiel #6
0
var column = source.data['speed'];

// iterate through rows of data source and see if each satisfies some constraint
for (var i = 0; i < column.length; i++){
    if(column[i]>min_speed && column[i]<max_speed){
        indices.push(true);
    } else {
        indices.push(false);
    }
}
console.log("filter completed");
return indices;
''',
                              args={'speed_slider': speed_slider})
speed_slider.js_on_change(
    "value",
    CustomJS(code="source.change.emit();", args=dict(source=source_visible)))

# range slider for time
start = datetime.datetime.fromtimestamp(df.timestamp.min())
end = datetime.datetime.fromtimestamp(df.timestamp.max())
time_slider = DateRangeSlider(title="Промежуток времени",
                              value=(start, end),
                              start=start,
                              end=end,
                              format="%H:%M",
                              step=10 * 60 * 1000)
time_filter = CustomJSFilter(code='''
var min_timestamp = time_slider.value[0]/1000 - 3600
var max_timestamp = time_slider.value[1]/1000 - 3600
console.log(min_timestamp, max_timestamp);
Beispiel #7
0
def compare_multiparameter_landscape_samples(
        Samples: List[List[multiparameter_landscape]],
        indices=None,
        TOOLTIPS=None,
        GroupLabels: List[str] = None,
        colors: List[str] = None):
    """
    Plots the mean landscapes of each collection to a single axes in range index = [ind_min,ind_max]
    together with a boxplot comparing the distribution of the functional values yielded by integrating the landscapes
    over a user specified range


    :param Samples: List
    List of lists of multiparameter_landscape objects so Sample[k][i] contains the
    i^th multiparameter landscape from the k^th Sample Group. All multiparameter
    landscapes are assumed to have the same bounds as Samples[0][0].
    :param indices:
    The range of indices to be plotted
    :param TOOLTIPS:
    A bokeh TOOLTIPS list to control features that can be probed in the plot
    :param GroupLabels:
    A list of the names of the Sample Groups
    :param colors:
    A list of the colors for the Sample Groups
    """

    for k in range(len(Samples)):
        if not (Samples[k][0].bounds.lower_left
                == Samples[0][0].bounds.lower_left
                and Samples[k][0].bounds.upper_right
                == Samples[0][0].bounds.upper_right):
            raise TypeError(
                'Inconsistent bounds for landscapes in Sample List')
        for i in range(len(Samples[k])):
            if not (Samples[k][i].bounds.lower_left
                    == Samples[0][0].bounds.lower_left
                    and Samples[k][i].bounds.upper_right
                    == Samples[0][0].bounds.upper_right):
                raise TypeError(
                    'Inconsistent bounds for landscapes in Sample List')

    for k in range(len(Samples)):
        if not (Samples[k][0].weight == Samples[0][0].weight).all():
            raise TypeError(
                'Inconsistent weights for landscapes in Sample List')
        for i in range(len(Samples[k])):
            if not (Samples[k][i].weight == Samples[k][0].weight).all():
                raise TypeError(
                    'Inconsistent weights for landscapes in Sample List')

    for k in range(len(Samples)):
        if not Samples[k][0].grid_step_size == Samples[0][0].grid_step_size:
            raise TypeError(
                'Inconsistent grid step size for landscapes in Sample List')
        for i in range(len(Samples[k])):
            if not Samples[k][i].grid_step_size == Samples[k][0].grid_step_size:
                raise TypeError(
                    'Inconsistent grid step size for landscapes in Sample List'
                )

    if indices is None:
        indices = [1, Samples[0][0].maximum_landscape_depth]
    elif type(indices[0]) is int and type(indices[1]) is int and \
            (indices[1] <= Samples[0][0].maximum_landscape_depth):
        indices = indices
    else:
        raise TypeError(
            'Index range must provide integer values no bigger that the landscape depth'
        )

    if TOOLTIPS is None:
        TOOLTIPS = [("x", "$x"), ("y", "$y"), ("value", "@image")]

    if GroupLabels is None:
        GroupLabels = ['Group ' + str(s + 1) for s in range(len(Samples))
                       ] * (indices[1] - indices[0] + 1)
    else:
        if not len(GroupLabels) == len(Samples):
            raise TypeError(
                'GroupLabels list is not the same length as the sample list')

    if colors is None:
        colors = [
            'plum', 'powderblue', 'gold', 'greenyellow', 'mediumblue',
            'firebrick'
        ]
    else:
        if not len(colors) == len(Samples):
            raise TypeError(
                'Color list is not the same length as the sample list')

    bounds = Samples[0][0].bounds
    grid_step_size = Samples[0][0].grid_step_size
    weight = Samples[0][0].weight

    ######################

    # Define ColumnDataSources #

    rectangle_source = ColumnDataSource(
        data=dict(x=[(bounds.lower_left[0] + bounds.upper_right[0]) / 2],
                  y=[(bounds.lower_left[1] + bounds.upper_right[1]) / 2],
                  width=[bounds.upper_right[0] - bounds.lower_left[0]],
                  height=[bounds.upper_right[1] - bounds.lower_left[1]]))

    rect = Rect(
        x='x',
        y='y',
        width='width',
        height='height',
        fill_alpha=0.2,
        fill_color='white',
        line_color='white',
    )

    landscape_properties = ColumnDataSource(data=dict(
        bounds=[[bounds.lower_left, bounds.upper_right]],
        x_steps=[
            int(
                round((bounds.upper_right[0] - bounds.lower_left[0]) /
                      grid_step_size * weight[1] + 1))
        ],
        y_steps=[
            int(
                round((bounds.upper_right[1] - bounds.lower_left[1]) /
                      grid_step_size * weight[0] + 1))
        ],
        indices=[indices]))

    boxplot_source = ColumnDataSource(
        data=dict(cats=[
            "Group " + str(s + 1) + ", k=" + str(k + 1)
            for k in range(indices[0] - 1, indices[1])
            for s in range(len(Samples))
        ],
                  colors=[
                      colors[s] for _ in range(indices[0] - 1, indices[1])
                      for s in range(len(Samples))
                  ],
                  q1=[-1] * (len(Samples) * (indices[1] - indices[0] + 1)),
                  q2=[0] * (len(Samples) * (indices[1] - indices[0] + 1)),
                  q3=[1] * (len(Samples) * (indices[1] - indices[0] + 1)),
                  lower=[-2] * (len(Samples) * (indices[1] - indices[0] + 1)),
                  upper=[2] * (len(Samples) * (indices[1] - indices[0] + 1)),
                  labels=GroupLabels))

    ######################

    # Callback Functions #

    rotated_samples = [
        rotate_stack(stack_landscapes(Samples[s])) for s in range(len(Samples))
    ]

    callback_x = CustomJS(args=dict(rectangle_source=rectangle_source,
                                    lp=landscape_properties,
                                    bp=boxplot_source,
                                    samples=rotated_samples),
                          code="""
        
        function Find_Median(list) {
          var Size = list.length;
          list = Array.from(list).sort(function(a, b) {
            return a - b
          });
          console.log('sorted')
          console.log(list)
          var Final_Number = 0;
          var HalfWay = 0;
          if (Size % 2 == 0) {
            HalfWay = Math.round((list.length) / 2)-1;
            console.log('Halfway index')
            console.log(HalfWay)
            var Value1 = list[HalfWay];
            var Value2 = list[HalfWay + 1];
            console.log('Value1')
            console.log(Value1)
            console.log('Value2')
            console.log(Value2)
            var Number = Value1 + Value2;
            Final_Number = Number / 2;
            console.log('Final_Number')
            console.log(Final_Number)
            
          } else {
            HalfWay = Math.round(list.length / 2)-1;
            console.log('Halfway index')
            console.log(HalfWay)
            Final_Number = list[HalfWay];
            console.log('Final_Number')
            console.log(Final_Number)
          }
          console.log('Final_Number')
          console.log(Final_Number)
          return Final_Number;
        
        }
        
        function BiggerElements(val)
       {
         return function(evalue, index, array)
         {
         return (evalue >= val);
         };
       }
       
       function SmallerElements(val)
       {
         return function(evalue, index, array)
         {
         return (evalue <= val);
         };
       }
        
        var data = rectangle_source.data;
        var xrange = cb_obj.value
        data['x'] = [(xrange[0]+xrange[1])/2]
        data['width'] = [(xrange[1]-xrange[0])]
        rectangle_source.change.emit();

        var bpdata = bp.data;

        var ylow = data['y'][0] - data['height'][0]/2;
        var yhigh = data['y'][0] + data['height'][0]/2;
        var a = Math.round(Math.PI)
        
        var bounds = lp.data['bounds'][0];
        var x_steps = lp.data['x_steps'];
        var y_steps = lp.data['y_steps'];
        var indices = lp.data['indices'][0];

        var xmin = Math.round(xrange[0]/ bounds.upper_right[0]* x_steps[0]);
        var xmax = Math.round(xrange[1]/ bounds.upper_right[0]* x_steps[0]);
        var ymin = Math.round(ylow/ bounds.upper_right[1]* y_steps[0]);
        var ymax = Math.round(yhigh/ bounds.upper_right[1]* y_steps[0]);

        var q1 = bpdata['q1']
        var q2 = bpdata['q2']
        var q3 = bpdata['q3']
        var lower = bpdata['lower']
        var upper = bpdata['upper']
        
        var number_of_samples = samples.length
        console.log("number_of_samples")
        console.log(number_of_samples)
        
        console.log(samples[0])
        console.log(samples[0].length)
        
        for (var s = 0; s < number_of_samples; s++ )
        {   
            for (var k = 0; k < indices[1]-indices[0]+1 ; k++ )
            {   
                console.log("Index")
                console.log(k)
                console.log('samples[s].length')
                console.log(samples[s].length)
                var holder = Array.from(Array(samples[s].length), () => 0)
                console.log('holder')
                console.log(holder)
                for (var l = 0; l < samples[s].length; l++ )
                {
                console.log("Sample")
                console.log(l)
                var value = 0
                    for (var i = xmin; i < xmax; i++)
                    {
                        for (var j = ymin; j < ymax ; j++)
                        {   
                            value += samples[s][l][k][j][i]
                        }
                    }
                console.log('value')
                console.log(value)
                holder[l] = value  / (x_steps * y_steps)
                }
                console.log('holder')
                console.log(holder)
                console.log('Median')
                console.log(Find_Median(holder))
                console.log('Median^')
                q2[number_of_samples*k + s] = Find_Median(holder)
                q1[number_of_samples*k + s] = Find_Median(holder.filter(SmallerElements(Find_Median(holder))))
                q3[number_of_samples*k + s] = Find_Median(holder.filter(BiggerElements(Find_Median(holder))))
                lower[number_of_samples*k + s] = Math.min.apply(Math,holder)
                upper[number_of_samples*k + s] = Math.max.apply(Math,holder)
            }

        }
        console.log('q2')
        console.log(q2)
        bp.change.emit()
    """)

    callback_y = CustomJS(args=dict(rectangle_source=rectangle_source,
                                    lp=landscape_properties,
                                    bp=boxplot_source,
                                    samples=rotated_samples),
                          code="""
        function Find_Median(list) {
          var Size = list.length;
          list = Array.from(list).sort(function(a, b) {
            return a - b
          });
          console.log('sorted')
          console.log(list)
          var Final_Number = 0;
          var HalfWay = 0;
          if (Size % 2 == 0) {
            HalfWay = Math.round((list.length) / 2)-1;
            console.log('Halfway index')
            console.log(HalfWay)
            var Value1 = list[HalfWay];
            var Value2 = list[HalfWay + 1];
            console.log('Value1')
            console.log(Value1)
            console.log('Value2')
            console.log(Value2)
            var Number = Value1 + Value2;
            Final_Number = Number / 2;
            console.log('Final_Number')
            console.log(Final_Number)
            
          } else {
            HalfWay = Math.round(list.length / 2)-1;
            console.log('Halfway index')
            console.log(HalfWay)
            Final_Number = list[HalfWay];
            console.log('Final_Number')
            console.log(Final_Number)
          }
          console.log('Final_Number')
          console.log(Final_Number)
          return Final_Number;
        
        }
        
        function BiggerElements(val)
       {
         return function(evalue, index, array)
         {
         return (evalue >= val);
         };
       }
       
       function SmallerElements(val)
       {
         return function(evalue, index, array)
         {
         return (evalue <= val);
         };
       }                            
        
        var data = rectangle_source.data;
        var yrange = cb_obj.value
        data['y'] = [(yrange[0]+yrange[1])/2]
        data['height'] = [(yrange[1]-yrange[0])]
        rectangle_source.change.emit();

        var bpdata = bp.data;
        
        var bounds = lp.data['bounds'][0];
        var x_steps = lp.data['x_steps'];
        var y_steps = lp.data['y_steps'];
        var indices = lp.data['indices'][0];
        
        var xlow = data['x'][0] - data['width'][0]/2;
        var xhigh = data['x'][0] + data['width'][0]/2;
        var x_steps = lp.data['x_steps'];
        var y_steps = lp.data['y_steps'];

        var xmin = Math.round(xlow/ bounds.upper_right[0]* x_steps[0]);
        var xmax = Math.round(xhigh/ bounds.upper_right[0]* x_steps[0]);
        var ymin = Math.round(yrange[0]/ bounds.upper_right[1]* y_steps[0]);
        var ymax = Math.round(yrange[1]/ bounds.upper_right[1]* y_steps[0]);

        var q1 = bpdata['q1']
        var q2 = bpdata['q2']
        var q3 = bpdata['q3']
        var lower = bpdata['lower']
        var upper = bpdata['upper']
        var number_of_samples = samples.length
        console.log("number_of_samples")
        console.log(number_of_samples)
        
        console.log(samples[0])
        console.log(samples[0].length)
        
        for (var s = 0; s < number_of_samples; s++ )
        {   
            for (var k = 0; k < indices[1]-indices[0]+1 ; k++ )
            {   
                console.log("Index")
                console.log(k)
                console.log('samples[s].length')
                console.log(samples[s].length)
                var holder = Array.from(Array(samples[s].length), () => 0)
                console.log('holder')
                console.log(holder)
                for (var l = 0; l < samples[s].length; l++ )
                {
                console.log("Sample")
                console.log(l)
                var value = 0
                    for (var i = xmin; i < xmax; i++)
                    {
                        for (var j = ymin; j < ymax ; j++)
                        {   
                            value += samples[s][l][k][j][i]
                        }
                    }
                console.log('value')
                console.log(value)
                holder[l] = value  / (x_steps * y_steps)
                }
                console.log('holder')
                console.log(holder)
                console.log('Median')
                console.log(Find_Median(holder))
                console.log('Median^')
                q2[number_of_samples*k + s] = Find_Median(holder)
                q1[number_of_samples*k + s] = Find_Median(holder.filter(SmallerElements(Find_Median(holder))))
                q3[number_of_samples*k + s] = Find_Median(holder.filter(BiggerElements(Find_Median(holder))))
                lower[number_of_samples*k + s] = Math.min.apply(Math,holder)
                upper[number_of_samples*k + s] = Math.max.apply(Math,holder)
            }

        }
        console.log('q2')
        console.log(q2)
        bp.change.emit()
    """)

    #########################

    # Widgets and callbacks #

    x_range_slider = RangeSlider(start=bounds.lower_left[0],
                                 end=bounds.upper_right[0],
                                 value=(bounds.lower_left[0],
                                        bounds.upper_right[0]),
                                 step=.1,
                                 title="x_range",
                                 width=400)
    y_range_slider = RangeSlider(start=bounds.lower_left[1],
                                 end=bounds.upper_right[1],
                                 value=(bounds.lower_left[1],
                                        bounds.upper_right[1]),
                                 step=.1,
                                 title="y_range",
                                 width=400)
    x_range_slider.js_on_change('value', callback_x)
    y_range_slider.js_on_change('value', callback_y)

    #########################

    # Make Plots #

    mean_landscape_plots = []

    for s in range(len(Samples)):
        mean_landscape = compute_mean_landscape(Samples[s])
        row_of_plots = plot_multiparameter_landscapes(mean_landscape,
                                                      indices,
                                                      TOOLTIPS=TOOLTIPS)
        row_of_plots.sizing_mode = "scale_both"
        mean_landscape_plots.append(row_of_plots)
        for plot in row_of_plots.children:
            plot.add_glyph(rectangle_source, rect)
            plot.plot_height = 250
            plot.plot_width = 250
            plot.border_fill_color = colors[s]
            plot.min_border = 15

    boxplots = figure(x_range=boxplot_source.data['cats'], height=350)

    # stems
    boxplots.segment(source=boxplot_source,
                     x0='cats',
                     y0='upper',
                     x1='cats',
                     y1='q3',
                     color="black")
    boxplots.segment(source=boxplot_source,
                     x0='cats',
                     y0='lower',
                     x1='cats',
                     y1='q1',
                     color="black")

    # boxes
    boxplots.vbar(source=boxplot_source,
                  x='cats',
                  top='q3',
                  bottom='q2',
                  width=0.5,
                  fill_color='colors',
                  line_color='black',
                  legend_group='labels')
    boxplots.vbar(source=boxplot_source,
                  x='cats',
                  top='q2',
                  bottom='q1',
                  width=0.5,
                  fill_color='colors',
                  line_color='black')

    # whiskers (almost-0 height rects simpler than segments)
    boxplots.rect(source=boxplot_source,
                  x='cats',
                  y='lower',
                  width=0.2,
                  height=0.000001,
                  color='black')
    boxplots.rect(source=boxplot_source,
                  x='cats',
                  y='upper',
                  width=0.2,
                  height=0.000001,
                  color='black')

    boxplots.legend.glyph_width = 100
    boxplots.legend.glyph_height = 40
    boxplots.legend.label_text_font_size = '14pt'

    boxplots.xgrid.grid_line_color = None
    boxplots.sizing_mode = "scale_both"

    #         ##########################
    #         # Layout and Show Plot #

    sliders = column([x_range_slider, y_range_slider])
    DOM = column(column(mean_landscape_plots), sliders, boxplots)

    return DOM
Beispiel #8
0
def show_camera(content,
                geom,
                pad_width,
                pad_height,
                label,
                titles=None,
                showlog=True,
                display_range=None,
                content_lowlim=None,
                content_upplim=None):
    """

    Parameters
    ----------
    content: pixel-wise quantity to be plotted, ndarray with shape (N,
    number_of_pixels) where N is the number of different sets of pixel
    values, for example N different data runs or whatever. The shape can also
    be just (number_of_pixels), in case a single camera display is to be shown

    geom: camera geometry
    pad_width: width in pixels of each of the 3 pads in the plot
    pad_height: height in pixels of each of the 3 pads in the plot
    label: string to label the quantity which is displayed, the same for the N
    sets of pixels inside "content"
    titles: list of N strings, with the title specific to each of the sets
    of pixel values to be displayed: for example, indicating run numbers

    content_lowlim: scalar or ndarray of shape(N, number_of_pixels),
    same as content: lowest value of "content" which is considered healthy,
    below which a message will be written out
    content_upplim: highest value considered healthy, same as above
    display_range: range of "content" to be displayed


    Returns
    -------
    [slider, p1, range_slider, p2, p3]: three bokeh figures, intended for
    showing them on the same row, and two sliders, one for the run numbers (
    or whatever "sets" of data we are displaying) and the other for the
    z-range of the plots.
    p1 is the camera display (with "content" in linear & logarithmic scale)
    p2: content vs. pixel
    p3: histogram of content (with one entry per pixel)

    """

    # patch to reduce gaps between bokeh's cam circular pixels:
    camgeom = copy.deepcopy(geom)

    numsets = 1
    if np.ndim(content) > 1:
        numsets = content.shape[0]
    # numsets is the number of different sets of pixel data to be displayed

    allimages = []
    if np.ndim(content) == 1:
        allimages.append(content)
    else:
        for i in range(1, numsets + 1):
            allimages.append(content[i - 1])

    if titles is None:
        titles = [''] * numsets

    # By default we plot the range which contains 99.8 of all events, so that
    # outliers do not prevent us from seing the bulk of the data:
    display_min = np.nanquantile(allimages, 0.001)
    display_max = np.nanquantile(allimages, 0.999)

    if display_range is not None:
        display_min = display_range[0]
        display_max = display_range[1]

    cam = CameraDisplay(camgeom,
                        display_min,
                        display_max,
                        label,
                        titles[0],
                        use_notebook=False,
                        autoshow=False)
    cam.image = allimages[0]
    cam.figure.title.text = titles[0]

    allimageslog = []
    camlog = None
    source1log = None
    color_mapper_log = None
    titlelog = None

    if showlog:
        for image in allimages:
            logcontent = np.copy(image)
            for i, x in enumerate(logcontent):
                # workaround as long as log z-scale is not implemented in bokeh camera:
                if x <= 0:
                    logcontent[i] = np.nan
                else:
                    logcontent[i] = np.log10(image[i])
            allimageslog.append(logcontent)

        camlog = CameraDisplay(camgeom,
                               np.nanquantile(allimageslog, 0.001),
                               np.nanquantile(allimageslog, 0.999),
                               label,
                               titles[0],
                               use_notebook=False,
                               autoshow=False)
        camlog.image = allimageslog[0]
        camlog.figure.title.text = titles[0]
        source1log = camlog.datasource
        color_mapper_log = camlog._color_mapper
        titlelog = camlog.figure.title

    cluster_i = []
    cluster_j = []
    pix_id_in_cluster = []
    for i in camgeom.pix_id:
        data = get_pixel_location(i)
        cluster_i.append(data[0])
        cluster_j.append(data[1])
        pix_id_in_cluster.append(data[2])

    for c in [cam, camlog]:
        if c is None:
            continue
        c.datasource.add(list(c.geom.pix_id), 'pix_id')
        c.datasource.add(cluster_i, 'cluster_i')
        c.datasource.add(cluster_j, 'cluster_j')
        c.datasource.add(pix_id_in_cluster, 'pix_id_in_cluster')

        # c.add_colorbar()
        c.figure.plot_width = pad_width
        c.figure.plot_height = int(pad_height * 0.85)
        c.figure.grid.visible = False
        c.figure.axis.visible = True
        c.figure.xaxis.axis_label = 'X position (m)'
        c.figure.yaxis.axis_label = 'Y position (m)'
        c.figure.add_tools(
            HoverTool(tooltips=[('pix_id', '@pix_id'), ('value', '@image'),
                                ('cluster (i,j)', '(@cluster_i, @cluster_j)'),
                                ('pix # in cluster', '@pix_id_in_cluster')],
                      mode='mouse',
                      point_policy='snap_to_data'))

    tab1 = Panel(child=cam.figure, title='linear')
    if showlog:
        tab2 = Panel(child=camlog.figure, title='logarithmic')
        p1 = Tabs(tabs=[tab1, tab2])
    else:
        p1 = Tabs(tabs=[tab1])
    p1.margin = (0, 0, 0, 25)

    p2 = figure(background_fill_color='#ffffff',
                y_range=(display_min, display_max),
                x_axis_label='Pixel id',
                y_axis_label=label)
    p2.min_border_top = 60
    p2.min_border_bottom = 70

    source2 = ColumnDataSource(
        data=dict(pix_id=cam.geom.pix_id, value=cam.image))
    pixel_data = p2.circle(x='pix_id', y='value', size=2, source=source2)

    if content_lowlim is None:
        content_lowlim = np.nan * np.ones_like(content)
    if content_upplim is None:
        content_upplim = np.nan * np.ones_like(content)

    if np.isscalar(content_lowlim):
        content_lowlim = content_lowlim * np.ones_like(content)
    source2_lowlim = ColumnDataSource(
        data=dict(pix_id=cam.geom.pix_id, value=content_lowlim[0]))
    p2.line(x='pix_id',
            y='value',
            source=source2_lowlim,
            line_dash='dashed',
            color='orange',
            line_width=2)

    if np.isscalar(content_upplim):
        content_upplim = content_upplim * np.ones_like(content)
    source2_upplim = ColumnDataSource(
        data=dict(pix_id=cam.geom.pix_id, value=content_upplim[0]))
    p2.line(x='pix_id',
            y='value',
            source=source2_upplim,
            line_dash='dashed',
            color='red')

    p2.add_tools(
        HoverTool(tooltips=[('(pix_id, value)', '(@pix_id, @value)')],
                  mode='mouse',
                  point_policy='snap_to_data',
                  renderers=[pixel_data]))

    p2.y_range = Range1d(display_min, display_max)

    allhists = []
    alledges = []

    # We define 100 bins between display_min and display_max
    # Note that values beyond that range won't be histogrammed and hence will
    # not appear on the "p3" figure below.
    nbins = 100
    for image in allimages:
        hist, edges = np.histogram(image[~np.isnan(image)],
                                   bins=nbins,
                                   range=(display_min, display_max))
        allhists.append(hist)
        alledges.append(edges)

    source3 = ColumnDataSource(data=dict(top=allhists[0],
                                         bottom=0.7 *
                                         np.ones_like(allhists[0]),
                                         left=alledges[0][:-1],
                                         right=alledges[0][1:]))

    p3 = figure(background_fill_color='#ffffff',
                y_range=(0.7, np.max(allhists) * 1.1),
                x_range=(display_min, display_max),
                x_axis_label=label,
                y_axis_label='Number of pixels',
                y_axis_type='log')
    p3.quad(top='top',
            bottom='bottom',
            left='left',
            right='right',
            source=source3)

    if titles is None:
        titles = [None] * len(allimages)

    cdsdata = dict(z=allimages, hist=allhists, edges=alledges, titles=titles)
    # BEWARE!! these have to be lists of arrays. Not 2D numpy arrays!!
    cdsdata['lowlim'] = [x for x in content_lowlim]
    cdsdata['upplim'] = [x for x in content_upplim]

    if showlog:
        cdsdata['zlog'] = allimageslog

    cds_allimages = ColumnDataSource(data=cdsdata)
    # One has to add here everything that must change when moving the slider:
    callback = CustomJS(args=dict(source1=cam.datasource,
                                  source1log=source1log,
                                  source2=source2,
                                  source2_lowlim=source2_lowlim,
                                  source2_upplim=source2_upplim,
                                  source3=source3,
                                  zz=cds_allimages,
                                  title=cam.figure.title,
                                  titlelog=titlelog,
                                  showlog=showlog),
                        code="""
        var slider_value = cb_obj.value
        var z = zz.data['z']
        varzlow = zz.data['lowlim']
        varzupp = zz.data['upplim']
        var edges = zz.data['edges']
        var hist = zz.data['hist']
        for (var i = 0; i < source1.data['image'].length; i++) {
             source1.data['image'][i] = z[slider_value-1][i]
             if (showlog) {
                 var zlog = zz.data['zlog']
                 source1log.data['image'][i] = zlog[slider_value-1][i]
             }
             source2.data['value'][i] = source1.data['image'][i]
             source2_lowlim.data['value'][i] = varzlow[slider_value-1][i]
             source2_upplim.data['value'][i] = varzupp[slider_value-1][i]
        }
        for (var j = 0; j < source3.data['top'].length; j++) {
            source3.data['top'][j] = hist[slider_value-1][j]
            source3.data['left'][j] = edges[slider_value-1][j]
            source3.data['right'][j] = edges[slider_value-1][j+1]
        }

        title.text = zz.data['titles'][slider_value-1]
        source1.change.emit()
        if (showlog) {
            titlelog.text = title.text
            source1log.change.emit()
        }
        source2.change.emit()
        source2_lowlim.change.emit()
        source2_upplim.change.emit()
        source3.change.emit()
    """)

    slider = None
    if numsets > 1:
        slider_height = 300
        # WARNING: the html won't look nice for number of sets much larger
        # than 300! But in this way we avoid that the slider skips elements:
        if numsets > 299:
            slider_height = numsets + 1
        slider = Slider(start=1,
                        end=numsets,
                        value=1,
                        step=1,
                        title="run",
                        orientation='vertical',
                        show_value=False,
                        height=slider_height)

        slider.margin = (0, 0, 0, 35)
        slider.js_on_change('value', callback)

    callback2 = CustomJS(args=dict(color_mapper=cam._color_mapper,
                                   color_mapper_log=color_mapper_log,
                                   showlog=showlog),
                         code="""
        var range = cb_obj.value
        color_mapper.low = range[0]
        color_mapper.high = range[1]
        color_mapper.change.emit()
        if (showlog) {
            if (range[0] > 0.)
                color_mapper_log.low = Math.log(range[0])/Math.LN10    
            color_mapper_log.high = Math.log(range[1])/Math.LN10
            color_mapper_log.change.emit()
        }
    """)
    step = (display_max - display_min) / 100.
    range_slider = RangeSlider(start=display_min,
                               end=display_max,
                               value=(display_min, display_max),
                               step=step,
                               title="z_range",
                               orientation='vertical',
                               direction='rtl',
                               height=300,
                               show_value=False)
    range_slider.js_on_change('value', callback2)

    return [slider, p1, range_slider, p2, p3]
Beispiel #9
0
    var avg = arrSum(avgList) / avgList.length
    for (var i = 0; i < alpha.length; i++){
        line_y[i] = avg
    }
    source.change.emit();
    line_source.change.emit();
""")

p.add_tools(bar_hover)
p.add_tools(line_hover)

p.sizing_mode = 'scale_width'
p.background_fill_color = "#fdf6e3"
p.border_fill_color = "#fdf6e3"
p.yaxis[0].formatter = NumeralTickFormatter(format="$0,0")
p.outline_line_color = None
range_slider = RangeSlider(start=0,
                           end=max(id_range),
                           value=(0, max(id_range)),
                           step=1,
                           title="Showing IDs")
range_slider.js_on_change('value', callback)
# range_slider.js_on_change("value", CustomJS(code="""
#     console.log('range_slider: value=' + this.value[0], this.toString())
# """))
range_slider.background = "#fdf6e3"

layout = Column(p, range_slider)
layout.sizing_mode = "scale_width"
# show the results
show(layout)
Beispiel #10
0
def create_bokeh(G, title, fname, extract_size=15, feature_size=10):
    # Add attributes this way
    try:
        max_weight = max(nx.get_edge_attributes(G, 'weight').values())
    except ValueError:
        max_weight = 1.0
    calc_alpha = lambda x: 0.1 + 0.6 * (x / max_weight)
    edge_attrs = {(s,e): calc_alpha(d['weight']) for s,e,d in G.edges(data=True)}

    node_attrs = {
        k: {
            "_size": feature_size if v['_type']=='spin' else extract_size,
            "_num_members": len(eval(v.get('members', '[]')))
        }
        for k,v in G.nodes(data=True) }
    nx.set_edge_attributes(G, edge_attrs, "_alpha")
    nx.set_node_attributes(G, node_attrs)

    # Show with Bokeh
    plot = Plot(plot_width=1100, plot_height=700,
                x_range=Range1d(-1.1, 1.1), y_range=Range1d(-1.1, 1.1))
    plot.title.text = title

    node_hover_tool = HoverTool(tooltips=[("Name", "@index"), ("Members", "@members")])
    plot.add_tools(node_hover_tool, WheelZoomTool(), BoxZoomTool(), ResetTool(), TapTool())

    # Tried this but default layout is just better...
    # def layout(x, **kwargs):
    #     return nx.spring_layout(x, **kwargs, k=1.1/sqrt(x.number_of_nodes()),iterations=10000)
    # graph_renderer = from_networkx(G, layout, scale=1, center=(0, 0))

    graph_renderer = from_networkx(G, nx.spring_layout, scale=1, center=(0, 0))

    graph_renderer.node_renderer.glyph = Circle(size='_size', fill_color="_color")
    graph_renderer.node_renderer.selection_glyph = Circle(size=15, fill_color="orange")#works
    graph_renderer.node_renderer.hover_glyph = Circle(size=15, fill_color="red")#works
    graph_renderer.edge_renderer.glyph = MultiLine(line_alpha="_alpha", line_width=1)
    plot.renderers.append(graph_renderer)

    # Add filter slider
    df = nx.to_pandas_edgelist(G)
    max_members = max(nx.get_node_attributes(G,"_num_members").values())
    backup_node_data = graph_renderer.node_renderer.data_source.data
    backup_edge_data = graph_renderer.edge_renderer.data_source.data
    code = """
        const min_nodes = cb_obj.value[0];
        const max_nodes = cb_obj.value[1];
        var to_keep;

        to_keep = ndata.index.map((v,i) =>{
            if (ndata._type[i] !== "spin"){return i}
            else{if(ndata._num_members[i]<=max_nodes && ndata._num_members[i]>=min_nodes)
            {return i}}
        }).filter(x => Boolean(x) | x === 0);

        let keep_names = ndata.index.filter((_,i)=>to_keep.includes(i))

        let new_nodes = {};
        Object.keys(ndata).forEach(k => {
            new_nodes[k] = ndata[k].filter((_,i)=>to_keep.includes(i));
        })

        let new_edges = {};

        Object.keys(edata).forEach(k => {
            new_edges[k] = edata[k].filter((_,i)=>{
                let end = false;
                let start = false;
                if (keep_names.includes(edata.start[i]))
                    start = true
                if (keep_names.includes(edata.end[i]))
                    end = true
                return end && start;
            });
        });

        // Update graph
        graph_setup.node_renderer.data_source.data = new_nodes;
        graph_setup.edge_renderer.data_source.data = new_edges;
        graph_setup.node_renderer.data_source.change.emit();
        graph_setup.edge_renderer.data_source.change.emit();
    """
    min_cb = CustomJS(args=dict(graph_setup=graph_renderer,
                                start=df['source'].values,
                                end=df['target'].values,
                                ndata=backup_node_data,
                                edata=backup_edge_data,
                                type="min"),
                        code=code)
    min_slider = RangeSlider(title='Filter by Number of Members', start=1, end=max_members, value=(1, max_members))

    min_slider.js_on_change('value', min_cb)
    output_file(fname)
    layout = Column(plot, min_slider)
    save(layout)
Beispiel #11
0
def bokeh_plot_sequence(preds,
                        name=None,
                        n=2,
                        cutoff=.95,
                        cutoff_method='default',
                        width=1000,
                        color_sequence=False,
                        title=''):
    """Plot sequence view of binders """

    from bokeh.plotting import figure
    from bokeh.models import ColumnDataSource, LinearAxis, Grid, Range1d, Text, Rect, CustomJS, Slider, RangeSlider, FactorRange
    from bokeh.layouts import gridplot, column

    colors = []
    seqs = []
    text = []
    alleles = []
    ylabels = []
    pcolors = get_bokeh_colors()

    for P in preds:
        print(P.name)
        df = P.data
        #get sequence from results dataframe
        seq = base.sequence_from_peptides(df)
        l = base.get_length(df)
        b = P.get_binders(name=name,
                          cutoff=cutoff,
                          cutoff_method=cutoff_method)
        pb = P.promiscuous_binders(name=name,
                                   cutoff=cutoff,
                                   n=n,
                                   cutoff_method=cutoff_method)
        b = b[b.pos.isin(pb.pos)]  #only promiscuous

        grps = b.groupby('allele')
        al = list(grps.groups)
        alleles.extend(al)
        ylabels.extend([P.name + ' ' + i for i in al])
        currseq = [seq for i in al]
        seqs.extend(currseq)
        t = [i for s in currseq for i in s]
        text.extend(t)
        print(len(seqs), len(text))
        for a in al:
            pos = []
            f = list(b[b.allele == a].pos)
            for i in f:
                pos.extend(np.arange(i, i + l))
            if color_sequence is True:
                c = plotting.get_sequence_colors(seq)
            else:
                c = ['white' for i in seq]

            for i in pos:
                c[i] = pcolors[P.name]
            colors.extend(c)

    #put into columndatasource for plotting
    N = len(seqs[0])
    S = len(alleles)
    x = np.arange(1, N + 1)
    y = np.arange(0, S, 1)
    xx, yy = np.meshgrid(x, y)
    gx = xx.ravel()
    gy = yy.flatten()
    recty = gy + .5

    source = ColumnDataSource(
        dict(x=gx, y=gy, recty=recty, text=text, colors=colors))
    plot_height = len(seqs) * 15 + 60
    x_range = Range1d(0, N + 1, bounds='auto')
    L = 100
    if len(seq) < 100:
        L = len(seq)
    view_range = (0, L)
    viewlen = view_range[1] - view_range[0]

    fontsize = "8.5pt"
    tools = "xpan, reset, save"
    p = figure(title=title,
               plot_width=width,
               plot_height=plot_height,
               x_range=view_range,
               y_range=ylabels,
               tools=tools,
               min_border=0,
               sizing_mode='stretch_both',
               lod_factor=10,
               lod_threshold=1000)
    seqtext = Text(x="x",
                   y="y",
                   text="text",
                   text_align='center',
                   text_color="black",
                   text_font="monospace",
                   text_font_size=fontsize)
    rects = Rect(x="x",
                 y="recty",
                 width=1,
                 height=1,
                 fill_color="colors",
                 line_color='gray',
                 fill_alpha=0.6)

    p.add_glyph(source, rects)
    p.add_glyph(source, seqtext)
    p.xaxis.major_label_text_font_style = "bold"
    p.grid.visible = False
    p.toolbar.logo = None

    #preview view (no text)
    p1 = figure(title=None,
                plot_width=width,
                plot_height=S * 3 + 5,
                x_range=x_range,
                y_range=(0, S),
                tools=[],
                min_border=0,
                sizing_mode='stretch_width',
                lod_factor=10,
                lod_threshold=10)
    rects = Rect(x="x",
                 y="recty",
                 width=1,
                 height=1,
                 fill_color="colors",
                 line_color=None,
                 fill_alpha=0.6)
    previewrect = Rect(x=viewlen / 2,
                       y=S / 2,
                       width=viewlen,
                       height=S * .99,
                       line_color='darkblue',
                       fill_color=None)
    p1.add_glyph(source, rects)
    p1.add_glyph(source, previewrect)
    p1.yaxis.visible = False
    p1.grid.visible = False
    p1.toolbar_location = None

    #callback for slider move
    jscode = """
        var start = cb_obj.value[0];
        var end = cb_obj.value[1];
        x_range.setv({"start": start, "end": end})
        rect.width = end-start;
        rect.x = start+rect.width/2;
        var fac = rect.width/width;
        console.log(fac);
        if (fac>=.14) { fontsize = 0;}
        else { fontsize = 8.5; }
        text.text_font_size=fontsize+"pt";
    """
    callback = CustomJS(args=dict(x_range=p.x_range,
                                  rect=previewrect,
                                  text=seqtext,
                                  width=p.plot_width),
                        code=jscode)
    slider = RangeSlider(start=0, end=N, value=(0, L),
                         step=10)  #, callback_policy="throttle")
    slider.js_on_change('value_throttled', callback)

    #callback for plot drag
    jscode = """
        start = parseInt(range.start);
        end = parseInt(range.end);
        slider.value[0] = start;
        rect.width = end-start;
        rect.x = start+rect.width/2;
    """
    #p.x_range.callback = CustomJS(args=dict(slider=slider, range=p.x_range, rect=previewrect),
    #                              code=jscode)

    p = gridplot([[p1], [p], [slider]],
                 toolbar_location="below",
                 merge_tools=False)
    return p
Beispiel #12
0
def plot_sequence_alignment(aln,
                            fontsize="8pt",
                            plot_width=800,
                            sizing_mode='stretch_width',
                            palette='tab20',
                            row_height=10,
                            annot=None):
    """Bokeh sequence alignment viewer.

    Args:
        aln: biopython Multiple Sequence Alignment
    """

    seqs = [rec.seq for rec in (aln)]
    ids = [rec.id for rec in aln]
    if len(seqs) <= 1:
        p = plot_empty('needs at least two sequences', plot_width)
        return p
    #ids=range(len(seqs))
    text = [i for s in list(seqs) for i in s]
    colors = utils.get_sequence_colors(seqs, palette=palette)
    cons = utils.get_cons(aln)
    N = len(seqs[0])
    S = len(seqs)
    width = .4

    x = np.arange(1, N + 1)
    y = np.arange(0, S, 1)
    #print (y[:20])
    xx, yy = np.meshgrid(x, y)
    gx = xx.ravel()
    gy = yy.flatten()
    recty = gy + .5
    h = 1 / S

    #print (text)
    source = ColumnDataSource(
        dict(x=gx, y=gy, recty=recty, text=text, colors=colors))
    plot_height = len(seqs) * row_height + 50
    x_range = Range1d(0, N + 1, bounds='auto')
    L = 100
    if len(seqs[0]) < 100:
        L = len(seqs[0])
    view_range = (0, L)
    viewlen = view_range[1] - view_range[0]
    tools = "xpan, xwheel_zoom, tap, reset, save"

    #box_select = BoxSelectTool(callback=callback_select)

    #preview sequence view (no text)
    p = figure(title=None,
               plot_width=plot_width,
               plot_height=S * 2 + 25,
               x_range=x_range,
               y_range=(0, S),
               tools=tools,
               min_border=0,
               toolbar_location='below',
               sizing_mode='stretch_width')
    rects = Rect(x="x",
                 y="recty",
                 width=1,
                 height=1,
                 fill_color="colors",
                 line_color=None,
                 fill_alpha=0.4)
    p.add_glyph(source, rects)
    previewrect = Rect(x=viewlen / 2,
                       y=S / 2,
                       width=viewlen,
                       height=S * .99,
                       line_color='darkblue',
                       fill_color=None)
    p.add_glyph(source, previewrect)
    p.yaxis.visible = False
    p.grid.visible = False

    #full sequence text view
    p1 = figure(title=None,
                plot_width=plot_width,
                plot_height=plot_height,
                x_range=view_range,
                y_range=ids,
                tools="xpan,reset",
                min_border=0,
                toolbar_location='below')  #, lod_factor=1)
    seqtext = Text(x="x",
                   y="y",
                   text="text",
                   text_align='center',
                   text_color="black",
                   text_font="monospace",
                   text_font_size=fontsize)
    rects = Rect(x="x",
                 y="recty",
                 width=1,
                 height=1,
                 fill_color="colors",
                 line_color=None,
                 fill_alpha=0.5)
    p1.add_glyph(source, rects)
    p1.add_glyph(source, seqtext)

    p1.grid.visible = False
    p1.xaxis.major_label_text_font_style = "bold"
    p1.yaxis.minor_tick_line_width = 0
    p1.yaxis.major_tick_line_width = 0
    p1.toolbar.logo = None

    source2 = ColumnDataSource(dict(x=x, cons=cons))

    p3 = figure(title=None,
                plot_width=plot_width,
                plot_height=50,
                x_range=p1.x_range,
                y_range=(Range1d(min(cons), .5)),
                tools="xpan")
    rects2 = Rect(x="x",
                  y=0,
                  width=1,
                  height="cons",
                  fill_color="gray",
                  line_color=None,
                  fill_alpha=0.7)
    p3.add_glyph(source2, rects2)

    p3.xaxis.visible = False
    p3.yaxis.visible = False
    p3.grid.visible = False
    p3.background_fill_color = "beige"

    if annot != None:
        p4 = figure(plot_width=plot_width,
                    plot_height=35,
                    x_range=p1.x_range,
                    y_range=(0, 1))
        #for a in annot:
        x = [annot[i] for i in annot]
        p4.text(x,
                .5,
                text=[i for i in annot],
                text_baseline="middle",
                text_align="center")
        p4.grid.visible = False
        p4.xaxis.visible = False
        p4.yaxis.visible = False
    else:
        p4 = None
    #callback for click
    jscode = """
        row =  parseInt(cb_obj.y);
        console.log(row);
    """
    clicked = CustomJS(args=dict(source=source), code=jscode)
    p1.js_on_event(Tap, clicked)

    #callback for slider move
    jscode = """
        var start = cb_obj.value[0];
        var end = cb_obj.value[1];
        x_range.setv({"start": start, "end": end})
        rect.width = end-start;
        rect.x = start+rect.width/2;
        var fac = rect.width/width;
        if (fac>=.22) { fontsize = 0;}
        else { fontsize = 8.5; }
        text.text_font_size=fontsize+"pt";
    """
    callback = CustomJS(args=dict(x_range=p1.x_range,
                                  rect=previewrect,
                                  text=seqtext,
                                  width=p1.plot_width),
                        code=jscode)
    slider = RangeSlider(start=0,
                         end=N,
                         value=(0, L),
                         step=10,
                         callback_policy="throttle")
    slider.js_on_change('value_throttled', callback)

    #callback for plot drag
    jscode = """
        start = parseInt(range.start);
        end = parseInt(range.end);
        slider.value[0] = start;
        rect.width = end-start;
        rect.x = start+rect.width/2;
    """
    p1.x_range.callback = CustomJS(args=dict(slider=slider,
                                             range=p1.x_range,
                                             rect=previewrect),
                                   code=jscode)
    p = gridplot([[p], [slider], [p3], [p1], [p4]],
                 toolbar_location='below',
                 sizing_mode=sizing_mode)
    return p
Beispiel #13
0
class RangeAnalyserGui:
    move_spans = \
        """
        start_span.location = cb_obj.value[0];
        start_span.change.emit();
        end_span.location = cb_obj.value[1];        
        end_span.change.emit();
        """

    update_range_slide = \
        """
        range_slide.start = cb_obj.start;
        range_slide.end = cb_obj.end;
        range_slide.change.emit();
        """

    def __init__(self, analyser):
        """
        Creates and manages the Gui for RangeAnalysis
        """
        self.analyser = analyser

        self.fig = self.make_fig()

        init_start = self.analyser.x.min() * 1.1
        init_end = self.analyser.x.max() * 0.9

        span_kwargs = dict(dimension='height', line_dash='dashed', line_width=3)
        self.start_span = Span(location=init_start, line_color='green', **span_kwargs)
        self.end_span = Span(location=init_end, line_color='red', **span_kwargs)

        self.range_slide = RangeSlider(start=self.analyser.x.min(), end=self.analyser.x.max(), step=self.analyser.dx,
                                       value=(init_start, init_end),
                                       width=self.fig.plot_width)

        self.start_connected = widgets.Button(label="start", button_type='success')
        self.end_connected = widgets.Button(label="end", button_type='success')

        self.setup_callbacks()

        self.app = self.make_app()
        self.doc = None

    @property
    def start(self):
        """
        current start value of slider
        """
        return self.range_slide.value[0]

    @start.setter
    def start(self, val):
        old = self.range_slide.value
        new = (val, old[1])
        self.range_slide.value = new
        #self.range_slide.trigger('value', old, new)
        old_loc = self.start_span.location
        self.start_span.location= val
        # self.start_span.trigger('location', old_loc, val)

    @property
    def end(self):
        """
        current end value of slider
        """
        return self.range_slide.value[1]

    @end.setter
    def end(self, val):
        old = self.range_slide.value
        new = (old[0], val)
        self.range_slide.value = new
        #self.range_slide.trigger('value', old, new)
        old_loc = self.end_span.location

        self.end_span.location = val
        # self.end_span.trigger('location', old_loc, val)

    def make_fig(self):
        fig = bok.figure()

        fig.tools.append(HoverTool(
            tooltips=[(f"{self.analyser.xlabel if self.analyser.xlabel else 'x'}, {self.analyser.ylabel}",
                       "$x, $y")]))
        fig.line(self.analyser.x, self.analyser.y, legend=self.analyser.ylabel)

        return fig

    def setup_callbacks(self):
        self.range_slide.js_on_change('value', CustomJS(code=self.move_spans,
                                                        args={'start_span': self.start_span,
                                                              'end_span': self.end_span}))
        self.fig.x_range.callback = CustomJS(code=self.update_range_slide,
                                        args={'range_slide': self.range_slide})
        self.start_connected.on_click(self.toggle_start_connected)
        self.end_connected.on_click(self.toggle_end_connected)

    def make_app(self):
        self.fig.add_layout(self.start_span)
        self.fig.add_layout(self.end_span)

        analysis_guis = []

        for Analysis in self.analyser.analysis_types:
            analysis = Analysis(self.analyser)
            self.analyser.analyses[analysis.name] = analysis
            analysis_guis.append(analysis.gui.as_row())

        layout = bklayouts.layout(
            [self.fig, bklayouts.column(*analysis_guis, bklayouts.row(self.start_connected,
                                                                      self.end_connected, width=300))],
                                   self.range_slide)

        def modify_doc(doc):
            self.doc = doc
            doc.add_root(layout)
            doc.add_periodic_callback(self.update_connected, 100)

        handler = FunctionHandler(modify_doc)
        app = Application(handler)
        return app

    def update_connected(self):
        old_start, old_end = self.start_connected.button_type, self.end_connected.button_type
        self.start_connected.button_type = "success" if self.analyser.start_connected else "danger"
        self.end_connected.button_type = "success" if self.analyser.end_connected else "danger"
    
    def toggle_start_connected(self):
        if self.analyser.start_connected:
            self.analyser.start = self.start
        else:
            self.analyser.start = None
        self.update_connected()
        
    def toggle_end_connected(self):
        if self.analyser.end_connected:
            self.analyser.end = self.end
        else:
            self.analyser.end = None
        self.update_connected()
Beispiel #14
0
from bokeh.io import show
from bokeh.models import CustomJS, RangeSlider

range_slider = RangeSlider(start=0,
                           end=10,
                           value=(1, 9),
                           step=.1,
                           title="Stuff")
range_slider.js_on_change(
    "value",
    CustomJS(code="""
    console.log('range_slider: value=' + this.value, this.toString())
"""))

show(range_slider)
Beispiel #15
0
def get_dashboard(local_data=False):
    """
    Assemble the dashboard. Define the layout, controls and 
    its callbacks, as well as data sources.
    """
    # Load data
    video_data = {}
    if local_data:
        data = pd.json_normalize(
            pd.read_json('data/channel/processed_data.json')['items'])
        with open('data/channel/processed_data.json', 'r') as f:
            data = json.load(f)
            video_data = data['items']
    else:
        video_data = handle_channel_data.get_data_firebase()['items']

    # X axis categories
    x_axis_map = {
        "Climber": "climber",
        "Zone": "zone",
        "Grade": "grade",
    }
    # Y axis categories
    y_axis_map = {
        "Count": "count",
        "Views": "viewCount",
        # "Favourites": "favoriteCount",
        "Likes": "likeCount",
        "Dislikes": "dislikeCount",
        "Comments": "commentCount"
    }

    # get ready to plot data
    barchart_data = prepare_barchart_data(video_data, x_axis_map)

    # html template to place the plots
    desc = Div(text=open(join(dirname(__file__),
                              "templates/stats.html")).read(),
               sizing_mode="stretch_width")

    # initial data source fill
    data_to_plot = barchart_data['grade']['raw']

    od = collections.OrderedDict(
        sorted(data_to_plot.items(), key=lambda x: x[0]))

    x_to_plot = np.array([key for key, _ in od.items()])
    y_to_plot = np.array([val['count'] for _, val in od.items()])
    source = ColumnDataSource(data=dict(x=x_to_plot, y=y_to_plot))
    # initial data
    x_init = x_to_plot[0:NUM_RESULTS]
    y_init = y_to_plot[0:NUM_RESULTS]

    # Create Input controls
    checkbox_limit_results = CheckboxGroup(
        labels=["Show only first 50 results"], active=[0])

    label_slider = Slider(start=0,
                          end=90,
                          value=90,
                          step=1,
                          title="Label Angle")

    range_slider = RangeSlider(title="Value Range",
                               start=0,
                               end=max(y_to_plot),
                               value=(0, max(y_to_plot)),
                               step=1)

    min_year = Slider(title="From", start=2015, end=2020, value=2015, step=1)

    max_year = Slider(title="To", start=2015, end=2020, value=2020, step=1)

    sort_order = RadioButtonGroup(
        labels=["Alphabetically", "Decreasing", "Increasing"], active=0)
    x_axis = Select(title="X Axis",
                    options=sorted(x_axis_map.keys()),
                    value="Grade")

    y_axis = Select(title="Y Axis",
                    options=sorted(y_axis_map.keys()),
                    value="Count")

    checkbox = CheckboxGroup(
        labels=["Show ratio with respect to number of videos"], active=[])

    # show number of categories
    x_count_source = ColumnDataSource(
        data=dict(x_count=[len(x_init)], category=[x_axis.value]))

    columns = [
        TableColumn(field="category", title="Category"),
        TableColumn(field="x_count", title="Count"),
    ]

    x_count_data_table = DataTable(source=x_count_source,
                                   columns=columns,
                                   width=320,
                                   height=280)

    # Generate the actual plot
    # p = figure(x_range=x_to_plot, y_range=(0, max(y_to_plot)), plot_height=250, title="{} {}".format(x_axis.value, y_axis.value),
    #            toolbar_location="above")
    p = figure(x_range=x_init,
               y_range=(0, max(y_init)),
               plot_height=250,
               title="{} {}".format(x_axis.value, y_axis.value),
               toolbar_location="above")

    # Fill it with data and format it
    p.vbar(x='x', top='y', width=0.9, source=source)
    p.xaxis.major_label_orientation = math.pi / 2
    p.add_tools(HoverTool(tooltips=[("name", "@x"), ("count", "@y")]))

    # Controls
    controls = [
        checkbox_limit_results, range_slider, min_year, max_year, sort_order,
        x_axis, y_axis, checkbox, label_slider, x_count_data_table
    ]

    # Callbacks for controls
    label_callback = CustomJS(args=dict(axis=p.xaxis[0]),
                              code="""
        axis.major_label_orientation = cb_obj.value * Math.PI / 180;
        """)
    label_slider.js_on_change('value', label_callback)

    # limit checkbox
    checkbox_limit_results_callback = CustomJS(
        args=dict(source=source,
                  x_source=x_count_source,
                  o_data=barchart_data,
                  sort_order=sort_order,
                  x_axis_map=x_axis_map,
                  x_axis=x_axis,
                  y_axis_map=y_axis_map,
                  y_axis=y_axis,
                  range_slider=range_slider,
                  checkbox=checkbox,
                  fig=p,
                  title=p.title),
        code=SORT_FUNCTION + JS_NUM_RESULTS + """
            var data = o_data[x_axis_map[x_axis.value]];
            var x = data['x'];
            var y = data['y'];
            var apply_limit = cb_obj.active.length > 0;
            var is_ratio = checkbox.active.length > 0;
            title.text = x_axis.value.concat(" ", y_axis.value);
            // Sort data
            var sorted_data = sortData(data['raw'], sort_order.active, y_axis_map[y_axis.value], is_ratio);
            var new_y = [];
            var new_x = [];
            var final_x = [];
            var final_y = [];
            for (var i = 0; i < x.length; i++) {
                if (apply_limit)
                {
                    if(sorted_data[i][1] >= range_slider.value[0] && sorted_data[i][1] <= range_slider.value[1]) 
                    {
                        new_x.push(sorted_data[i][0]);
                        new_y.push(sorted_data[i][1]);
                    } 
                } else {
                    new_x.push(sorted_data[i][0]);
                    new_y.push(sorted_data[i][1]);                    
                }
            }
            if (apply_limit) { 
                final_x = new_x.slice(0, num_results);
                final_y = new_y.slice(0, num_results);
                window.should_update_range = false;
            } else {
                final_x = new_x;
                final_y = new_y;
                window.should_update_range = true;
            }
            x_source.data['x_count'] = [final_x.length];
            x_source.data['category'] = [x_axis.value];
            x_source.change.emit();
            source.data['x'] = new_x;
            source.data['y'] = new_y;
            source.change.emit();
            fig.x_range.factors = [];
            fig.x_range.factors = final_x;
            if (Array.isArray(new_y) && new_y.length) {
                // range init and end cannot have same value
                var range_end = Math.max.apply(Math, new_y);
                if (range_end == 0 || range_end == -Infinity) {
                    range_end = 1;
                }
                range_slider.value = [0, Math.max.apply(Math, final_y)]; 
                range_slider.end = range_end;
                fig.y_range.end = Math.max.apply(Math, final_y);
                fig.change.emit();
            }        
        """)
    checkbox_limit_results.js_on_change('active',
                                        checkbox_limit_results_callback)

    # ratio checkbox
    checkbox_callback = CustomJS(args=dict(
        source=source,
        x_source=x_count_source,
        o_data=barchart_data,
        sort_order=sort_order,
        x_axis_map=x_axis_map,
        x_axis=x_axis,
        y_axis_map=y_axis_map,
        y_axis=y_axis,
        range_slider=range_slider,
        checkbox_limit_results=checkbox_limit_results,
        fig=p,
        title=p.title),
                                 code=SORT_FUNCTION + JS_NUM_RESULTS + """
            var data = o_data[x_axis_map[x_axis.value]];
            var x = data['x'];
            var y = data['y'];
            var is_ratio = cb_obj.active.length > 0;
            title.text = x_axis.value.concat(" ", y_axis.value);
            if (is_ratio)
            {
                title.text = x_axis.value.concat(" ", y_axis.value, " per video");   
            }
            // Sort data
            var sorted_data = sortData(data['raw'], sort_order.active, y_axis_map[y_axis.value], is_ratio);
            var new_y = [];
            var new_x = [];
            var final_x = [];
            var final_y = [];
            for (var i = 0; i < x.length; i++) {
                if (checkbox_limit_results.active.length <= 0)
                {
                    if(sorted_data[i][1] >= range_slider.value[0] && sorted_data[i][1] <= range_slider.value[1]) 
                    {
                        new_x.push(sorted_data[i][0]);
                        new_y.push(sorted_data[i][1]);
                    } 
                } else {
                    new_x.push(sorted_data[i][0]);
                    new_y.push(sorted_data[i][1]);                    
                }
            }
            if (checkbox_limit_results.active.length > 0) { 
                final_x = new_x.slice(0, num_results);
                final_y = new_y.slice(0, num_results);
                window.should_update_range = false;
            } else {
                final_x = new_x;
                final_y = new_y;
                window.should_update_range = true;
            }
            x_source.data['x_count'] = [final_x.length];
            x_source.data['category'] = [x_axis.value];
            x_source.change.emit();
            source.data['x'] = new_x;
            source.data['y'] = new_y;
            source.change.emit();
            fig.x_range.factors = [];
            fig.x_range.factors = final_x;
            if (Array.isArray(new_y) && new_y.length) {
                // range init and end cannot have same value
                var range_end = Math.max.apply(Math, new_y);
                if (range_end == 0 || range_end == -Infinity) {
                    range_end = 1;
                }
                range_slider.value = [0, Math.max.apply(Math, final_y)]; 
                range_slider.end = range_end;
                fig.y_range.end = Math.max.apply(Math, final_y);
                fig.change.emit();
            }
        """)
    checkbox.js_on_change('active', checkbox_callback)

    # range slider
    range_callback = CustomJS(args=dict(
        source=source,
        x_source=x_count_source,
        o_data=barchart_data,
        sort_order=sort_order,
        x_axis_map=x_axis_map,
        x_axis=x_axis,
        y_axis_map=y_axis_map,
        y_axis=y_axis,
        checkbox=checkbox,
        checkbox_limit_results=checkbox_limit_results,
        fig=p),
                              code=SORT_FUNCTION + """
            if (window.should_update_range == true) {
                var data = o_data[x_axis_map[x_axis.value]];
                var x = data['x'];
                var y = data['y'];
                var is_ratio = checkbox.active.length > 0;
                // Sort data
                var sorted_data = sortData(data['raw'], sort_order.active, y_axis_map[y_axis.value], is_ratio);
                var new_y = [];
                var new_x = [];
                for (var i = 0; i < x.length; i++) {
                    if (checkbox_limit_results.active.length <= 0)
                    {
                        if (sorted_data[i][1] >= cb_obj.value[0] && sorted_data[i][1] <= cb_obj.value[1]) 
                        {
                            new_x.push(sorted_data[i][0]);
                            new_y.push(sorted_data[i][1]);
                        }
                    } else {
                        new_x.push(sorted_data[i][0]);
                        new_y.push(sorted_data[i][1]);                        
                    }
                }
                x_source.data['x_count'] = [new_x.length];
                x_source.data['category'] = [x_axis.value];
                x_source.change.emit();
                source.data['x'] = new_x;
                source.data['y'] = new_y;
                source.change.emit();
                fig.x_range.factors = [];
                fig.x_range.factors = new_x;
                if (Array.isArray(new_y) && new_y.length) {
                    fig.y_range.end = Math.max.apply(Math, new_y);
                }
            } else {
                window.should_update_range = true;
            }
        """)
    range_slider.js_on_change('value', range_callback)

    # variable to group data
    x_axis_callback = CustomJS(args=dict(
        source=source,
        x_source=x_count_source,
        o_data=barchart_data,
        x_axis_map=x_axis_map,
        y_axis_map=y_axis_map,
        y_axis=y_axis,
        range_slider=range_slider,
        sort_order=sort_order,
        checkbox=checkbox,
        checkbox_limit_results=checkbox_limit_results,
        fig=p,
        title=p.title),
                               code=SORT_FUNCTION + JS_NUM_RESULTS + """
            title.text = cb_obj.value.concat(" ", y_axis.value);
            var data = o_data[x_axis_map[cb_obj.value]];
            var x = data['x'];
            var y = data['y'];
            var is_ratio = checkbox.active.length > 0;
            if (is_ratio)
            {
                title.text = title.text.concat(" per video");   
            }
            var sorted_data = sortData(data['raw'], sort_order.active, y_axis_map[y_axis.value], is_ratio);
            var new_y = [];
            var new_x = [];
            var final_x = [];
            var final_y = [];
            for (var i = 0; i < x.length; i++) {
                new_x.push(sorted_data[i][0]);
                new_y.push(sorted_data[i][1]);
            }
            if (checkbox_limit_results.active.length > 0) {
                final_x = new_x.slice(0, num_results);
                final_y = new_y.slice(0, num_results);
                window.should_update_range = false;
            } else {
                final_x = new_x;
                final_y = new_y;
                window.should_update_range = true;
            }
            x_source.data['x_count'] = [final_x.length];
            x_source.data['category'] = [cb_obj.value];
            x_source.change.emit();
            source.data['x'] = new_x;
            source.data['y'] = new_y;
            source.change.emit();
            fig.x_range.factors = [];
            fig.x_range.factors = final_x;
            if (new_y && Array.isArray(new_y) && new_y.length) {
                // range init and end cannot have same value
                var range_end = Math.max.apply(Math, new_y);
                if (range_end == 0 || range_end == -Infinity) {
                    range_end = 1;
                }
                range_slider.value = [0, Math.max.apply(Math, final_y)]; 
                range_slider.end = range_end;
                fig.y_range.end = Math.max.apply(Math, final_y);
                fig.change.emit();
            }
        """)

    x_axis.js_on_change('value', x_axis_callback)

    # variable to group data
    y_axis_callback = CustomJS(args=dict(
        source=source,
        x_source=x_count_source,
        o_data=barchart_data,
        x_axis_map=x_axis_map,
        x_axis=x_axis,
        y_axis_map=y_axis_map,
        range_slider=range_slider,
        sort_order=sort_order,
        checkbox=checkbox,
        checkbox_limit_results=checkbox_limit_results,
        fig=p,
        title=p.title),
                               code=SORT_FUNCTION + JS_NUM_RESULTS + """
            title.text = x_axis.value.concat(" ", cb_obj.value);
            var data = o_data[x_axis_map[x_axis.value]];
            var x = data['x'];
            var y = data['y'];
            var is_ratio = checkbox.active.length > 0;
            if (is_ratio)
            {
                title.text = x_axis.value.concat(" ", cb_obj.value, " per video");   
            }
            var sorted_data = sortData(data['raw'], sort_order.active, y_axis_map[cb_obj.value], is_ratio);
            var new_y = [];
            var new_x = [];
            var final_x = [];
            var final_y = [];
            for (var i = 0; i < x.length; i++) {
                new_x.push(sorted_data[i][0]);
                new_y.push(sorted_data[i][1]);
            }
            if (checkbox_limit_results.active.length > 0) {
                final_x = new_x.slice(0, num_results);
                final_y = new_y.slice(0, num_results);
                window.should_update_range = false;
            } else {
                final_x = new_x;
                final_y = new_y;
                window.should_update_range = true;
            }
            x_source.data['x_count'] = [final_x.length];
            x_source.data['category'] = [x_axis.value];
            x_source.change.emit();
            source.data['x'] = new_x;
            source.data['y'] = new_y;
            source.change.emit();
            fig.x_range.factors = [];
            fig.x_range.factors = final_x;
            if (new_y && Array.isArray(new_y) && new_y.length) {
                // range init and end cannot have same value
                var range_end = Math.max.apply(Math, new_y);
                if (range_end == 0 || range_end == -Infinity) {
                    range_end = 1;
                }
                range_slider.value = [0, Math.max.apply(Math, final_y)]; 
                range_slider.end = range_end;
                fig.y_range.end = Math.max.apply(Math, final_y);
            }
        """)

    y_axis.js_on_change('value', y_axis_callback)

    # sort order control
    sort_order_callback = CustomJS(args=dict(
        source=source,
        x_source=x_count_source,
        o_data=barchart_data,
        x_axis_map=x_axis_map,
        x_axis=x_axis,
        y_axis_map=y_axis_map,
        y_axis=y_axis,
        range_slider=range_slider,
        checkbox=checkbox,
        checkbox_limit_results=checkbox_limit_results,
        fig=p),
                                   code=SORT_FUNCTION + JS_NUM_RESULTS + """
            var data = o_data[x_axis_map[x_axis.value]];
            var x = data['x'];
            var y = data['y'];
            // Sort data
            var is_ratio = checkbox.active.length > 0;
            var sorted_data = sortData(data['raw'], cb_obj.active, y_axis_map[y_axis.value], is_ratio);
            var new_y = [];
            var new_x = [];
            var final_x = [];
            var final_y = [];
            // push data if it lies inside range
            for (var i = 0; i < x.length; i++) {
                    if (checkbox_limit_results.active.length <= 0)
                    {
                        if (sorted_data[i][1] >= cb_obj.value[0] && sorted_data[i][1] <= cb_obj.value[1]) 
                        {
                            new_x.push(sorted_data[i][0]);
                            new_y.push(sorted_data[i][1]);
                        }
                    } else {
                        new_x.push(sorted_data[i][0]);
                        new_y.push(sorted_data[i][1]);                        
                    }
            }
            if (checkbox_limit_results.active.length > 0)
            { 
                final_x = new_x.slice(0, 50);
                final_y = new_y.slice(0, 50);
                window.should_update_range = false;
            } else {
                final_x = new_x;
                final_y = new_y;
                window.should_update_range = true;
            }
            x_source.data['x_count'] = [final_x.length];
            x_source.data['category'] = [x_axis.value];
            x_source.change.emit();
            source.data['x'] = new_x;
            source.data['y'] = new_y;
            source.change.emit();
            fig.x_range.factors = [];
            fig.x_range.factors = final_x;
            if (new_y && Array.isArray(new_y) && new_y.length) {
                // range init and end cannot have same value
                var range_end = Math.max.apply(Math, new_y);
                if (range_end == 0 || range_end == -Infinity) {
                    range_end = 1;
                }
                range_slider.value = [0, Math.max.apply(Math, final_y)]; 
                range_slider.end = range_end;
                fig.y_range.end = Math.max.apply(Math, final_y);
                fig.change.emit();
            }
        """)

    sort_order.js_on_change('active', sort_order_callback)

    # Define layout
    inputs = column(*controls, width=320, height=1000)
    inputs.sizing_mode = "fixed"
    l = layout([
        [desc],
        [inputs, p],
    ], sizing_mode="scale_both")

    return l
def make_explorer(blocks_path: str):
    '''
    Loads a blocks path and creates an explorer for
    viewing blocks based on certain criteria
    '''

    blocks = gpd.read_file(blocks_path).to_crs("EPSG:3857")
    p_width = 1200
    p_height = 600

    blocks['x'] = blocks['geometry'].apply(
        lambda p: get_polygon_coords(p, 'x'))
    blocks['y'] = blocks['geometry'].apply(
        lambda p: get_polygon_coords(p, 'y'))
    blocks['color'] = ['red'] * blocks.shape[0]

    blocks_df = blocks.drop(columns=['geometry'])
    blocks_source = ColumnDataSource(data=blocks_df)

    TOOLTIPS = [('OpenArea', '@max_dist'), ('BldgDensity', '@bldg_density'),
                ('BlockID', '@id')]
    p = figure(background_fill_color="lightgrey",
               tooltips=TOOLTIPS,
               plot_width=p_width,
               plot_height=p_height,
               match_aspect=True)

    p_map = figure(background_fill_color="lightgrey",
                   tooltips=TOOLTIPS,
                   plot_width=p_width,
                   plot_height=p_height,
                   x_range=p.x_range,
                   y_range=p.y_range)

    # p = figure(background_fill_color="lightgrey", tooltips=TOOLTIPS, plot_width=p_width, plot_height=p_height,
    #          x_axis_type="mercator", y_axis_type="mercator", match_aspect=True)

    # p_map = figure(background_fill_color="lightgrey", tooltips=TOOLTIPS, plot_width=p_width, plot_height=p_height,
    #              x_axis_type="mercator", y_axis_type="mercator", x_range=p.x_range, y_range=p.y_range)
    blocks_source = ColumnDataSource(data=blocks_df)
    # Add patch renderer to figure.
    tile_provider = get_provider(Vendors.ESRI_IMAGERY)
    tile_provider2 = get_provider(Vendors.ESRI_IMAGERY)
    p.add_tile(tile_provider)
    p.patches('x',
              'y',
              source=blocks_source,
              fill_color='color',
              line_color='black',
              line_width=.5,
              fill_alpha=0.5)
    p_map.add_tile(tile_provider2)

    density_slider = RangeSlider(start=0.0,
                                 end=1.0,
                                 value=(0.0, 1.0),
                                 step=.01,
                                 title="Selected density")
    b_min = blocks['max_dist'].min()
    b_max = blocks['max_dist'].max()
    area_slider = RangeSlider(start=b_min,
                              end=b_max,
                              value=(b_min, b_max),
                              title='Selected open area')

    javascript_string = """
            var data = source.data;
            var color = data['color'];

            var v_min = cb_obj.value[0];
            var v_max = cb_obj.value[1];
            var col_data = data[col];

            var v_min_other = other_slider.value[0];
            var v_max_other = other_slider.value[1];
            var other_col_data = data[other_col];

            var l = color.length;
            
            var cur_col_data = 0.0;
            var col_bool = true;

            var other_cur_col_data = 0.0;
            var other_col_bool = true;

            for (var i = 0; i < l; i++) {
              
              cur_col_data = col_data[i];
              other_cur_col_data = other_col_data[i];

              col_bool = cur_col_data >= v_min && cur_col_data <= v_max;
              other_col_bool = other_cur_col_data >= v_min_other && other_cur_col_data <= v_max_other;
              
              if (col_bool && other_col_bool) {
                color[i] = 'red';
              }
              else {
                color[i] = 'blue';
              }
            }

            source.change.emit();
        """

    density_callback = CustomJS(args=dict(source=blocks_source,
                                          col='bldg_density',
                                          other_slider=area_slider,
                                          other_col='max_dist'),
                                code=javascript_string)

    area_callback = CustomJS(args=dict(source=blocks_source,
                                       col='max_dist',
                                       other_slider=density_slider,
                                       other_col='bldg_density'),
                             code=javascript_string)

    density_slider.js_on_change('value', density_callback)
    area_slider.js_on_change('value', area_callback)

    layout = column(density_slider, area_slider, p, p_map)
    return layout, blocks