Esempio n. 1
0
    def build_color_lines(df: pd.DataFrame, scheme, col_open: str = 'open', col_close: str = 'close', col_prefix: str = '') -> pd.DataFrame:
        # build color strings from scheme
        colorup = convert_color(scheme.barup)
        colordown = convert_color(scheme.bardown)
        colorup_wick = convert_color(scheme.barup_wick)
        colordown_wick = convert_color(scheme.bardown_wick)
        colorup_outline = convert_color(scheme.barup_outline)
        colordown_outline = convert_color(scheme.bardown_outline)
        volup = convert_color(scheme.volup)
        voldown = convert_color(scheme.voldown)

        # build binary series determining if up or down bar
        is_up: pd.DataFrame = df[col_close] >= df[col_open]

        # we use the open-line as a indicator for NaN values
        nan_ref = df[col_open]

        # TODO: we want to have NaN values in the color lines if the corresponding data is also NaN
        # find better way with less isnan usage

        color_df = pd.DataFrame(index=df.index)
        color_df[col_prefix + 'colors_bars'] = [np.nan if np.isnan(n) else colorup if x else colordown for x, n in zip(is_up, nan_ref)]
        color_df[col_prefix + 'colors_wicks'] = [np.nan if np.isnan(n) else colorup_wick if x else colordown_wick for x, n in zip(is_up, nan_ref)]
        color_df[col_prefix + 'colors_outline'] = [np.nan if np.isnan(n) else colorup_outline if x else colordown_outline for x, n in zip(is_up, nan_ref)]
        color_df[col_prefix + 'colors_volume'] = [np.nan if np.isnan(n) else volup if x else voldown for x, n in zip(is_up, nan_ref)]

        # convert to object since we want to hold str and NaN
        for c in color_df.columns:
            color_df[c] = color_df[c].astype(object)

        return color_df
Esempio n. 2
0
    def plot_data(self, data: bt.AbstractDataBase):
        source_id = FigureEnvelope._source_id(data)
        # title = sanitize_source_name(label_resolver.datatarget2label([data]))
        title = ""
        legend_label = "OHLC"
        # append to title
        self._figure_append_title(title)

        self._add_columns([(source_id + x, object) for x in ['open', 'high', 'low', 'close']])
        self._add_columns([(source_id + x, str) for x in ['colors_bars', 'colors_wicks', 'colors_outline']])

        if self._scheme.style == 'line':
            if data.plotinfo.plotmaster is None:
                color = convert_color(self._scheme.loc)
            else:
                self._nextcolor(data.plotinfo.plotmaster)
                color = convert_color(self._color(data.plotinfo.plotmaster))

            renderer = self.figure.line('index', source_id + 'close', source=self._cds, line_color=color, legend_label=legend_label)
            self._set_single_hover_renderer(renderer)

            self._hoverc.add_hovertip("Close", f"@{source_id}close", data)
        elif self._scheme.style == 'bar':
            self.figure.segment('index', source_id + 'high', 'index', source_id + 'low', source=self._cds, color=source_id + 'colors_wicks', legend_label=legend_label)
            renderer = self.figure.vbar('index',
                                        get_bar_width(),
                                        source_id + 'open',
                                        source_id + 'close',
                                        source=self._cds,
                                        fill_color=source_id + 'colors_bars',
                                        line_color=source_id + 'colors_outline',
                                        legend_label=legend_label,
                                        )

            self._set_single_hover_renderer(renderer)

            self._hoverc.add_hovertip("Open", f"@{source_id}open{{{self._scheme.number_format}}}", data)
            self._hoverc.add_hovertip("High", f"@{source_id}high{{{self._scheme.number_format}}}", data)
            self._hoverc.add_hovertip("Low", f"@{source_id}low{{{self._scheme.number_format}}}", data)
            self._hoverc.add_hovertip("Close", f"@{source_id}close{{{self._scheme.number_format}}}", data)
        else:
            raise Exception(f"Unsupported style '{self._scheme.style}'")

        # make sure the regular y-axis only scales to the normal data on 1st axis (not to e.g. volume data on 2nd axis)
        self.figure.y_range.renderers.append(renderer)

        if self._scheme.volume and self._scheme.voloverlay:
            self.plot_volume(data, self._scheme.voltrans, True)
