New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
allow users to specify explicit tick labels #1671
Comments
One idea would be to add mapping ( So use might look something like:
Random observations:
@bokeh/dev thoughts? |
I can see multiple angles on this. There is an argument to be made that it should be on the Ticker, as well as the Formatter. However, the most important thing IMO is that the split between ticker vs. formatter is an architectural one in our object model, and, under normal circumstances, it's not a distinction that we should burden the user with understanding. We need to consider the use cases when an end user is most likely to want to specify these things:
What would the ideal spelling look like for each of these? Are there other common use cases I'm missing here? |
@bryevdv Is there a way to do this yet? |
Currently you could do this with a custom |
@bryevdv Thanks. That is currently the way I'm doing it in my code as well. |
Here's an example of doing exactly that (using a FixedTicker and FuncTickFormatter together to set explicit tick labels at specific locations). I think it's the best method for doing this: from bokeh.plotting import figure, show
from bokeh.models import ColorBar, LinearColorMapper, Plot, Range1d, LinearAxis, FixedTicker, FuncTickFormatter
color_mapper = LinearColorMapper(palette="Spectral6", low=0, high=60)
ticker = FixedTicker(ticks=[5,15,25,35,45,55])
formatter = FuncTickFormatter(code="""
data = {5: '0-10', 15: '10-20', 25: '20-30', 35: '30-40', 45: '40-50', 55: '50+'}
return data[tick]
""")
cbar = ColorBar(color_mapper=color_mapper, ticker=ticker, formatter=formatter,
major_tick_out=0, major_tick_in=0, major_label_text_align='left',
major_label_text_font_size='10pt', label_standoff=2)
p = Plot(x_range=Range1d(0,1), y_range=Range1d(0,1), width=500, height=500, toolbar_location=None)
p.add_layout(LinearAxis(), 'left')
p.add_layout(LinearAxis(), 'below')
p.add_layout(cbar)
show(p) |
@canavandl Thank you for the idea. Currently I am using class FixedTickFormatter(TickFormatter):
"""
Class used to allow custom axis tick labels on a bokeh chart
Extends bokeh.model.formatters.TickFormatte
"""
JS_CODE = """
_ = require "underscore"
Model = require "model"
p = require "core/properties"
class FixedTickFormatter extends Model
type: 'FixedTickFormatter'
doFormat: (ticks) ->
labels = @get("labels")
return (labels[tick] ? "" for tick in ticks)
@define {
labels: [ p.Any ]
}
module.exports =
Model: FixedTickFormatter
"""
labels = Dict(Int, String, help="""
A mapping of integer ticks values to their labels.
""")
__implementation__ = JS_CODE |
@Rubyj I was curious about this, so I put together a complete example. Please note that you're custom FixedTickFormatter needed to be changed quite a lot for it to work on master (and hence the next release) from bokeh.plotting import show
from bokeh.properties import Dict, Int, String
from bokeh.models import (
ColorBar,
LinearColorMapper,
Plot,
Range1d,
LinearAxis,
FixedTicker,
TickFormatter,
)
from bokeh.util.compiler import CoffeeScript
class FixedTickFormatter(TickFormatter):
"""
Class used to allow custom axis tick labels on a bokeh chart
Extends bokeh.model.formatters.TickFormatter
"""
COFFEESCRIPT = """
import {Model} from "model"
import * as p from "core/properties"
export class FixedTickFormatter extends Model
type: 'FixedTickFormatter'
doFormat: (ticks) ->
labels = @get("labels")
return (labels[tick] ? "" for tick in ticks)
@define {
labels: [ p.Any ]
}
"""
labels = Dict(Int, String, help="""
A mapping of integer ticks values to their labels.
""")
__implementation__ = CoffeeScript(COFFEESCRIPT)
color_mapper = LinearColorMapper(palette="Spectral6", low=0, high=60)
ticker = FixedTicker(ticks=[5,15,25,35,45,55])
formatter = FixedTickFormatter(labels={5: '0-10', 15: '10-20', 25: '20-30', 35: '30-40', 45: '40-50', 55: '50+'})
cbar = ColorBar(color_mapper=color_mapper, ticker=ticker, formatter=formatter,
major_tick_out=0, major_tick_in=0, major_label_text_align='left',
major_label_text_font_size='10pt', label_standoff=2)
p = Plot(x_range=Range1d(0,1), y_range=Range1d(0,1), width=500, height=500, toolbar_location=None)
p.add_layout(LinearAxis(), 'left')
p.add_layout(LinearAxis(), 'below')
p.add_layout(cbar)
show(p) @bryevdv - we're going to need some major migration notes about the new export stuff, then new import stuff, and the compilation stuff for folks |
@birdsarah awesome! Thank you for this :) |
Actually |
Hi, I arrived here via Stack Overflow.
The clue seems to be in the comment above :)
Has anyone got any suggestion what the best way to go about this is now? I guess there's some different way to register the JS code? |
@hodgson-neil I am using the below code which works fine in my application running the latest version of bokeh
|
@Rubyj Thanks, my mistake. It is indeed working fine on my use case! Thanks. |
@canavandl How can you do the same for the x-axis in a scatter plot? Thanks. |
@pzwang I guess my use case is either the first or the third. I'm generating a Manhattan plot, which plots millions of points with the probability of association between phenotypes and genotypes at millions of base pair locations in the genome: Preferably I would also like for the position on a given chromosome to be shown, when I zoom in, but that would probably require a secondary x-axis. I'm super excited about Bokeh! Right now I have to semi naively down-sample my data to less than 100k data points, because the hover tool doesn't work with datashader. Tomorrow I'll look into doing what I think you refer to as call backs with Bokeh serve, so I can do Manhattan plots for various phenotypic traits. Awesome! Excited! |
@tommycarstensen , I haven't tested it, but the below should work: from bokeh.plotting import show
from bokeh.properties import Dict, Int, String
from bokeh.models import (
Plot,
Range1d,
LinearAxis,
FixedTicker,
TickFormatter,
)
from bokeh.util.compiler import CoffeeScript
class FixedTickFormatter(TickFormatter):
"""
Class used to allow custom axis tick labels on a bokeh chart
Extends bokeh.model.formatters.TickFormatter
"""
COFFEESCRIPT = """
import {Model} from "model"
import * as p from "core/properties"
export class FixedTickFormatter extends Model
type: 'FixedTickFormatter'
doFormat: (ticks) ->
labels = @get("labels")
return (labels[tick] ? "" for tick in ticks)
@define {
labels: [ p.Any ]
}
"""
labels = Dict(Int, String, help="""
A mapping of integer ticks values to their labels.
""")
__implementation__ = CoffeeScript(COFFEESCRIPT)
ticker = FixedTicker(ticks=[5,15,25,35,45,55])
formatter = FixedTickFormatter(labels={5: '0-10', 15: '10-20', 25: '20-30', 35: '30-40', 45: '40-50', 55: '50+'})
x_axis = LinearAxis(ticker=ticker, formatter=formatter)
p = Plot(x_range=Range1d(0,60))
p.add_layout(x_axis, 'below')
show(p) |
With the latest GitHub master version of HoloViews, you can now easily overlay a hover layer on a datashader plot, as shown here: holoviz/holoviews#1223 Not sure if that helps your use case, but if it doesn't, please file an issue about that on the datashader site. |
Ok I'd like to do something for this for
Then internally axis models would pass this on to their tick formatters on init (or when a formatter is replaced). All the built in formatters would refer to this list of overrides (and extension formatters could as well). Users would only need to worry about supplying this mapping on an axis, which is a bit more common/approachable than tickers and formatter. This would let specific values be overridden, however they occur. If only these ticks are desired, use of
works as a shorthand for setting up a fixed ticker. Does this sound acceptable to everyone? If so I would plan on working on this after the refactor of categorical values. |
+1, I think this would be super! |
@hodgson-neil @tommycarstensen @Rubyj PR #6225 should solve this issue in the manner described above, if you have the opportunity to build and test it, it would be helpful and appreciated. |
FixedTicker
allows users to specify fixed tick locations, but also need to allow users to specify explicit tick labelsThe text was updated successfully, but these errors were encountered: