MichaelA
MichaelA

Reputation: 1986

Change the order of bars in a grouped barplot with hvplot/holoviews

I try to create a grouped bar plot but can't figure out how to influence the order of the barplot.

Given these example data:

import pandas as pd
import hvplot.pandas

df = pd.DataFrame({
    "lu": [200, 100, 10], 
    "le": [220, 80, 130], 
    "la": [60, 20, 15], 
    "group": [1, 2, 2],
})
df = df.groupby("group").sum()

I'd like to create a horizontal grouped bar plot showing the two groups 1 and 2 with all three columns. The columns should appear in the order of "le", "la" and "lu".

Naturally I'd try this with Hvplot:

df.hvplot.barh(x = "group", y = ["le", "la", "lu"])

With that I get the result below: grouped barplot in wrong order hvplot

Hvplot does not seem to care about the order I add the columns (calling df.hvplot.barh(x = "group", y = ["lu", "le", "la"]) doesn't change anything. Nor does Hvplot seem to care about the original order in the dataframe.

Are there any options to influence the order of the bars?

Upvotes: 5

Views: 2033

Answers (2)

Sander van den Oord
Sander van den Oord

Reputation: 12818

This has just been fixed in HoloViews 1.13.

You can sort your barplot just like you wanted:

df.hvplot.barh(x="group", y=["lu", "la", "le"])


As I write this, HoloViews 1.13 is not officially available yet, but you can install it through:

pip install git+https://github.com/holoviz/holoviews.git


If you want even more control over the order, you can use .redim.values() on your grouped_barplot:

group_specific_order = [2, 1]
variable_specific_order = ['lu', 'la', 'le']

# Note that group and Variable are the variable names of your dimensions here
# when you use this on a different grouped barchart, then please change to the 
# names of your own dimensions.
your_grouped_barplot.redim.values(
    group=group_specific_order, 
    Variable=variable_specific_order,
)

Upvotes: 4

Sander van den Oord
Sander van den Oord

Reputation: 12818

For normal bar charts, you can just order your data in the way you want it to be plotted.
However, for grouped bar charts you can't set the order yet.
But development of this feature is on the way and probably available in one of the next releases: https://github.com/holoviz/holoviews/issues/3799

Current solutions with Hvplot 0.5.2 and Holoviews 1.12:

1) If you're using a Bokeh backend, you can use keyword hooks:

from itertools import product

# define hook function to set order on bokeh plot
def set_grouped_barplot_order(plot, element):
    # define you categorical ordering in a list of tuples
    factors = product(['2', '1'], ['le', 'la', 'lu'])

    # since you're using horizontal bar set order on y_range.factors
    # if you would have had a normal (vertical) barplot you would use x_range.factors
    plot.state.y_range.factors = [*factors]

# create plot    
group = df.groupby("group").sum()
group_plot = group.hvplot.barh(
    x="group",
    y=["le", "la", "lu"],
    padding=0.05,
)

# apply your special ordering function
group_plot.opts(hooks=[set_grouped_barplot_order], backend='bokeh')

Hooks allow you to apply specific bokeh settings to your plots. You don't need hooks very often, but they are very handy in this case. Documentation:
http://holoviews.org/user_guide/Customizing_Plots.html#Plot-hooks
https://holoviews.org/FAQ.html


2) Another solution would be to convert your Holoviews plot to an actual Bokeh plot and then set the ordering:

from itertools import product
import holoviews as hv
from bokeh.plotting import show

# create plot
group = df.groupby("group").sum()
group_plot = group.hvplot.barh(
    x="group",
    y=["le", "la", "lu"],
    padding=0.05,
)

# render your holoviews plot as a bokeh plot
my_bokeh_plot = hv.render(group_plot, backend='bokeh')

# set the custom ordering on your bokeh plot
factors = product(['2', '1'], ['le', 'la', 'lu'])
my_bokeh_plot.y_range.factors = [*factors]

show(my_bokeh_plot)

Personally I prefer the first solution because it stays within Holoviews.

Resulting plot: customized categorical axes in grouped barcharts using keyword hooks

Upvotes: 3

Related Questions