Esempio n. 3
0
    def plot_volume(self,
                    data: bt.AbstractDataBase,
                    alpha=1.0,
                    extra_axis=False):
        """extra_axis displays a second axis (for overlay on data plotting)"""
        source_id = FigureEnvelope._source_id(data)

        self._add_columns([(source_id + 'volume', np.float64),
                           (source_id + 'colors_volume', np.object)])
        kwargs = {
            'fill_alpha': alpha,
            'line_alpha': alpha,
            'name': 'Volume',
            'legend_label': 'Volume'
        }

        ax_formatter = NumeralTickFormatter(format=self._scheme.number_format)

        if extra_axis:
            source_data_axis = 'axvol'

            self.figure.extra_y_ranges = {
                source_data_axis:
                DataRange1d(
                    range_padding=1.0 / self._scheme.volscaling,
                    start=0,
                )
            }

            # use colorup
            ax_color = convert_color(self._scheme.volup)

            ax = LinearAxis(y_range_name=source_data_axis,
                            formatter=ax_formatter,
                            axis_label_text_color=ax_color,
                            axis_line_color=ax_color,
                            major_label_text_color=ax_color,
                            major_tick_line_color=ax_color,
                            minor_tick_line_color=ax_color)
            self.figure.add_layout(ax, 'left')
            kwargs['y_range_name'] = source_data_axis
        else:
            self.figure.yaxis.formatter = ax_formatter

        vbars = self.figure.vbar('index',
                                 get_bar_width(),
                                 f'{source_id}volume',
                                 0,
                                 source=self._cds,
                                 fill_color=f'{source_id}colors_volume',
                                 line_color="black",
                                 **kwargs)

        # make sure the new axis only auto-scales to the volume data
        if extra_axis:
            self.figure.extra_y_ranges['axvol'].renderers = [vbars]

        self._hoverc.add_hovertip(
            "Volume", f"@{source_id}volume{{({self._scheme.number_format})}}",
            data)
Esempio n. 4
0
    def _plot_hlines(self, obj):
        hlines = obj.plotinfo._get('plothlines', [])
        if not hlines:
            hlines = obj.plotinfo._get('plotyhlines', [])

        # Horizontal Lines
        hline_color = convert_color(self._scheme.hlinescolor)
        for hline in hlines:
            span = Span(location=hline,
                        dimension='width',
                        line_color=hline_color,
                        line_dash=convert_linestyle(self._scheme.hlinesstyle),
                        line_width=self._scheme.hlineswidth)
            self.figure.renderers.append(span)
Esempio n. 5
0
    def _plot_indicator_observer(self,
                                 obj: Union[bt.Indicator, bt.Observer],
                                 master,
                                 strat_clk: array = None):
        pl = plotobj2label(obj)

        self._figure_append_title(pl)
        indlabel = obj.plotlabel()
        plotinfo = obj.plotinfo

        for lineidx in range(obj.size()):
            line = obj.lines[lineidx]
            source_id = Figure._source_id(line)
            linealias = obj.lines._getlinealias(lineidx)

            lineplotinfo = getattr(obj.plotlines, '_%d' % lineidx, None)
            if not lineplotinfo:
                lineplotinfo = getattr(obj.plotlines, linealias, None)

            if not lineplotinfo:
                lineplotinfo = bt.AutoInfoClass()

            if lineplotinfo._get('_plotskip', False):
                continue

            marker = lineplotinfo._get("marker", None)
            method = lineplotinfo._get('_method', "line")

            color = getattr(lineplotinfo, "color", None)
            if color is None:
                if not lineplotinfo._get('_samecolor', False):
                    self._nextcolor()
                color = self._color()
            color = convert_color(color)

            kwglyphs = {'name': linealias}

            dataline = line.plotrange(self._start, self._end)
            line_clk = get_data_obj(obj).lines.datetime.plotrange(
                self._start, self._end)
            dataline = resample_line(dataline, line_clk, strat_clk)
            self._add_to_cds(dataline, source_id)

            label = None
            if master is None or lineidx == 0 or plotinfo.plotlinelabels:
                label = indlabel
                if master is None or plotinfo.plotlinelabels:
                    label += " " + (lineplotinfo._get("_name", "")
                                    or linealias)
            kwglyphs['legend_label'] = label

            if marker is not None:
                kwglyphs['size'] = lineplotinfo.markersize * 1.2
                kwglyphs['color'] = color
                kwglyphs['y'] = source_id

                mrk_fncs = {
                    '^': self.figure.triangle,
                    'v': self.figure.inverted_triangle,
                    'o': self.figure.circle,
                    '<': self.figure.circle_cross,
                    '>': self.figure.circle_x,
                    '1': self.figure.diamond,
                    '2': self.figure.diamond_cross,
                    '3': self.figure.hex,
                    '4': self.figure.square,
                    '8': self.figure.square_cross,
                    's': self.figure.square_x,
                    'p': self.figure.triangle,
                    '*': self.figure.asterisk,
                    'h': self.figure.hex,
                    'H': self.figure.hex,
                    '+': self.figure.asterisk,
                    'x': self.figure.x,
                    'D': self.figure.diamond_cross,
                    'd': self.figure.diamond,
                }
                if marker not in mrk_fncs:
                    raise Exception(
                        f"Sorry, unsupported marker: '{marker}'. Please report to GitHub."
                    )
                glyph_fnc = mrk_fncs[marker]
            elif method == "bar":
                kwglyphs['bottom'] = 0
                kwglyphs['line_color'] = 'black'
                kwglyphs['fill_color'] = color
                kwglyphs['width'] = get_bar_width()
                kwglyphs['top'] = source_id

                glyph_fnc = self.figure.vbar
            elif method == "line":
                kwglyphs['line_width'] = 1
                kwglyphs['color'] = color
                kwglyphs['y'] = source_id

                linestyle = getattr(lineplotinfo, "ls", None)
                if linestyle is not None:
                    kwglyphs['line_dash'] = convert_linestyle(linestyle)

                glyph_fnc = self.figure.line
            else:
                raise Exception(f"Unknown plotting method '{method}'")

            renderer = glyph_fnc("index", source=self._cds, **kwglyphs)

            # for markers add additional renderer so hover pops up for all of them
            if marker is None:
                self._set_single_hover_renderer(renderer)
            else:
                self._add_hover_renderer(renderer)

            hover_label_suffix = f" - {linealias}" if obj.size(
            ) > 1 else ""  # we need no suffix if there is just one line in the indicator anyway
            hover_label = indlabel + hover_label_suffix
            hover_data = f"@{source_id}{{{self._scheme.number_format}}}"
            self._hoverc.add_hovertip(hover_label, hover_data, obj)

            # adapt y-axis if needed
            if master is None or getattr(master.plotinfo, 'plotylimited',
                                         False) is False:
                adapt_yranges(self.figure.y_range, dataline)

        self._set_yticks(obj)
        self._plot_hlines(obj)
