Forcing minimum width in LabelSet

I am trying to force a minimum width for LabelSet, but have not been successful so far.
Because I want these labels to be at the left of the graph, they automatically get resized so that they contain just one word per line.
Once the html is generated, I could fix this by adding width: 100px to the style attribute like so:
<div class="bk-annotation-child" style="width: 100px; position: absolute; left: 196px; top: 199.263px; color: rgb(68, 68, 68); opacity: 1; font: 7pt helvetica; background-color: rgb(255, 255, 255);">Label that get resized</div>
But is there a way to do that in python?
I thought because render_mode is set to 'css' I should be able to modify the style directly from python? Can someone point to an example code which does that?

Many thanks!

Because I want these labels to be at the left of the graph, they automatically get resized so that they contain just one word per line.

Since LabelSet are used for annotating points on a graph, if you’d want to above, I guess x_offset would be your only option to force the x coordinates to be offset from their actual value. I’m not sure if updating the html would be a good option. Another option would be to maybe reduce font-size of label (not sure if this would solve your problem of 1 line/label).

x_offset seems to have an effect on the left of the div and not on its actual width. And font-size is already too small =)

I don’t really have a clear picture of what you are trying to accomplish, and without code I can’t try things out myself. A few annotated images or mock ups would go a long way.

Thanks for this and sorry for the late reply.
Here is an example:

    import numpy as np
    import pandas as pd
    from bokeh.plotting import figure, show, output_file
    from bokeh.sampledata.les_mis import data
    from bokeh.models.axes import LinearAxis,FixedTicker,BasicTicker
    from bokeh.models import Div,ColumnDataSource,FuncTickFormatter,Label,LabelSet
    from bokeh.models.glyphs import Segment
    from bokeh.io import output_notebook
    output_notebook()
    from itertools import product

    row_axis=list(reversed(["row"+str(i) for i in range(10)]))
    col_axis=list(["col"+str(i) for i in range(5)])
    df=pd.DataFrame(np.random.uniform(size=(10,5)),columns=col_axis,index=row_axis)
    values=list(df.values.flatten())
    data=dict(
        xname=[a[1] for a in product(row_axis,col_axis)],
        yname=[a[0] for a in product(row_axis,col_axis)],
        color=['#%02x%02x%02x' % (255,255-int(255*i),0) for i in values]
    )
    p = figure(title="Heatmap",
               x_axis_location="above",
               tools="save",
               y_range=row_axis,
               x_range=col_axis,
              )
    #p.rect('xname', 'yname',.95,.95,source=data,fill_color='black')
    p.plot_width = 300
    p.plot_height = 400
    p.rect(data['xname'], data['yname'], color=['#%02x%02x%02x' % (255,255-int(255*i),0) for i in values], width=1, height=1)
    caterogy_separators=[0,3,5,8,10]
    p.add_layout(LinearAxis(), 'right')
    p.yaxis[1].ticker = FixedTicker(ticks=caterogy_separators)
    #deleting text of separator ticks:
    p.yaxis[1].formatter = FuncTickFormatter(code='data={'+','.join([str(s)+":''" for s in caterogy_separators])+'}\nreturn data[tick]')
    for sep in caterogy_separators:
        glyph = Segment(x0=0, y0=sep, x1=5, y1=sep, line_color="black", line_width=2)
        p.add_glyph( glyph)
        
    category_centers=[(caterogy_separators[i]+caterogy_separators[i+1])/2 for i in range(len(caterogy_separators)-1)]

    category_data=ColumnDataSource(dict(
        x=[250]*4,
        y=[9,6.5,4,1.5],
    text=['my long data category 1',
        'my long data category 2',
        'my long data category 3',
        'my long data category 4']    
    ))
                     
    chapter_text = LabelSet(x='x',
        y='y',x_units='screen', y_units='data',level='overlay',
        text='text', render_mode='css',source=category_data,
        border_line_color=None, border_line_alpha=1.0,text_font_size='10pt',
        background_fill_color='white', background_fill_alpha=1.0, text_baseline = 'middle')                 
    p.add_layout(chapter_text)
    show(p)

And here is the current result. As you can see, the text of the categories is wrapped into many lines which is not what I want here.

BTW, do you know if bokeh makes it possible to have nested categories in a heatmap chart instead of a bar chart?

Many thanks

@ahassaine OK that makes it more clear what’s going on, but I am not sure what you want to happen otherwise. If you don’t want the labels to wrap, you will need to make much more space for them, there’s not getting around that. You can pass min_border_right=200 to make sure there is a 200 pixel buffer to the right of the central plot frame, but you will probably want to add a corresponding amount to plot_width as well.

Also, nested categorical coordinates can be used for heatmaps. You would supply the nested coordinates for the (x,y) coordinates of a Rect and set its width and height to 1.

Lastly as a gentle suggestion, please always apply code formatting to code in posts. You can do this by putting triple backtick ``` fences around code blocks.

1 Like

Many thanks!
Any idea on how to supply the “nested” axis please? The following seems to result in an error:

from bokeh.layouts import row
from bokeh.plotting import figure, show, output_file
from itertools import product

factors_x = ["A", "B", "C"]
#factors_y = [("Category1","1"), ("Category1","2"), ("Category1","3"),("Category2","X"), ("Category2","Y"), ("Category3","?")]
factors_y = [["Category1","1"], ["Category1","2"], ["Category1","3"],["Category2","X"], ["Category2","Y"], ["Category3","?"]]

x=[a[0] for a in product(factors_x,factors_y)]
y=[a[1] for a in product(factors_x,factors_y)]
values=np.random.uniform(size=(len(x),))
colors=['#%02x%02x%02x' % (255,255-int(255*i),0) for i in values]

hm = figure(title="Categorical Heatmap", tools="hover", toolbar_location=None,
            x_range=factors_x, y_range=factors_y)

hm.rect(x, y, color=colors, width=1, height=1)

show(hm)

@ahassaine To help keep the topics organized, can you make a new topic about this separate question? Thanks!

1 Like