bokeh.models.BoxAnnotation

Here are the examples of the python api bokeh.models.BoxAnnotation taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.

9 Examples 7

0 Source : visual_midi.py
with MIT License
from dubreuia

    def plot(self, pm: PrettyMIDI):
        """
        Plots the pretty midi object as a plot object.

          :param pm: the PrettyMIDI instance to plot
          :return: the bokeh plot layout
        """
        preset = self._preset

        # Calculates the QPM from the MIDI file, might raise exception if confused
        qpm = self._get_qpm(pm)

        # Initialize the tools, those are present on the right hand side
        plot = bokeh.plotting.figure(
            tools="reset,hover,save,wheel_zoom,pan",
            toolbar_location=preset.toolbar_location)

        # Setup the hover and the data dict for bokeh,
        # each property must match a property in the data dict
        plot.select(dict(type=bokeh.models.HoverTool)).tooltips = ({
            "program": "@program",
            "pitch": "@top",
            "velocity": "@velocity",
            "duration": "@duration",
            "start_time": "@left",
            "end_time": "@right"})
        data = dict(
            program=[],
            top=[],
            bottom=[],
            left=[],
            right=[],
            duration=[],
            velocity=[],
            color=[])

        # Puts the notes in the dict for bokeh and saves first
        # and last note time, bigger and smaller pitch
        pitch_min = None
        pitch_max = None
        first_note_start = None
        last_note_end = None
        index_instrument = 0
        for instrument in pm.instruments:
            for note in instrument.notes:
                pitch_min = min(pitch_min or self._MAX_PITCH, note.pitch)
                pitch_max = max(pitch_max or self._MIN_PITCH, note.pitch)
                color = self._get_color(index_instrument, note)
                note_start = note.start
                note_end = note.start + (note.end - note.start)
                data["program"].append(instrument.program)
                data["top"].append(note.pitch)
                if self._show_velocity:
                    data["bottom"].append(note.pitch + (note.velocity / 127))
                else:
                    data["bottom"].append(note.pitch + 1)
                data["left"].append(note_start)
                data["right"].append(note_end)
                data["duration"].append(note_end - note_start)
                data["velocity"].append(note.velocity)
                data["color"].append(color)
                first_note_start = min(first_note_start or sys.maxsize, note_start)
                last_note_end = max(last_note_end or 0, note_end)
            index_instrument = index_instrument + 1

        # Shows an empty plot even if there are no notes
        if first_note_start is None or last_note_end is None or pitch_min is None or pitch_max is None:
            pitch_min = self._MIN_PITCH
            pitch_max = pitch_min + 5
            first_note_start = 0
            last_note_end = 0

        # Gets the pitch range (min, max) from either the provided arguments
        # or min and max values from the notes
        if self._plot_pitch_range_start is not None:
            pitch_min = self._plot_pitch_range_start
        else:
            pitch_min = min(self._MAX_PITCH, pitch_min)
        if self._plot_pitch_range_stop is not None:
            pitch_max = self._plot_pitch_range_stop
        else:
            pitch_max = max(self._MIN_PITCH, pitch_max)

        pitch_range = pitch_max + 1 - pitch_min

        # Draws the rectangles on the plot from the data
        source = ColumnDataSource(data=data)
        plot.quad(left="left",
                  right="right",
                  top="top",
                  bottom="bottom",
                  line_alpha=1,
                  line_color="black",
                  color="color",
                  source=source)

        # Draws the y grid by hand, because the grid has label on the ticks, but
        # for a plot like this, the labels needs to fit in between the ticks.
        # Also useful to change the background of the grid each line
        for pitch in range(pitch_min, pitch_max + 1):
            # Draws the background box and contours, on the underlay layer, so
            # that the rectangles and over the box annotations
            fill_alpha = (0.15 if pitch % 2 == 0 else 0.00)
            box = BoxAnnotation(bottom=pitch,
                                top=pitch + 1,
                                fill_color="gray",
                                fill_alpha=fill_alpha,
                                line_color="black",
                                line_alpha=0.3,
                                line_width=1,
                                level="underlay")
            plot.add_layout(box)
            label = Label(
                x=preset.label_y_axis_offset_x,
                y=pitch + preset.label_y_axis_offset_y,
                x_units="screen",
                text=str(pitch),
                render_mode="css",
                text_font_size=preset.label_text_font_size,
                text_font_style=preset.label_text_font_style)
            plot.add_layout(label)

        # Gets the time signature from pretty midi, or 4/4 if none
        if self._midi_time_signature:
            numerator, denominator = self._midi_time_signature.split("/")
            time_signature = TimeSignature(int(numerator), int(denominator), 0)
        else:
            if pm.time_signature_changes:
                if len(pm.time_signature_changes) > 1:
                    raise Exception("Multiple time signatures are not supported")
                time_signature = pm.time_signature_changes[0]
            else:
                time_signature = TimeSignature(4, 4, 0)

        # Gets seconds per bar and seconds per beat
        if len(pm.get_beats()) >= 2:
            seconds_per_beat = pm.get_beats()[1] - pm.get_beats()[0]
        else:
            seconds_per_beat = 0.5
        if len(pm.get_downbeats()) >= 2:
            seconds_per_bar = pm.get_downbeats()[1] - pm.get_downbeats()[0]
        else:
            seconds_per_bar = 2.0

        # Defines the end time of the plot in seconds
        if self._plot_bar_range_stop is not None:
            plot_end_time = self._plot_bar_range_stop * seconds_per_bar
        else:
            # Calculates the plot start and end time, the start time can start after
            # notes or truncate notes if the plot is too long (we left truncate the
            # plot with the bounds)
            # The plot start and plot end are a multiple of seconds per bar (closest
            # smaller value for the start time, closest higher value for the end time)
            plot_end_time = int((last_note_end) / seconds_per_bar) * seconds_per_bar
            # If the last note end is exactly on a multiple of seconds per bar,
            # we don't start a new one
            is_on_bar = math.isclose(last_note_end % seconds_per_bar, seconds_per_bar)
            is_on_bar_exact = math.isclose(last_note_end % seconds_per_bar, 0.0)
            if not is_on_bar and not is_on_bar_exact:
                plot_end_time += seconds_per_bar

        # Defines the start time of the plot in seconds
        if self._plot_bar_range_start is not None:
            plot_start_time = self._plot_bar_range_start * seconds_per_bar
        else:
            start_time = int(first_note_start / seconds_per_bar) * seconds_per_bar
            plot_max_length_time = self._plot_max_length_bar * seconds_per_bar
            plot_start_time = max(plot_end_time - plot_max_length_time, start_time)

        # Draws the vertical bar grid, with a different background color
        # for each bar
        if preset.show_bar:
            bar_count = 0
            for bar_time in pm.get_downbeats():
                fill_alpha_index = bar_count % len(self._bar_fill_alphas)
                fill_alpha = self._bar_fill_alphas[fill_alpha_index]
                box = BoxAnnotation(left=bar_time,
                                    right=bar_time + seconds_per_bar,
                                    fill_color="gray",
                                    fill_alpha=fill_alpha,
                                    line_color="black",
                                    line_width=2,
                                    line_alpha=0.5,
                                    level="underlay")
                plot.add_layout(box)
                bar_count += 1

        # Draws the vertical beat grid, those are only grid lines
        if preset.show_beat:
            for beat_time in pm.get_beats():
                box = BoxAnnotation(left=beat_time,
                                    right=beat_time + seconds_per_beat,
                                    fill_color=None,
                                    line_color="black",
                                    line_width=1,
                                    line_alpha=0.4,
                                    level="underlay")
                plot.add_layout(box)

        # Configure x axis
        plot.xaxis.bounds = (plot_start_time, plot_end_time)
        plot.xaxis.axis_label = "time (SEC)"
        plot.xaxis.axis_label_text_font_size = preset.axis_label_text_font_size
        plot.xaxis.ticker = bokeh.models.SingleIntervalTicker(interval=1)
        plot.xaxis.major_tick_line_alpha = 0.9
        plot.xaxis.major_tick_line_width = 1
        plot.xaxis.major_tick_out = preset.axis_x_major_tick_out
        plot.xaxis.minor_tick_line_alpha = 0
        plot.xaxis.major_label_text_font_size = preset.label_text_font_size
        plot.xaxis.major_label_text_font_style = preset.label_text_font_style

        # Configure y axis
        plot.yaxis.bounds = (pitch_min, pitch_max + 1)
        plot.yaxis.axis_label = "pitch (MIDI)"
        plot.yaxis.axis_label_text_font_size = preset.axis_label_text_font_size
        plot.yaxis.ticker = bokeh.models.SingleIntervalTicker(interval=1)
        plot.yaxis.major_label_text_alpha = 0
        plot.yaxis.major_tick_line_alpha = 0.9
        plot.yaxis.major_tick_line_width = 1
        plot.yaxis.major_tick_out = preset.axis_y_major_tick_out
        plot.yaxis.minor_tick_line_alpha = 0
        plot.yaxis.axis_label_standoff = preset.axis_y_label_standoff
        plot.outline_line_width = 1
        plot.outline_line_alpha = 1
        plot.outline_line_color = "black"

        # The x grid is deactivated because is draw by hand (see x grid code)
        plot.xgrid.grid_line_color = None

        # The y grid is deactivated because is draw by hand (see y grid code)
        plot.ygrid.grid_line_color = None

        # Configure the plot size and range
        if self._plot_title is None:
            plot_title_text = "Visual MIDI (%s QPM, %s/%s)" % (
                str(int(qpm)), time_signature.numerator, time_signature.denominator)
        else:
            plot_title_text = self._plot_title
        
        plot.title = Title(text=plot_title_text,
                           text_font_size=preset.title_text_font_size)
        plot.plot_width = preset.plot_width
        if preset.row_height:
            plot.plot_height = pitch_range * preset.row_height
        else:
            plot.plot_height = preset.plot_height
        plot.x_range = Range1d(plot_start_time, plot_end_time)
        plot.y_range = Range1d(pitch_min, pitch_max + 1)
        plot.min_border_right = 50

        if self._live_reload and preset.stop_live_reload_button:
            callback = CustomJS(code="clearInterval(liveReloadInterval)")
            button = Button(label="stop live reload")
            button.js_on_click(callback)
            layout = column(button, plot)
        else:
            layout = column(plot)

        return layout

    def save(self, pm: PrettyMIDI, filepath: str):

