I want to ensure a couple of specific ticks are visible on the X axis on top of the default ticks of the plot. To this end I found in the documentation FixedTicker which allows me to specify exact values along the X axis where ticks should reside. However, if I set:
p.xaxis.ticker = FixedTicker(ticks=[-1,1])
...this replaces all tickers along the X axis with just the two I specified (one at -1 and one at 1). I tried "extending" the existing ticker using CompositeTicker:
# compose whatever is there by default, adding the fixed points:
p.xaxis.ticker = CompositeTicker(tickers=[p.xaxis.ticker, FixedTicker(ticks=[-1,1])])
This again does not seem to do what I need. The result is the same (I get an X axis with just two ticks at positions -1 and 1) as for using the plain FixedTicker. It's as if there is no 'composition' going on. Reading the documentation it does seem that CompositeTicker is more than a "sum of individual tickers" because I read:
A list of Ticker objects to combine at different scales in order to generate tick values. The supplied tickers should be in order. Specifically, if S comes before T, then it should be the case that:
S.get_max_interval() < T.get_min_interval()
How would one go about having a default "linear" ticker across whatever data range is in the column data source, but just "highlighting" a couple of point (which may or may not be present in the default ticker).
A simple use case would be for example plotting a quadratic function and highlighting its roots on the X axis.
Well, it is possible, but it is not currently built-in. And "ticker" is the right concept, as a ticker is what decides what tick locations should be. However, as you have learned the CompositeTicker
is for picking one "best" ticker (out of many possible) for the current scale (i.e pick nice days on a scale of months, pick nice months on a scale of years). To "join" two tickers like you want would require creating a custom extension, which unfortunately at present involves a lot of boilerplate. Here is a reference version that works with Bokeh 1.4.0 1
from bokeh.core.properties import Float, List
from bokeh.models import BasicTicker
from bokeh.plotting import figure, show
from bokeh.util.compiler import TypeScript
TS_CODE = """
import * as p from "core/properties"
import {TickSpec} from "models/tickers/ticker"
import {BasicTicker} from "models/tickers/basic_ticker"
export namespace MyTicker {
export type Attrs = p.AttrsOf<Props>
export type Props = BasicTicker.Props & {
extra_ticks: p.Property<Array<number>>
}
}
export interface MyTicker extends MyTicker.Attrs {}
export class MyTicker extends BasicTicker {
properties: MyTicker.Props
constructor(attrs?: Partial<MyTicker.Attrs>) {
super(attrs)
}
get_ticks_no_defaults(data_low: number, data_high: number, cross_loc: any, desired_n_ticks: number): TickSpec<number> {
const ticks = super.get_ticks_no_defaults(data_low, data_high, cross_loc, desired_n_ticks)
for (var i=0; i<this.extra_ticks.length; i++) {
const et = this.extra_ticks[i]
if (et >= data_low && et <= data_high)
ticks.major.push(et)
}
return ticks
}
static init_MyTicker(): void {
this.define<MyTicker.Props>({
extra_ticks: [ p.Any ],
})
}
}
"""
class MyTicker(BasicTicker):
__implementation__ = TypeScript(TS_CODE)
extra_ticks = List(Float)
p = figure()
p.circle([1, 2, 3, 4, 6], [5, 7, 3, 2, 4], size=20)
p.xaxis.ticker = MyTicker(extra_ticks=[3.65])
p.xaxis.major_label_orientation = 1.2
show(p)
Note that I have rotated the ticks as well since the extra tick does not participate in the calculations to keep ticks "spread apart" so they may overlap otherwise.
A "joined" ticker might be a reasonable feature request, as well as a nice task for a new contributor. Please feel free to open a GitHub issue to suggest.
1 Please note that BokehJS is still under very active development. Although its API is now reaching a level of stability, we do not yet make guarantees about custom extension compatibility version to version.