forked from bokeh/bokeh
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add CustomJSTicker * Apply suggestions from code review Co-authored-by: Moritz Schreiber <[email protected]> --------- Co-authored-by: Moritz Schreiber <[email protected]>
- Loading branch information
Showing
8 changed files
with
342 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import type {FactorTickSpec} from "./categorical_ticker" | ||
import type {TickSpec} from "./ticker" | ||
import {Ticker} from "./ticker" | ||
import {FactorRange} from "../ranges/factor_range" | ||
import type {Range} from "../ranges/range" | ||
import type * as p from "core/properties" | ||
import type {Dict} from "core/types" | ||
import {keys, values} from "core/util/object" | ||
import {use_strict} from "core/util/string" | ||
|
||
type MajorCBData = { | ||
start: number | ||
end: number | ||
range: Range | ||
cross_loc: number | ||
} | ||
|
||
type MinorCBData = MajorCBData & { | ||
major_ticks: any[] | ||
} | ||
|
||
export namespace CustomJSTicker { | ||
export type Attrs = p.AttrsOf<Props> | ||
|
||
export type Props = Ticker.Props & { | ||
args: p.Property<Dict<unknown>> | ||
major_code: p.Property<string> | ||
minor_code: p.Property<string> | ||
} | ||
} | ||
|
||
export interface CustomJSTicker extends CustomJSTicker.Attrs {} | ||
|
||
export class CustomJSTicker extends Ticker { | ||
declare properties: CustomJSTicker.Props | ||
|
||
constructor(attrs?: Partial<CustomJSTicker.Attrs>) { | ||
super(attrs) | ||
} | ||
|
||
static { | ||
this.define<CustomJSTicker.Props>(({Unknown, Str, Dict}) => ({ | ||
args: [ Dict(Unknown), {} ], | ||
major_code: [ Str, "" ], | ||
minor_code: [ Str, "" ], | ||
})) | ||
} | ||
|
||
get names(): string[] { | ||
return keys(this.args) | ||
} | ||
|
||
get values(): unknown[] { | ||
return values(this.args) | ||
} | ||
|
||
get_ticks(start: number, end: number, range: Range, cross_loc: number): TickSpec<number> | FactorTickSpec { | ||
const major_cb_data = {start, end, range, cross_loc} | ||
const major_ticks = this.major_ticks(major_cb_data) | ||
|
||
// CustomJSTicker for categorical axes only support a single level of major ticks | ||
if (range instanceof FactorRange) { | ||
return {major: major_ticks, minor: [], tops: [], mids: []} | ||
} | ||
|
||
const minor_cb_data = {major_ticks, ...major_cb_data} | ||
const minor_ticks = this.minor_ticks(minor_cb_data) | ||
|
||
return { | ||
major: major_ticks, | ||
minor: minor_ticks, | ||
} | ||
} | ||
|
||
protected major_ticks(cb_data: MajorCBData): any[] { | ||
if (this.major_code == "") { | ||
return [] | ||
} | ||
const code = use_strict(this.major_code) | ||
const func = new Function("cb_data", ...this.names, code) | ||
return func(cb_data, ...this.values) | ||
} | ||
|
||
protected minor_ticks(cb_data: MinorCBData): any[] { | ||
if (this.minor_code == "") { | ||
return [] | ||
} | ||
const code = use_strict(this.minor_code) | ||
const func = new Function("cb_data", ...this.names, code) | ||
return func(cb_data, ...this.values) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import {expect} from "assertions" | ||
|
||
import {CustomJSTicker} from "@bokehjs/models/tickers/customjs_ticker" | ||
import type {FactorTickSpec} from "@bokehjs/models/tickers/categorical_ticker" | ||
import {FactorRange} from "@bokehjs/models/ranges/factor_range" | ||
import {Range1d} from "@bokehjs/models/ranges/range1d" | ||
|
||
describe("CustomJSTicker Model", () => { | ||
|
||
describe("Continuous get_ticks method", () => { | ||
it("should handle case with no major_code", () => { | ||
const ticker = new CustomJSTicker() | ||
const range = new Range1d({start: -1, end: 11}) | ||
const ticks = ticker.get_ticks(0, 10, range, NaN) | ||
expect(ticks.major).to.be.equal([]) | ||
expect(ticks.minor).to.be.equal([]) | ||
}) | ||
|
||
it("should return major_code result", () => { | ||
const ticker = new CustomJSTicker({major_code: "return [2,4,6,8]"}) | ||
const range = new Range1d({start: -1, end: 11}) | ||
const ticks = ticker.get_ticks(0, 10, range, NaN) | ||
expect(ticks.major).to.be.equal([2, 4, 6, 8]) | ||
expect(ticks.minor).to.be.equal([]) | ||
}) | ||
|
||
it("should pass start and end to major_code", () => { | ||
const ticker = new CustomJSTicker({major_code: "return [cb_data.start, cb_data.end]"}) | ||
const range = new Range1d({start: -1, end: 11}) | ||
const ticks = ticker.get_ticks(0, 10, range, NaN) | ||
expect(ticks.major).to.be.equal([0, 10]) | ||
expect(ticks.minor).to.be.equal([]) | ||
}) | ||
|
||
it("should pass range to major_code", () => { | ||
const ticker = new CustomJSTicker({major_code: "return [cb_data.range.start, cb_data.range.end]"}) | ||
const range = new Range1d({start: -1, end: 11}) | ||
const ticks = ticker.get_ticks(0, 10, range, NaN) | ||
expect(ticks.major).to.be.equal([-1, 11]) | ||
expect(ticks.minor).to.be.equal([]) | ||
}) | ||
|
||
it("should pass cross_loc to major_code", () => { | ||
const ticker = new CustomJSTicker({major_code: "return [cb_data.cross_loc]"}) | ||
const range = new Range1d({start: -1, end: 11}) | ||
const ticks = ticker.get_ticks(0, 10, range, 20) | ||
expect(ticks.major).to.be.equal([20]) | ||
expect(ticks.minor).to.be.equal([]) | ||
}) | ||
|
||
}) | ||
|
||
describe("Categorical get_ticks method", () => { | ||
|
||
it("should handle case with no major_code", () => { | ||
const ticker = new CustomJSTicker() | ||
const range = new FactorRange({factors: ["foo", "bar", "baz"]}) | ||
const ticks = ticker.get_ticks(0, 10, range, NaN) as FactorTickSpec | ||
expect(ticks.major).to.be.equal([]) | ||
expect(ticks.minor).to.be.equal([]) | ||
expect(ticks.mids).to.be.equal([]) | ||
expect(ticks.tops).to.be.equal([]) | ||
}) | ||
|
||
it("should handle case where range has factors", () => { | ||
const ticker = new CustomJSTicker({major_code: "return['foo', 'baz']"}) | ||
const range = new FactorRange({factors: ["foo", "bar", "baz"]}) | ||
const ticks = ticker.get_ticks(0, 3, range, NaN) as FactorTickSpec | ||
expect(ticks.major).to.be.equal(["foo", "baz"]) | ||
expect(ticks.minor).to.be.equal([]) | ||
expect(ticks.mids).to.be.equal([]) | ||
expect(ticks.tops).to.be.equal([]) | ||
}) | ||
|
||
it("should pass start and end to major_code", () => { | ||
const ticker = new CustomJSTicker({major_code: "return [cb_data.start.toString(), cb_data.end.toString()]"}) | ||
const range = new FactorRange({factors: ["foo", "bar", "baz"]}) | ||
const ticks = ticker.get_ticks(0, 10, range, NaN) as FactorTickSpec | ||
expect(ticks.major).to.be.equal(["0", "10"]) | ||
expect(ticks.minor).to.be.equal([]) | ||
expect(ticks.mids).to.be.equal([]) | ||
expect(ticks.tops).to.be.equal([]) | ||
}) | ||
|
||
it("should pass range to major_code", () => { | ||
const ticker = new CustomJSTicker({major_code: "return cb_data.range.factors"}) | ||
const range = new FactorRange({factors: ["foo", "bar", "baz"]}) | ||
const ticks = ticker.get_ticks(0, 10, range, NaN) as FactorTickSpec | ||
expect(ticks.major).to.be.equal(["foo", "bar", "baz"]) | ||
expect(ticks.minor).to.be.equal([]) | ||
expect(ticks.mids).to.be.equal([]) | ||
expect(ticks.tops).to.be.equal([]) | ||
}) | ||
|
||
it("should pass cross_loc to major_code", () => { | ||
const ticker = new CustomJSTicker({major_code: "return [cb_data.cross_loc.toString()]"}) | ||
const range = new FactorRange({factors: ["foo", "bar", "baz"]}) | ||
const ticks = ticker.get_ticks(0, 10, range, 20) as FactorTickSpec | ||
expect(ticks.major).to.be.equal(["20"]) | ||
expect(ticks.minor).to.be.equal([]) | ||
expect(ticks.mids).to.be.equal([]) | ||
expect(ticks.tops).to.be.equal([]) | ||
}) | ||
|
||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from bokeh.models import CustomJSTicker | ||
from bokeh.plotting import figure, show | ||
|
||
xticker = CustomJSTicker( | ||
# always three equally spaced ticks | ||
major_code=""" | ||
const {start, end} = cb_data.range | ||
const interval = (end-start) / 4 | ||
return [start + interval, start + 2*interval, start + 3*interval] | ||
""", | ||
# minor ticks in between the major ticks | ||
minor_code=""" | ||
const {start, end, major_ticks} = cb_data | ||
return [ | ||
(start+major_ticks[0])/2, | ||
(major_ticks[0]+major_ticks[1])/2, | ||
(major_ticks[1]+major_ticks[2])/2, | ||
(major_ticks[2]+end)/2, | ||
] | ||
""", | ||
) | ||
|
||
yticker = CustomJSTicker(major_code="return ['a', 'c', 'e', 'g']") | ||
|
||
p = figure(y_range=list("abcdefg")) | ||
p.scatter([1, 2, 3, 4, 5], ["a", "d", "b", "f", "c"], size=30) | ||
|
||
p.xaxis.ticker = xticker | ||
|
||
# keep the grid lines at all original tick locations | ||
p.ygrid.ticker = p.yaxis.ticker | ||
p.yaxis.ticker = yticker | ||
|
||
show(p) |
Oops, something went wrong.