0 Source : genome_protein_plots.py
with GNU General Public License v3.0
from michellejlin

def protein_annotation(first):
	protein_locs = []
	protein_names = []
	protein_lengths = []

	# Shades in every other protein region. Provides warning if proteins overlap.
	for i in range(0, proteins.shape[0]):
		if(i==0):
			x1 = 0
		elif(proteins.iloc[i,1]   <   proteins.iloc[i-1,2]) and first:
			print('WARNING: Protein-' + str(proteins.iloc[i,0]) + ' is overlapping with Protein-' + str(proteins.iloc[i-1,0]))
			print('Analysis will continue but the visualization for these two proteins will look a little funny. Often the fix for this is simply deleting the small ancilary proteins that overlapping from the gff file and using the -f and -g flags. For more help see the readme.')
			x1 = proteins.iloc[i,1]
		else:
			x1 = proteins.iloc[i,1]
		if(i==proteins.shape[0]-1):
			x2 = proteins.iloc[i,2]
		else:
			x2 = proteins.iloc[(i+1),1]
		if(i%2==0):
			genome_plot.add_layout(BoxAnnotation(left=x1, right=x2, fill_alpha=0.1, fill_color='green'))
		protein_locs.append((x1+x2)/2)
		protein_lengths.append(x2-x1)
		protein_names.append(proteins.iloc[i,0])

	if(os.stat("mat_peptides_additions.txt").st_size!=0):
		# Makes arrows for mature peptides.
		for i in range(0, mat_peptides_list.shape[0]):
			x1 = mat_peptides_list.iloc[i,1]
			x2 = mat_peptides_list.iloc[i,2]
			genome_plot.add_layout(Arrow(end = VeeHead(size=20, fill_color = "cadetblue", fill_alpha = 0.3, line_alpha = 0), 
				line_color = "cadetblue", line_width = 20, x_start = x1, x_end = x2,
				y_start = 5, y_end = 5, line_alpha = 0.3))

	# Adds protein labels as tick marks.
	genome_plot.xaxis.ticker = protein_locs
	protein_locs2 = []
	for protein_loc in protein_locs:
		str_protein_loc = str(protein_loc)
		## print("old str_protein_loc" + str_protein_loc)
		if ".0" in str_protein_loc:
			str_protein_loc = str_protein_loc.split('.')[0]
			## print("split" + str_protein_loc)
			protein_locs2.append(int(str_protein_loc))
		else:
			protein_locs2.append(float(str_protein_loc))	
	genome_plot.xaxis.major_label_overrides = dict(zip(protein_locs2, protein_names))
	return protein_names,protein_lengths

	