Esempio n. 6
0
    def plot_volume(self,
                    data: bt.AbstractDataBase,
                    strat_clk: array,
                    alpha,
                    extra_axis=False):
        """extra_axis displays a second axis (for overlay on data plotting)"""
        source_id = Figure._source_id(data)

        df = convert_to_pandas(strat_clk, data, self._start, self._end)

        if len(nanfilt(df.volume)) == 0:
            return

        colorup = convert_color(self._scheme.volup)
        colordown = convert_color(self._scheme.voldown)

        is_up = df.close > df.open
        colors = [colorup if x else colordown for x in is_up]

        self._add_to_cds(df.volume, f'{source_id}volume')
        self._add_to_cds(colors, f'{source_id}volume_colors')

        kwargs = {
            'fill_alpha': alpha,
            'line_alpha': alpha,
            'name': 'Volume',
            'legend_label': 'Volume'
        }

        ax_formatter = NumeralTickFormatter(format=self._scheme.number_format)

        if extra_axis:
            self.figure.extra_y_ranges = {'axvol': DataRange1d()}
            adapt_yranges(self.figure.extra_y_ranges['axvol'], df.volume)
            self.figure.extra_y_ranges['axvol'].end /= self._scheme.volscaling

            ax_color = colorup

            ax = LinearAxis(y_range_name="axvol",
                            formatter=ax_formatter,
                            axis_label_text_color=ax_color,
                            axis_line_color=ax_color,
                            major_label_text_color=ax_color,
                            major_tick_line_color=ax_color,
                            minor_tick_line_color=ax_color)
            self.figure.add_layout(ax, 'left')
            kwargs['y_range_name'] = "axvol"
        else:
            self.figure.yaxis.formatter = ax_formatter
            adapt_yranges(self.figure.y_range, df.volume)
            self.figure.y_range.end /= self._scheme.volscaling

        self.figure.vbar('index',
                         get_bar_width(),
                         f'{source_id}volume',
                         0,
                         source=self._cds,
                         fill_color=f'{source_id}volume_colors',
                         line_color="black",
                         **kwargs)

        self._hoverc.add_hovertip(
            "Volume", f"@{source_id}volume{{({self._scheme.number_format})}}",
            data)
Esempio n. 7
0
    def plot_data(self, data: bt.AbstractDataBase, strat_clk: array = None):
        source_id = Figure._source_id(data)
        title = sanitize_source_name(label_resolver.datatarget2label([data]))

        # append to title
        self._figure_append_title(title)

        df = convert_to_pandas(strat_clk, data, self._start, self._end)

        # configure colors
        colorup = convert_color(self._scheme.barup)
        colordown = convert_color(self._scheme.bardown)
        colorup_wick = convert_color(self._scheme.barup_wick)
        colordown_wick = convert_color(self._scheme.bardown_wick)
        colorup_outline = convert_color(self._scheme.barup_outline)
        colordown_outline = convert_color(self._scheme.bardown_outline)
        is_up = df.close > df.open

        self._add_to_cds(df.open, source_id + 'open')
        self._add_to_cds(df.high, source_id + 'high')
        self._add_to_cds(df.low, source_id + 'low')
        self._add_to_cds(df.close, source_id + 'close')
        self._add_to_cds([colorup if x else colordown for x in is_up],
                         source_id + 'colors_bars')
        self._add_to_cds(
            [colorup_wick if x else colordown_wick for x in is_up],
            source_id + 'colors_wicks')
        self._add_to_cds(
            [colorup_outline if x else colordown_outline for x in is_up],
            source_id + 'colors_outline')

        if self._scheme.style == 'line':
            if data.plotinfo.plotmaster is None:
                color = convert_color(self._scheme.loc)
            else:
                self._nextcolor(data.plotinfo.plotmaster)
                color = convert_color(self._color(data.plotinfo.plotmaster))

            renderer = self.figure.line('index',
                                        source_id + 'close',
                                        source=self._cds,
                                        line_color=color,
                                        legend=title)
            self._set_single_hover_renderer(renderer)

            self._hoverc.add_hovertip("Close", f"@{source_id}close", data)
        elif self._scheme.style == 'bar':
            self.figure.segment('index',
                                source_id + 'high',
                                'index',
                                source_id + 'low',
                                source=self._cds,
                                color=source_id + 'colors_wicks',
                                legend_label=title)
            renderer = self.figure.vbar(
                'index',
                get_bar_width(),
                source_id + 'open',
                source_id + 'close',
                source=self._cds,
                fill_color=source_id + 'colors_bars',
                line_color=source_id + 'colors_outline',
                legend_label=title,
            )

            self._set_single_hover_renderer(renderer)

            self._hoverc.add_hovertip(
                "Open", f"@{source_id}open{{{self._scheme.number_format}}}",
                data)
            self._hoverc.add_hovertip(
                "High", f"@{source_id}high{{{self._scheme.number_format}}}",
                data)
            self._hoverc.add_hovertip(
                "Low", f"@{source_id}low{{{self._scheme.number_format}}}",
                data)
            self._hoverc.add_hovertip(
                "Close", f"@{source_id}close{{{self._scheme.number_format}}}",
                data)
        else:
            raise Exception(f"Unsupported style '{self._scheme.style}'")

        adapt_yranges(self.figure.y_range, df.low, df.high)

        # check if we have to plot volume overlay
        if self._scheme.volume and self._scheme.voloverlay:
            self.plot_volume(data, strat_clk, self._scheme.voltrans, True)
