我想用Python画马赛克 |带有自定义颜色和标签的 marimekko 图表。
以下代码可以正常工作
import plotly.graph_objects as go
year = ['2019', '2020', '2021', '2022']
fig1 = go. Figure()
fig1.add_trace(go.Bar(x=year, y=[20, 18, 14, 10], text=['20', '18', '14', '10'], name='brand 1'))
fig1.add_trace(go.Bar(x=year, y=[10, 15, 20, 22], text=['10', '15', '20', '22'], name='brand 2'))
fig1.add_trace(go.Bar(x=year, y=[6, 8, 10, 12], text=[ '6', '8', '10', '12'], name='brand 3'))
fig1.update_layout(barmode='stack')
fig1.write_image('test_1.png')
但是,我想根据通过 y 传递的数据对每年的数据进行排序。这意味着代码看起来像(我将省略排序,这不是这里的问题)。
fig2.add_trace(go.Bar(x=year, y=[20, 18, 20, 22], text=['20: brand 1', '18: brand 1', '20: brand 2', '22: brand 2']))
fig2.add_trace(go.Bar(x=year, y=[10, 15, 14, 12], text=['10: brand 2', '15: brand 2', '14: brand 1', '12: brand 3']))
fig2.add_trace(go.Bar(x=year, y=[ 6, 8, 10, 10], text=[ '6: brand 3', '8: brand 3', '10: brand 3', '10: brand 1']))
当然,我仍然希望每个品牌(而不是每个位置)使用相同的颜色,所以除了适当排序的数据外,我还需要为自定义标签文本(工作正常)和相应的自定义颜色传递两个数组(我不知道该怎么做)。
问题 1:如何将一组自定义颜色传递给每条迹线,以便每个品牌始终获得相同的颜色?有没有像
这样的fig1.add_trace(go.Bar(x=year, y=[20, 18, 14, 10], colors=...))
问题2:是否有另一种创建马赛克的选项|不基于 plotly 的具有不同 x 宽度的 marimekko 图表?
预期的代码是这样的
# the color map
the_brand_cmap = plt.get_cmap('seismic_r')
the_brand_norm = co.TwoSlopeNorm(vmin=-max_abs, vcenter=0, vmax=max_abs)
...
for i in years: # the loop is over the years, not over the brabnds
# some more code to sort df per year and to extract the brand names and colors
fig1.add_trace(go.Bar(
x=np.cumsum(xwidths) - xwidths,
y=ysizes_norm,
width=xwidths,
marker_color=the_brand_cmap(the_brand_norm(colors)), # the colors for each year
text=brand_name)
预期的结果是
我根据 reference 中的示例使用您的数据创建了一个 Marimekko 图。为年份的组成添加一个新列。同样,创建一个包含年份总数的列宽。为了指定每个品牌的颜色,创建品牌和颜色的字典,并在创建带有品牌提取数据的堆叠图时指定。
import plotly.graph_objects as go
import numpy as np
import pandas as pd
year = ['2019', '2020', '2021', '2022']
data = {'brand 1': [20, 18, 14, 10],
'brand 2': [10, 15, 20, 22],
'brand 3': [6, 8, 10, 12]
}
df = pd.DataFrame.from_dict(data)
df = df.T
df.columns = year
for c in df.columns:
df[c+'_%'] = df[c].apply(lambda x: (x / df.loc[:,c].sum()) * 100)
widths = np.array([sum(df['2019']), sum(df['2020']), sum(df['2021']), sum(df['2022'])])
marker_colors = {'brand 1': 'darkblue', 'brand 2': 'darkgreen', 'brand 3': 'crimson'}
fig1 = go.Figure()
for idx in df.index:
dff = df.filter(items=[idx], axis=0)
fig1.add_trace(go.Bar(
x=np.cumsum(widths) - widths,
y=dff[dff.columns[4:]].values[0],
width=widths,
marker_color=marker_colors[idx],
text=['{:.2f}%'.format(x) for x in dff[dff.columns[4:]].values[0]],
name=idx
)
)
fig1.update_xaxes(
tickvals=np.cumsum(widths)-widths,
ticktext= ["%s<br>%d" % (l, w) for l, w in zip(year, widths)]
)
fig1.update_xaxes(range=[0, widths])
fig1.update_yaxes(range=[0, 100])
fig1.update_layout(barmode='stack')
#fig1.write_image('test_1.png')
fig1.show()