# Creates the legend and configures some of the toolbar stuff.
def configurePlot(g):

0 Source : visualization.py
with MIT License
from pedromartins4

def plot_rsi(stock):
    p = figure(x_axis_type="datetime", plot_width=WIDTH_PLOT, plot_height=200, title="RSI 15 days",
               tools=TOOLS, toolbar_location='above')

    p.line(x='date', y='rsi_15', line_width=2, color=BLUE, source=stock)

    low_box = BoxAnnotation(top=30, fill_alpha=0.1, fill_color=RED)
    p.add_layout(low_box)
    high_box = BoxAnnotation(bottom=70, fill_alpha=0.1, fill_color=GREEN)
    p.add_layout(high_box)

    # Horizontal line
    hline = Span(location=50, dimension='width', line_color='black', line_width=0.5)
    p.renderers.extend([hline])

    p.y_range = Range1d(0, 100)
    p.yaxis.ticker = [30, 50, 70]
    p.yaxis.formatter = PrintfTickFormatter(format="%f%%")
    p.grid.grid_line_alpha = 0.3

    return p


#### On-Balance Volume (OBV)
def plot_obv(stock):

0 Source : widgets.py
with MIT License
from smartyal

    def stream_update_backgrounds(self):
        """ we update the background by following this algo:
            - take the last existing entry in the backgrounds
            - do we have a new one which starts inside the last existing?
              NO: find the
        """
        #make current backgrounds from the latest data and check against the existing backgrounds, put those which we need to append
        newBackgrounds = self.make_background_entries(self.streamingUpdateData)
        addBackgrounds = [] # the backgrounds to be created new
        self.logger.debug("stream_update_backgrounds")
        if self.backgrounds == []:
            #we don't have backgrounds yet, make them
            self.hide_backgrounds()
        else:
            # we have backgrounds
            # now see if we have to adjust the last background
            for entry in newBackgrounds:
                if entry["start"]   <  = self.backgrounds[-1]["end"] and entry["end"] > self.backgrounds[-1]["end"]:
                    # this is the first to show, an overlapping or extending one, we cant' extend the existing easily, so
                    # we put the new just right of the old
                    addEntry = {"start": self.backgrounds[-1]["end"], "end": entry["end"], "value":entry["value"], "color": entry["color"]}
                    addBackgrounds.append(addEntry)
                if entry["start"] > self.backgrounds[-1]["end"] and entry["end"]> self.backgrounds[-1]["end"]:
                    #these are on the right side of the old ones, just add them
                    addBackgrounds.append(entry)

        boxes =[]

        for back in addBackgrounds:
            name = "__background"+str('%8x'%random.randrange(16**8))
            newBack = BoxAnnotation(left=back["start"], right=back["end"],
                                    fill_color=back["color"],
                                    fill_alpha=globalBackgroundsAlpha,
                                    level = globalBackgroundsLevel,
                                    name=name)  # +"_annotaion
            boxes.append(newBack)
            back["rendererName"]=name
            self.backgrounds.append(back) # put it in the list of backgrounds for later use

        self.plot.renderers.extend(boxes)

        #remove renderes out of sight
        deleteList = []
        for r in self.plot.renderers:
            if r.name and "__background" in r.name:
                #self.logger.debug(f"check {r.name}, is is {r.right} vs starttime {self.plot.x_range.start}")
                #this is a background, so let's see if it is out of sight
                if r.right  <  self.plot.x_range.start:
                    #this one can go, we can't see it anymore
                    deleteList.append(r.name)
        self.logger.debug(f"remove background renderes out of sight{deleteList}")
        if deleteList:
            self.remove_renderers(deleteList=deleteList)


        #newBackgrounds = self.make_background_entries(self.streamingUpdateData)
        #self.hide_backgrounds()
        #self.show_backgrounds()


        return

    def stream_update_new(self,data):