Esempio n. 8
0
    def _init_figure(self):
        # plot height will be set later
        f = figure(tools=Figure._tools,
                   x_axis_type='linear',
                   aspect_ratio=self._scheme.plot_aspect_ratio)
        # TODO: backend webgl (output_backend="webgl") removed due to this bug:
        # https://github.com/bokeh/bokeh/issues/7568

        f.border_fill_color = convert_color(self._scheme.border_fill)

        f.xaxis.axis_line_color = convert_color(self._scheme.axis_line_color)
        f.yaxis.axis_line_color = convert_color(self._scheme.axis_line_color)
        f.xaxis.minor_tick_line_color = convert_color(
            self._scheme.tick_line_color)
        f.yaxis.minor_tick_line_color = convert_color(
            self._scheme.tick_line_color)
        f.xaxis.major_tick_line_color = convert_color(
            self._scheme.tick_line_color)
        f.yaxis.major_tick_line_color = convert_color(
            self._scheme.tick_line_color)

        f.xaxis.major_label_text_color = convert_color(
            self._scheme.axis_label_text_color)
        f.yaxis.major_label_text_color = convert_color(
            self._scheme.axis_label_text_color)

        f.xgrid.grid_line_color = convert_color(self._scheme.grid_line_color)
        f.ygrid.grid_line_color = convert_color(self._scheme.grid_line_color)
        f.title.text_color = convert_color(self._scheme.plot_title_text_color)

        f.left[0].formatter.use_scientific = False
        f.background_fill_color = convert_color(self._scheme.background_fill)

        # mechanism for proper date axis without gaps, thanks!
        # https://groups.google.com/a/continuum.io/forum/#!topic/bokeh/t3HkalO4TGA
        f.xaxis.formatter = FuncTickFormatter(args=dict(
            axis=f.xaxis[0],
            formatter=DatetimeTickFormatter(
                minutes=[self._scheme.axis_tickformat_minutes],
                hourmin=[self._scheme.axis_tickformat_hourmin],
                hours=[self._scheme.axis_tickformat_hours],
                days=[self._scheme.axis_tickformat_days],
                months=[self._scheme.axis_tickformat_months],
                years=[self._scheme.axis_tickformat_years],
            ),
            source=self._cds,
        ),
                                              code="""
            // We override this axis' formatter's `doFormat` method
            // with one that maps index ticks to dates. Some of those dates
            // are undefined (e.g. those whose ticks fall out of defined data
            // range) and we must filter out and account for those, otherwise
            // the formatter computes invalid visible span and returns some
            // labels as 'ERR'.
            // Note, after this assignment statement, on next plot redrawing,
            // our override `doFormat` will be called directly
            // -- FunctionTickFormatter.doFormat(), i.e. _this_ code, no longer
            // executes.  
                axis.formatter.doFormat = function (ticks) {
                    const dates = ticks.map(i => source.data.datetime[i]),
                          valid = t => t !== undefined,
                          labels = formatter.doFormat(dates.filter(valid));
                    let i = 0;
                    return dates.map(t => valid(t) ? labels[i++] : '');
                };
                
                // we do this manually only for the first time we are called
                const labels = axis.formatter.doFormat(ticks);
                return labels[index];
            """)

        ch = CrosshairTool(line_color=self._scheme.crosshair_line_color)
        f.tools.append(ch)

        h = HoverTool(tooltips=[
            ('Time', f'@datetime{{{self._scheme.hovertool_timeformat}}}')
        ],
                      mode="vline",
                      formatters={'datetime': 'datetime'})
        f.tools.append(h)

        self._hover = h
        self.figure = f
