如何调整我的 Plotly 条高度并仅显示条的边缘(在子图中)?
Posted
技术标签:
【中文标题】如何调整我的 Plotly 条高度并仅显示条的边缘(在子图中)?【英文标题】:How do I resize my Plotly bar height and show only bar’s edge (in subplot)? 【发布时间】:2021-07-28 21:12:24 【问题描述】:这是我第一次涉足 Plotly。与 matplotlib 和散景相比,我喜欢它的易用性。然而,我被困在一些关于如何美化我的情节的基本问题上。首先,这是下面的代码(功能齐全,只需复制和粘贴!):
import plotly.express as px
from plotly.subplots import make_subplots
import plotly as py
import pandas as pd
from plotly import tools
d = 'Mkt_cd': ['Mkt1','Mkt2','Mkt3','Mkt4','Mkt5','Mkt1','Mkt2','Mkt3','Mkt4','Mkt5'],
'Category': ['Apple','Orange','Grape','Mango','Orange','Mango','Apple','Grape','Apple','Orange'],
'CategoryKey': ['Mkt1Apple','Mkt2Orange','Mkt3Grape','Mkt4Mango','Mkt5Orange','Mkt1Mango','Mkt2Apple','Mkt3Grape','Mkt4Apple','Mkt5Orange'],
'Current': [15,9,20,10,20,8,10,21,18,14],
'Goal': [50,35,21,44,20,24,14,29,28,19]
dataset = pd.DataFrame(d)
grouped = dataset.groupby('Category', as_index=False).sum()
data = grouped.to_dict(orient='list')
v_cat = grouped['Category'].tolist()
v_current = grouped['Current']
v_goal = grouped['Goal']
fig1 = px.bar(dataset, x = v_current, y = v_cat, orientation = 'h',
color_discrete_sequence = ["#ff0000"],height=10)
fig2 = px.bar(dataset, x = v_goal, y = v_cat, orientation = 'h',height=15)
trace1 = fig1['data'][0]
trace2 = fig2['data'][0]
fig = make_subplots(rows = 1, cols = 1, shared_xaxes=True, shared_yaxes=True)
fig.add_trace(trace2, 1, 1)
fig.add_trace(trace1, 1, 1)
fig.update_layout(barmode = 'overlay')
fig.show()
这是输出:
问题1:如何使v_current(红色条所示)的宽度变小?如中,它的高度应该更小,因为这是一个水平条。我将 trace1 的高度添加为 10,将 trace2 的高度添加为 15,但它们仍然显示在相同的高度。
问题2:有没有办法让 v_goal(以蓝色条显示)只显示它的右边缘,而不是填充条?像这样的东西:
如果您注意到,我还在每个类别下添加了一行。有没有一种快速的方法来添加它?不是破坏交易,只是奖金。我正在尝试做的其他事情是添加动画等,但那是其他时间!
提前感谢您的回答!
【问题讨论】:
【参考方案1】:运行 plotly.express
将返回一个 plotly.graph_objs._figure.Figure
对象。 plotly.graph_objects
与 go.Figure()
一起运行也是如此,例如,go.Bar()
。所以在使用 plotly express 构建图形后,您可以通过直接对图形的引用添加线条或轨迹,例如:
fig['data'][0].width = 0.4
这正是您设置条形宽度所需的。您可以轻松地将其与 plotly express 结合使用:
代码 1
fig = px.bar(grouped, y='Category', x = ['Current'],
orientation = 'h', barmode='overlay', opacity = 1,
color_discrete_sequence = px.colors.qualitative.Plotly[1:])
fig['data'][0].width = 0.4
情节 1
为了获得指示目标级别的条形或形状,您可以使用 DerekO 描述的方法,也可以使用:
for i, g in enumerate(grouped.Goal):
fig.add_shape(type="rect",
x0=g+1, y0=grouped.Category[i], x1=g, y1=grouped.Category[i],
line=dict(color='#636EFA', width = 28))
完整代码:
import plotly.express as px
from plotly.subplots import make_subplots
import plotly as py
import pandas as pd
from plotly import tools
d = 'Mkt_cd': ['Mkt1','Mkt2','Mkt3','Mkt4','Mkt5','Mkt1','Mkt2','Mkt3','Mkt4','Mkt5'],
'Category': ['Apple','Orange','Grape','Mango','Orange','Mango','Apple','Grape','Apple','Orange'],
'CategoryKey': ['Mkt1Apple','Mkt2Orange','Mkt3Grape','Mkt4Mango','Mkt5Orange','Mkt1Mango','Mkt2Apple','Mkt3Grape','Mkt4Apple','Mkt5Orange'],
'Current': [15,9,20,10,20,8,10,21,18,14],
'Goal': [50,35,21,44,20,24,14,29,28,19]
dataset = pd.DataFrame(d)
grouped = dataset.groupby('Category', as_index=False).sum()
fig = px.bar(grouped, y='Category', x = ['Current'],
orientation = 'h', barmode='overlay', opacity = 1,
color_discrete_sequence = px.colors.qualitative.Plotly[1:])
fig['data'][0].width = 0.4
fig['data'][0].marker.line.width = 0
for i, g in enumerate(grouped.Goal):
fig.add_shape(type="rect",
x0=g+1, y0=grouped.Category[i], x1=g, y1=grouped.Category[i],
line=dict(color='#636EFA', width = 28))
f = fig.full_figure_for_development(warn=False)
fig.show()
【讨论】:
谢谢!但是当我运行它时它要求我安装 Kaleido。想知道为什么,因为你甚至没有导入它 @rustynail 我相信这与不导入 javascript 的原因相同。 Plotly 两者都使用,但您不需要在 python 脚本中导入它们。 您能解释一下“x0=g+1, y0=grouped.Category[i], x1=g, y1=grouped.Category[i]” 部分吗?我一直在看网站,但我更困惑。为什么是g+1?另外,您是如何将 color_discrete_sequence 定义为我在示例中所显示的?如果我想为不同的酒吧选择不同的颜色,我能做到吗?感谢您的回答! @rustynail 不客气!我很乐意在聊天中解释所有细节。我现在没有时间,所以我稍后会发送邀请。如果我忘记了,请提醒我。 @rustynail 如果你愿意的话,我现在有时间chat!【参考方案2】:您可以使用Plotly Express
,然后像@vestland 描述的那样直接访问图形对象,但我个人更喜欢使用graph_objects
来在一个地方进行所有更改。
我还要指出,由于您将条形堆叠在一个图表中,因此您不需要子图。您可以使用fig = go.Figure()
创建一个graph_object
,并添加跟踪以获得堆叠条,类似于您已经做过的。
对于问题1,如果你使用go.Bar()
,你可以传递一个宽度参数。但是,这是以位置轴为单位的,并且由于您的 y 轴是分类的,因此 width=1 将填充整个类别,因此我为红色条选择了 width=0.25,为红色条选择了 width=0.3(稍大)蓝条,因为这似乎是您的意图。
对于问题 2,唯一想到的是 hack。将条分成两部分(一个高度 = 原始高度 - 1),并将其不透明度设置为 0,使其透明。然后将高度为 1 的条放在透明条的顶部。
如果您不希望跟踪显示在图例中,您可以通过将showlegend=False
传递给fig.add_trace
来为每个条单独设置,或者通过将showlegend=False
传递给@987654331 来完全隐藏图例@方法。
import plotly.express as px
import plotly.graph_objects as go
# from plotly.subplots import make_subplots
import plotly as py
import pandas as pd
from plotly import tools
d = 'Mkt_cd': ['Mkt1','Mkt2','Mkt3','Mkt4','Mkt5','Mkt1','Mkt2','Mkt3','Mkt4','Mkt5'],
'Category': ['Apple','Orange','Grape','Mango','Orange','Mango','Apple','Grape','Apple','Orange'],
'CategoryKey': ['Mkt1Apple','Mkt2Orange','Mkt3Grape','Mkt4Mango','Mkt5Orange','Mkt1Mango','Mkt2Apple','Mkt3Grape','Mkt4Apple','Mkt5Orange'],
'Current': [15,9,20,10,20,8,10,21,18,14],
'Goal': [50,35,21,44,20,24,14,29,28,19]
dataset = pd.DataFrame(d)
grouped = dataset.groupby('Category', as_index=False).sum()
data = grouped.to_dict(orient='list')
v_cat = grouped['Category'].tolist()
v_current = grouped['Current']
v_goal = grouped['Goal']
fig = go.Figure()
## you have a categorical plot and the units for width are in position axis units
## therefore width = 1 will take up the entire allotted space
## a width value of less than 1 will be the fraction of the allotted space
fig.add_trace(go.Bar(
x=v_current,
y=v_cat,
marker_color="#ff0000",
orientation='h',
width=0.25
))
## you can show the right edge of the bar by splitting it into two bars
## with the majority of the bar being transparent (opacity set to 0)
fig.add_trace(go.Bar(
x=v_goal-1,
y=v_cat,
marker_color="#ffffff",
opacity=0,
orientation='h',
width=0.30,
))
fig.add_trace(go.Bar(
x=[1]*len(v_cat),
y=v_cat,
marker_color="#1f77b4",
orientation='h',
width=0.30,
))
fig.update_layout(barmode='relative')
fig.show()
【讨论】:
这是一个不错的方法!但只有一件事; Plotly express not 为了便于编码而牺牲了可调整性。我会自己写一个答案,告诉你为什么你的陈述不完全正确。 @vestland 确定!既然您提到了它,由于 Plotly express 在内部创建了 graph_objects,您可能仍然可以访问任何图形所需的所有参数?我想我的观点是我认为 plotly.graph_objects 比 Plotly express + 访问 fig.layout 更“干净”,但这是一个品味问题。 但是我知道使用 Plotly express 并不意味着你不能访问必要的参数——我会修改我的答案,使其在事实上是正确的 谢谢@derekO!如果我想在单个类别下添加 x 轴,保留子图是否有意义(暗指我的奖励问题:)) 非常感谢!最后我最终使用了 vestland 的代码 :) 但想再次感谢您的帮助,它为我回答了很多问题。以上是关于如何调整我的 Plotly 条高度并仅显示条的边缘(在子图中)?的主要内容,如果未能解决你的问题,请参考以下文章