0 Source : widgets.py
with MIT License
from smartyal

    def draw_annotation__old(self, anno, visible=False):
        """
            draw one time annotation on the plot
            Args:
             anno: the annotation
             visible: true/false
        """
        try:
            #self.logger.debug(f"draw_annotation  {anno['name']} visible {visible}")

            tag = anno["tags"][0]
            mirror = self.server.get_mirror()
            myColors = mirror["hasAnnotation"]["colors"][".properties"]["value"]
            myTags = mirror["hasAnnotation"]["tags"][".properties"]["value"]

            try: # to set color and pattern
                if type(myColors) is list:
                    tagIndex = myTags.index(tag)
                    pattern = None
                    color = myColors[tagIndex]
                elif type(myColors) is dict:
                    color = myColors[tag]["color"]
                    pattern = myColors[tag]["pattern"]
                    if not pattern is None:
                        if pattern not in [" ",".","o","-","|","+",":","@","/","\\","x",",","`","v",">","*"]:
                            pattern = 'x'
            except:
                color = None
                pattern = None
            if not color:
                self.logger.error("did not find color for boxannotation")
                color = "red"

            start = anno["startTime"]
            end = anno["endTime"]

            infinity=globalInfinity
            # we must use varea, as this is the only one glyph that supports hatches and does not create a blue box when zooming out
            #self.logger.debug(f"have pattern with hatch {pattern}, tag {tag}, color{color} ")
            

            if not pattern is None:
                """
                source = ColumnDataSource(dict(x=[start, end], y1=[-infinity, -infinity], y2=[infinity, infinity]))
                area = VArea(x="x",y1="y1",y2="y2",
                                    fill_color=color,
                                    name=anno["id"],
                                    fill_alpha=globalAnnotationsAlpha,
                                    hatch_color="black",
                                    hatch_pattern=pattern,
                                    hatch_alpha=1.0)
                rendererType = "VArea"
                """
                source = ColumnDataSource(dict(x=[start + (end - start) / 2], t=[infinity], b=[-infinity], w=[end - start]))
                area = VBar(x="x", top="t", bottom="b", width="w",
                            fill_color=color,
                            name=anno["id"],
                            fill_alpha=globalAnnotationsAlpha,
                            hatch_color="black",
                            hatch_pattern=pattern,
                            hatch_alpha=1.0)
                
                
                myrenderer = GlyphRenderer(data_source=source, glyph=area, name=anno['id'])
                myrenderer.level = globalThresholdsLevel
                rendererType = "VBar"
            else:
                #we use a Boxannotation as this is a lot more efficient in bokeh
                """ 
                area = VArea(x="x", y1="y1", y2="y2",
                                    fill_color=color,
                                    name=anno["id"],
                                    fill_alpha=globalAlpha)
                """
                if any([True for tag in anno["tags"] if "anomaly" in tag]):
                    # if we have an anomaly to draw, we put it on top
                    level = globalThresholdsLevel
                else:
                    level = globalAnnotationLevel

                if BOX_ANNO:
                    source = None
                    myrenderer = BoxAnnotation(left=start,right=end,fill_color=color,fill_alpha=globalAnnotationsAlpha,name=anno['id'],level=level)
                    rendererType = "BoxAnnotation"
                else:
                    #use rect
                    source = ColumnDataSource({"l": [start+(end-start)/2],"w": [end-start],"y": [-infinity],"height": [3 * infinity]})
                    recta = Rect(x="l", y="y", width="w", height="height", fill_color=color, fill_alpha=globalAnnotationsAlpha)
                    myrenderer = GlyphRenderer(data_source=source, glyph=recta, name=anno['id'],level=level)
                    rendererType = "Rect"

                    if myrenderer not in self.annoHovers:
                        self.annoHovers.append(myrenderer)


            # bokeh hack to avoid adding the renderers directly: we create a renderer from the glyph and store it for later bulk assing to the plot
            # which is a lot faster than one by one

            if 0: #this was a trial for an extra object to hover the annotations
                dic = {"y": [0],
                       "x": [start+(end-start)/20],
                       "w":[end-start],
                       "h":[infinity],
                       "l":[start],
                       "r":[end-start],
                       "t":[infinity],
                       "b":[-infinity],
                       "f":[0.9]}
                col = ColumnDataSource(dic)
                # the only glyph that worked for hovering was the circle, rect, quad did not work
                #annoHover = self.plot.circle(x="x", y="f",size=15, fill_color="white",fill_alpha=0.5,source=col,name="annohover",y_range_name="y2",line_color="white",line_width=2) #works
                 #self.annoHovers.append(annoHover)

            if visible:
                self.add_renderers([myrenderer])

            self.renderers[anno["id"]] = {"renderer": myrenderer, "info": copy.deepcopy(anno),"source": source,"rendererType":rendererType}  # we keep this renderer to speed up later


            self.__make_tooltips(force=True) #xxxkna

        except Exception as ex:
            self.logger.error(f"error draw annotation {anno}"+str(ex))
            return None

    def create_annotations_glyph(self, tag):