Esempio n. 9
0
 def _color(self, key: object = None):
     return convert_color(self._scheme.color(self._coloridx[key]))
Esempio n. 10
0
    def _plot_indicator_observer(self, obj: Union[bt.Indicator, bt.Observer]):
        pl = labelizer.label(obj)

        self._figure_append_title(pl)
        indlabel = obj.plotlabel()
        plotinfo = obj.plotinfo

        is_multiline = obj.size() > 1
        for lineidx in range(obj.size()):
            line = obj.lines[lineidx]
            source_id = get_source_id(line)
            linealias = obj.lines._getlinealias(lineidx)

            lineplotinfo = get_plotlineinfo(obj, lineidx)

            if lineplotinfo._get('_plotskip', False):
                continue

            method = lineplotinfo._get('_method', 'line')

            color = getattr(lineplotinfo, 'color', None)
            if color is None:
                if not lineplotinfo._get('_samecolor', False):
                    self._nextcolor()
                color = self._color()
            color = convert_color(color)

            kwglyphs = {'name': linealias}

            self._add_column(source_id, np.float64)

            # either all individual lines of are displayed in the legend or only the ind/obs as a whole
            label = indlabel
            if is_multiline and plotinfo.plotlinelabels:
                label += " " + (lineplotinfo._get("_name", "") or linealias)
            kwglyphs['legend_label'] = label

            marker = lineplotinfo._get('marker', None)
            if marker is not None:
                fnc_name, extra_kwglyphs = build_marker_call(marker, self.bfigure, source_id, color, lineplotinfo.markersize)
                kwglyphs.update(extra_kwglyphs)
                glyph_fnc = getattr(self.bfigure, fnc_name)
            elif method == "bar":
                kwglyphs['bottom'] = 0
                kwglyphs['line_color'] = 'black'
                kwglyphs['fill_color'] = color
                kwglyphs['width'] = get_bar_width()
                kwglyphs['top'] = source_id

                glyph_fnc = self.bfigure.vbar
            elif method == "line":
                kwglyphs['line_width'] = 1
                kwglyphs['color'] = color
                kwglyphs['y'] = source_id

                linestyle = getattr(lineplotinfo, "ls", None)
                if linestyle is not None:
                    kwglyphs['line_dash'] = convert_linestyle(linestyle)
                linewidth = getattr(lineplotinfo, "lw", None)
                if linewidth is not None:
                    kwglyphs['line_width'] = linewidth

                glyph_fnc = self.bfigure.line
            else:
                raise Exception(f"Unknown plotting method '{method}'")

            renderer = glyph_fnc("index", source=self._cds, **kwglyphs)

            # iterate again to generate area plot data
            for fattr, y1, y2, fcol, falpha, fop in get_ind_areas(obj, lineidx):
                self._add_column(y1, np.float64)

                falpha = falpha or self._scheme.fillalpha

                fcol = convert_color(fcol)

                self.bfigure.varea('index', source=self._cds, y1=y1, y2=y2, fill_color=fcol, fill_alpha=falpha)

            # make sure the regular y-axis only scales to the normal data (data + ind/obs) on 1st axis (not to e.g. volume data on 2nd axis)
            self.bfigure.y_range.renderers.append(renderer)

            # for markers add additional renderer so hover pops up for all of them
            if marker is None:
                self._set_single_hover_renderer(renderer)
            else:
                self._add_hover_renderer(renderer)

            hover_label_suffix = f" - {linealias}" if obj.size() > 1 else ""  # we need no suffix if there is just one line in the indicator anyway
            hover_label = indlabel + hover_label_suffix
            hover_data = f"@{source_id}{{{self._scheme.number_format}}}"
            self._hoverc.add_hovertip(hover_label, hover_data, obj)

        self._set_yticks(obj)
        self._plot_hlines(obj)
Esempio n. 11
0
    def _plot_indicator_observer(self, obj: Union[bt.Indicator, bt.Observer], master):
        # pl = plotobj2label(obj)
        pl = ""

        self._figure_append_title(pl)
        indlabel = obj.plotlabel()
        plotinfo = obj.plotinfo

        is_multiline = obj.size() > 1
        for lineidx in range(obj.size()):
            line = obj.lines[lineidx]
            source_id = FigureEnvelope._source_id(line)
            linealias = obj.lines._getlinealias(lineidx)

            lineplotinfo = getattr(obj.plotlines, '_%d' % lineidx, None)
            if not lineplotinfo:
                lineplotinfo = getattr(obj.plotlines, linealias, None)

            if not lineplotinfo:
                lineplotinfo = bt.AutoInfoClass()

            if lineplotinfo._get('_plotskip', False):
                continue

            marker = lineplotinfo._get("marker", None)
            method = lineplotinfo._get('_method', "line")

            color = getattr(lineplotinfo, "color", None)
            if color is None:
                if not lineplotinfo._get('_samecolor', False):
                    self._nextcolor()
                color = self._color()
            color = convert_color(color)

            kwglyphs = {'name': linealias}

            self._add_column(source_id, np.float64)

            # either all individual lines of are displayed in the legend or only the ind/obs as a whole
            label = indlabel
            if is_multiline and plotinfo.plotlinelabels:
                label += " " + (lineplotinfo._get("_name", "") or linealias)
            kwglyphs['legend_label'] = label

            if marker is not None:
                kwglyphs['size'] = lineplotinfo.markersize * 1.2
                kwglyphs['color'] = color
                kwglyphs['y'] = source_id

                if marker not in FigureEnvelope._mrk_fncs:
                    raise Exception(f"Sorry, unsupported marker: '{marker}'. Please report to GitHub.")
                glyph_fnc_name = FigureEnvelope._mrk_fncs[marker]
                glyph_fnc = getattr(self.figure, glyph_fnc_name)
            elif method == "bar":
                kwglyphs['bottom'] = 0
                kwglyphs['line_color'] = 'black'
                kwglyphs['fill_color'] = color
                kwglyphs['width'] = get_bar_width()
                kwglyphs['top'] = source_id

                glyph_fnc = self.figure.vbar
            elif method == "line":
                kwglyphs['line_width'] = 1
                kwglyphs['color'] = color
                kwglyphs['y'] = source_id

                linestyle = getattr(lineplotinfo, "ls", None)
                if linestyle is not None:
                    kwglyphs['line_dash'] = convert_linestyle(linestyle)

                glyph_fnc = self.figure.line
            else:
                raise Exception(f"Unknown plotting method '{method}'")

            renderer = glyph_fnc("index", source=self._cds, **kwglyphs)

            # make sure the regular y-axis only scales to the normal data (data + ind/obs) on 1st axis (not to e.g. volume data on 2nd axis)
            self.figure.y_range.renderers.append(renderer)

            # for markers add additional renderer so hover pops up for all of them
            if marker is None:
                self._set_single_hover_renderer(renderer)
            else:
                self._add_hover_renderer(renderer)

            hover_label_suffix = f" - {linealias}" if obj.size() > 1 else ""  # we need no suffix if there is just one line in the indicator anyway
            hover_label = indlabel + hover_label_suffix
            hover_data = f"@{source_id}{{{self._scheme.number_format}}}"
            # self._hoverc.add_hovertip(hover_label, hover_data, obj)

        self._set_yticks(obj)
        self._plot_hlines(obj)