如何调整 Plotly 条形高度并仅显示条形边缘(在子图中)?
How do I resize my Plotly bar height and show only bar’s edge (in subplot)?
这是我第一次涉足 Plotly。与 matplotlib 和 bokeh 相比,我喜欢它的易用性。但是,我在如何美化我的情节方面遇到了一些基本问题。首先,这是下面的代码(功能齐全,只需复制和粘贴!):
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(显示在蓝色条中)只显示它的右边缘,而不是填充条?是这样的:
如果您注意到了,我还在每个类别下添加了一行。有没有快速的方法来添加这个?不是交易破坏者,只是奖金。我正在尝试做的其他事情是添加动画等,但那是其他时间!
提前感谢您的回答!
您可以使用 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
为每个柱单独设置此项,或者通过将 fig.add_trace
完全隐藏图例=16=] 到 fig.update_layout
方法。
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
将 return 一个 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()
这是我第一次涉足 Plotly。与 matplotlib 和 bokeh 相比,我喜欢它的易用性。但是,我在如何美化我的情节方面遇到了一些基本问题。首先,这是下面的代码(功能齐全,只需复制和粘贴!):
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(显示在蓝色条中)只显示它的右边缘,而不是填充条?是这样的:
如果您注意到了,我还在每个类别下添加了一行。有没有快速的方法来添加这个?不是交易破坏者,只是奖金。我正在尝试做的其他事情是添加动画等,但那是其他时间!
提前感谢您的回答!
您可以使用 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
为每个柱单独设置此项,或者通过将 fig.add_trace
完全隐藏图例=16=] 到 fig.update_layout
方法。
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
将 return 一个 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()