0 Source : widgets.py
with MIT License
from smartyal

    def draw_threshold(self, annoDict):#, linePath=None):
        """ draw the boxannotation for a threshold
            Args:
                 modelPath(string): the path to the annotation, the modelPath-node must contain children startTime, endTime, colors, tags
        """
        self.logger.debug(f"draw thresholds {annoDict}")
        try:
            #if the box is there already, then we skip
            if annoDict["id"] in self.renderers:
                self.logger.warning(f"have this already {annoDict['id']}")
                return
            #foundRenderer = self.find_renderer(annoDict["id"])
            #if foundRenderer:
            #    #nothing to do
            #    return



            #annotations = self.server.get_annotations()
            # now get the first tag, we only use the first
            #tag = annoDict["tags"][0]



            color = self.lines[annoDict["variable"]].glyph.line_color

            min = annoDict["min"]
            max = annoDict["max"]
            if min>max:
                max,min = min,max # swap them

            # print("draw new anno",color,start,end,modelPath)

            if self.server.is_y2_variable(annoDict["variable"]):
                newAnno = BoxAnnotation(top=max, bottom=min,
                                        fill_color=color,
                                        fill_alpha=globalThresholdsAlpha,
                                        level=globalThresholdsLevel,
                                        name=annoDict["id"],y_range_name="y2")  # +"_annotaion
            else:

                newAnno = BoxAnnotation(top=max, bottom=min,
                                        fill_color=color,
                                        fill_alpha=globalThresholdsAlpha,
                                        level = globalThresholdsLevel,
                                        name=annoDict["id"])  # +"_annotaion

            self.add_renderers([newAnno])

            self.renderers[annoDict["id"]] = {"renderer": newAnno, "info": copy.deepcopy(annoDict)}  # we keep this renderer to speed up later


        except Exception as ex:
            self.logger.error("error draw threshold "+str(annoDict["id"])+str(ex))


    def draw_threshold2(self, anno,visible=False):

