Search code examples
python-3.xjupyter-notebookbokeh

Bokeh plot returned in function not rendering


I was writing a function to simplify my plotting, it dose not give any error yet when I call

show(plt)

on the return value nothing happens. I'm working in a Jupyter notebook. I've alredy made a call to :

output_notebook()

Here is the function code :

def plot_dist(x, h, title, xl="X axis", yl="Y axis", categories=None, width=0.5, bottom=0, color="#DC143C", xmlo=None, ymlo=None, xlo=-18, ylo=5):
    total = np.sum(h)
    source = ColumnDataSource(data={
        "x":x,
        "h":h,
        "percentages":[str(round((x*100)/total, 2)) + "%" for x in h]
    })
    plt = figure(
        title=title,
        x_axis_label=xl,
        y_axis_label=yl
    )
    plt.vbar(
        x="x",
        width=width,
        bottom=bottom,
        top="h",
        source=source,
        color=color
    )
    if xmlo is None:
        if categories is None:
            raise ValueError("If no categories are provided xaxis.major_label_overrides must be defined")
        plt.xaxis.major_label_overrides = {
            int(x):("(" + str(c.left) + "-" + str(c.right) + "]") for x,c in enumerate(categories)
        }
    else:
        plt.xaxis.major_label_overrides = xmlo

    if ymlo is None:
        plt.yaxis.major_label_overrides = { int(x):(str(int(x)/1000)+"k") for x in range(0, h.max(), math.ceil((h.max()/len(h))) )}
    else:
        plt.yaxis.major_label_overrides = ymlo

    labels = LabelSet(
        x=str(x), y=str(h), text="percentages", level="glyph",
        x_offset=xlo, y_offset=ylo, source=source, render_mode="canvas"
    )
    plt.add_layout(labels)

    return plt   

And this is how it is invoked :

X = [x for x in range(0, len(grps.index))]
H = grps.to_numpy()
plt = plot_dist(X, H, "Test", "xtest", "ytest", grps.index.categories)

X is just a list and grps is the result of a call to pandas' DataFrame.groupby

As I said it dose not give any error so I think the problem is with the ColumnDataSource object, I must be creating it wrong. Any help is appreciated, thanks!

Edit 1 : Apparently removing the following line solved the problem :

plt.add_layout(labels)

The plot now renders correclyt, yet I need to add the labels, any idea?

Edit 2 : Ok I've solved the problem, inspecting the web console when running the code the following error shows :

Error: attempted to retrieve property array for nonexistent field

The problem was in the following lines :

    labels = LabelSet(
        x=str(x), y=str(h), text="percentages", level="glyph",
        x_offset=xlo, y_offset=ylo, source=source, render_mode="canvas"
    )

In particular assignin x=str(x) and y=str(h). Changed it to simply x="x" and y="h" solved it.


Solution

  • The problem with the code is with the labels declaration :

    labels = LabelSet(
        x=str(x), y=str(h), text="percentages", level="glyph",
        x_offset=xlo, y_offset=ylo, source=source, render_mode="canvas"
    )   
    

    It was discovered by inspecting the browser's web console, which gave the following error :

    Error: attempted to retrieve property array for nonexistent field
    

    The parameters x and y must refer to the names in the ColumnDataSource object passed to the Glyph method used to draw on the plot.
    I was mistakenly passing str(x) and str(y) which, are the string representation of the content. I was mistakenly assuming it would refer to the string representation of the variable.
    To solve the problem is sufficient to pass as values to the x and y parameters of the LabelSet constructor the dictionary's keys used in the ColumnDataSource constructor :

    labels = LabelSet(
        x="x", y="h", text="percentages", level="glyph",
        x_offset=xlo, y_offset=ylo, source=source, render_mode="canvas"
    )   
    

    In addition if the ColumnDataSource was constructed from a DataFrame the strings will be either the columns names, the string "index", if any of the data used in the plot refer to the index and this has no explicit name, or the name of the index object.

    Thanks a lot to bigreddot for helping me with the problem and answer.