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

烂漫一生 提交于 2021-01-24 07:03:21

问题


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:

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?


回答1:


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,
)



回答2:


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:



来源:https://stackoverflow.com/questions/59735494/change-the-order-of-bars-in-a-grouped-barplot-with-hvplot-holoviews

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!