0

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.

7
  • Is this in classic notebook, or Jupyter Lab? If the latter, do you have the required Jupyter Lab extension installed? If not, what versions of everything, what OS, what browser? Does output_notebook display a successful loaded message? Commented Mar 27, 2020 at 18:38
  • I'm on a classic notebook, plotting works fine without the function, Ubuntu 18.04, Firefox 74 64bit, and yes it dose display the successfully loaded message Commented Mar 27, 2020 at 18:43
  • @bigreddot forgot to tag you Commented Mar 27, 2020 at 18:49
  • What bokeh version? Can you run example notebooks from the repo (at the appropriate release tag)? Commented Mar 27, 2020 at 21:49
  • @bigreddot I've solved the problem, the solution is in edit 2!It was a mistake on my part Commented Mar 28, 2020 at 9:43

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.