0 Source : widgets.py
with MIT License
from smartyal

    def draw_threshold2(self, anno,visible=False):
        """ draw the boxannotation for a threshold
            Args:
                 anno
        """

        try:
            tag = anno["tags"][0]

            if linePath:
                color = self.lines[linePath].glyph.line_color
            else:
                color ="blue"

            min = annotations[modelPath]["min"]
            max = annotations[modelPath]["max"]
            if min>max:
                max,min = min,max # swap them

            # print("draw new anno",color,start,end,modelPath)

            newAnno = BoxAnnotation(top=max, bottom=min,
                                    fill_color=color,
                                    fill_alpha=globalAlpha,
                                    name=modelPath)  # +"_annotaion

            self.add_renderers([newAnno])
        except Exception as ex:
            self.logger.error("error draw threshold "+str(modelPath)+ " "+linePath+" "+str(ex))


    def make_background_entries(self, data, roundValues = True):

0 Source : widgets.py
with MIT License
from smartyal

    def show_backgrounds(self,data=None):
        """
            show the current backgrounds
            Args:
                data(dict):  contains a dict holding the nodeid with of the background and the __time as keys and the lists of data
                    if te data is not given, we get the backgrounds fresh from the data server
        """
        self.showBackgrounds=True

        try:
            self.logger.debug("show_backgrounds()")
            backGroundNodeId = self.server.get_settings()["background"]["background"]

            if not data:
                #we have to pick up the background data first
                self.logger.debug("get fresh background data from the model server %s",backGroundNodeId)
                bins = self.server.get_settings()["bins"]
                getData = self.server.get_data([backGroundNodeId], start=self.rangeStart, end=self.rangeEnd,
                                               bins=bins)  # for debug
                data = getData

            #now make the new backgrounds
            backgrounds = self.make_background_entries(data)
            #now we have a list of backgrounds
            self.logger.info("have %i background entries",len(backgrounds))
            #now plot them

            boxes =[]

            self.backgrounds=[]

            for back in backgrounds:
                name = "__background"+str('%8x'%random.randrange(16**8))
                newBack = BoxAnnotation(left=back["start"], right=back["end"],
                                        fill_color=back["color"],
                                        fill_alpha=globalBackgroundsAlpha,
                                        level = globalBackgroundsLevel,
                                        name=name)  # +"_annotaion
                boxes.append(newBack)
                back["rendererName"] = name
                self.backgrounds.append(back)  # put it in the list of backgrounds for later look up for streaming

            self.plot.renderers.extend(boxes)
        except Exception as ex:
            self.logger.error(f"problem duringshow_backgrounds {ex} ")

    def hide_backgrounds(self):

0 Source : callout.py
with Apache License 2.0
from spotify

    def box(self,
            top=None,
            bottom=None,
            left=None,
            right=None,
            alpha=.2,
            color='red'):
        """Add box callout to the chart.

        Args:
            top (numeric, optional): Top edge of the box.
            bottom (numeric, optional): Bottom edge of the box.
            left (numeric, optional): Left edge of the box.
            right (numeric, optional): Right edge of the box.
            alpha (float, optional): 0.2
            color (str): Color name or hex value.
                See chartify.color_palettes.show() for available color names.

        Note:
            The box will extend to the edge if the corresponding position
            argument is omitted.

        Returns:
            Current chart object
        """
        # Convert datetime values to epoch if datetime axis.
        if isinstance(self._chart.axes, DatetimeXNumericalYAxes):
            if left is not None:
                left = self._chart.axes._convert_timestamp_to_epoch_ms(left)
            if right is not None:
                right = self._chart.axes._convert_timestamp_to_epoch_ms(right)
        color = colors.Color(color).get_hex_l()
        box = bokeh.models.BoxAnnotation(
            top=top,
            bottom=bottom,
            left=left,
            right=right,
            fill_alpha=alpha,
            fill_color=color)
        self._chart.figure.add_layout(box)
        return self._chart

    def text(self,