简体   繁体   English

带有可变宽度条形的 Altair 条形图?

[英]Altair bar chart with bars of variable width?

I'm trying to use Altair in Python to make a bar chart where the bars have varying width depending on the data in a column of the source dataframe.我正在尝试在 Python 中使用 Altair 来制作条形图,其中条形图的宽度取决于源数据框列中的数据。 The ultimate goal is to get a chart like this one:最终目标是获得这样的图表:

带有可变宽度条形的条形图

The height of the bars corresponds to a marginal-cost of each energy-technology (given as a column in the source dataframe).条形的高度对应于每种能源技术的边际成本(作为源数据框中的一列给出)。 The bar width corresponds to the capacity of each energy-technology (also given as a columns in the source dataframe).条形宽度对应于每种能源技术的容量(也在源数据框中以列的形式给出)。 Colors are ordinal data also from the source dataframe.颜色也是来自源数据帧的有序数据。 The bars are sorted in increasing order of marginal cost.条形按边际成本的升序排列。 (A plot like this is called a "generation stack" in the energy industry). (这样的情节在能源行业被称为“发电栈”)。 This is easy to achieve in matplotlib like shown in the code below:这在 matplotlib 中很容易实现,如下面的代码所示:

import matplotlib.pyplot as plt 

# Make fake dataset
height = [3, 12, 5, 18, 45]
bars = ('A', 'B', 'C', 'D', 'E')

# Choose the width of each bar and their positions
width = [0.1,0.2,3,1.5,0.3]
y_pos = [0,0.3,2,4.5,5.5]

# Make the plot
plt.bar(y_pos, height, width=width)
plt.xticks(y_pos, bars)
plt.show()

(code from https://python-graph-gallery.com/5-control-width-and-space-in-barplots/ ) (代码来自https://python-graph-gallery.com/5-control-width-and-space-in-barplots/

But is there a way to do this with Altair?但是有没有办法用 Altair 做到这一点? I would want to do this with Altair so I can still get the other great features of Altair like a tooltip, selectors/bindings as I have lots of other data I want to show alongside the bar-chart.我想用 Altair 来做到这一点,这样我仍然可以获得 Altair 的其他强大功能,如工具提示、选择器/绑定,因为我有很多其他数据要与条形图一起显示。

First 20 rows of my source data looks like this:我的源数据的前 20 行如下所示:

在此处输入图片说明

(does not match exactly the chart shown above). (与上面显示的图表不完全匹配)。

In Altair, the way to do this would be to use the rect mark and construct your bars explicitly.在 Altair 中,这样做的方法是使用rect标记并明确构建您的条形。 Here is an example that mimics your data:这是一个模仿您的数据的示例:

import altair as alt
import pandas as pd
import numpy as np

np.random.seed(0)

df = pd.DataFrame({
    'MarginalCost': 100 * np.random.rand(30),
    'Capacity': 10 * np.random.rand(30),
    'Technology': np.random.choice(['SOLAR', 'THERMAL', 'WIND', 'GAS'], 30)
})

df = df.sort_values('MarginalCost')
df['x1'] = df['Capacity'].cumsum()
df['x0'] = df['x1'].shift(fill_value=0)

alt.Chart(df).mark_rect().encode(
    x=alt.X('x0:Q', title='Capacity'),
    x2='x1',
    y=alt.Y('MarginalCost:Q', title='Marginal Cost'),
    color='Technology:N',
    tooltip=["Technology", "Capacity", "MarginalCost"]
)

在此处输入图片说明

To get the same result without preprocessing of the data, you can use Altair's transform syntax:要在不预处理数据的情况下获得相同的结果,您可以使用 Altair 的转换语法:

df = pd.DataFrame({
    'MarginalCost': 100 * np.random.rand(30),
    'Capacity': 10 * np.random.rand(30),
    'Technology': np.random.choice(['SOLAR', 'THERMAL', 'WIND', 'GAS'], 30)
})

alt.Chart(df).transform_window(
    x1='sum(Capacity)',
    sort=[alt.SortField('MarginalCost')]
).transform_calculate(
    x0='datum.x1 - datum.Capacity'
).mark_rect().encode(
    x=alt.X('x0:Q', title='Capacity'),
    x2='x1',
    y=alt.Y('MarginalCost:Q', title='Marginal Cost'),
    color='Technology:N',
    tooltip=["Technology", "Capacity", "MarginalCost"]
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM