如何在 Plotly python 中添加矩形和文本注释?
How to add rectangles and text annotations in Plotly python?
Matplotlib 有 plt.Rectangle()
创建彩色矩形和 ax.text
为每个添加的矩形放置文本。
示例数据
data_dict = {"Trace": [["A-M", "B&M", "B&Q", "BLOG", "BYPAS", "CIM"],
["B&M", "B&Q", "BLOG", "BYPAS"],
["BLOG", "BYPAS", "CIM"],
["A-M", "B&M", "B&Q", "BLOG"]],
"Percentage": [28.09, 32, 0.98, 18.68]}
acronym = {"A-M": "Alternating Maximization",
"B&M": "Business & Management",
"B&Q": "Batch-And-Queue",
"BLOG": "Buy Locally Owned Group",
"BYPAS": "Bypass",
"CIM": "Common Information Model"
}
plotly
是否支持向图中添加矩形。如何在 plotly 中绘制“Trace Explorer”类型的图?
为了让图例条目连接到您绘制的矩形,您需要使用 go.Scatter
来绘制矩形。注释将不起作用,因为它们没有对应的图例条目。
每个矩形将使用包含五个 (x,y) 坐标(从起始位置回到原始起始位置)的 go.Scatter
轨迹绘制,我们可以用特定于其名称的颜色映射填充它。由于多个矩形具有相同的名称,我们希望通过使用图例组来避免重复条目。
还有一些与格式相关的其他事情,例如行之间的填充、框的宽度和高度,以及设置 y-axes 的范围,以便 selecting 和 deselecting traces 不会调整图的大小(我认为 plotly 的默认行为在这里是不可取的)。
import pandas as pd
import plotly.graph_objects as go
data_dict = {"Trace": [["A-M", "B&M", "B&Q", "BLOG", "BYPAS", "CIM"],
["B&M", "B&Q", "BLOG", "BYPAS"],
["BLOG", "BYPAS", "CIM"],
["A-M", "B&M", "B&Q", "BLOG"]],
"Percentage": [28.09, 32, 0.98, 18.68]}
acronym = {"A-M": "Alternating Maximization",
"B&M": "Business & Management",
"B&Q": "Batch-And-Queue",
"BLOG": "Buy Locally Owned Group",
"BYPAS": "Bypass",
"CIM": "Common Information Model"
}
color_map = {"A-M": "DodgerBlue",
"B&M": "DarkTurquoise",
"B&Q": "Aquamarine",
"BLOG": "LightGreen",
"BYPAS": "Khaki",
"CIM": "Tomato"
}
check_legend_entry = {key:False for key in acronym.keys()}
fig = go.Figure()
## xaxis legnth is the number of categories + 1 for the percentage boxes
xaxis_length = max([len(trace_list) for trace_list in data_dict['Trace']]) + 1
width, height = 1, 1
y_row_padding = width/4
xaxis_padding = width/4
## draw out of the rectangles by iterating through each trace
## and plotting in coordinates starting from upper left to lower right
## the rectangles will be centered at (0,0), (1,0), ... (0,-1), (1,-1), ... ()
for row_number, trace_list in enumerate(data_dict['Trace']):
## this will add y-padding between any boxes that aren't in the first row
y_pos = (row_number-1)*(1+y_row_padding)
for x_pos, name in enumerate(trace_list):
## check whether a legend entry has been created for a particular name
## to avoid duplicate legend entries for the same type of rectangle
if check_legend_entry[name] == False:
check_legend_entry[name] = True
showlegend=True
else:
showlegend=False
fig.add_trace(go.Scatter(
x=[x_pos-width/2, x_pos+width/2, x_pos+width/2, x_pos-width/2, x_pos-width/2],
y=[-y_pos-height/2, -y_pos-height/2, -y_pos+height/2, -y_pos+height/2, -y_pos-height/2],
mode='lines',
name=acronym[name],
meta=[name],
hovertemplate='%{meta[0]}<extra></extra>',
legendgroup=acronym[name],
line=dict(color="black"),
fill='toself',
fillcolor=color_map[name],
showlegend=showlegend
))
## add the text in the center of each rectangle
## skip hoverinfo since the rectangle itself already has hoverinfo
fig.add_trace(go.Scatter(
x=[x_pos],
y=[-y_pos],
mode='text',
legendgroup=acronym[name],
text=[name],
hoverinfo='skip',
textposition="middle center",
showlegend=False
))
## add the percentage boxes
for row_number, percentage in enumerate(data_dict['Percentage']):
y_pos = (row_number-1)*(1+y_row_padding)
x_pos = max([len(trace_list) for trace_list in data_dict['Trace']]) + width/4
fig.add_trace(go.Scatter(
x=[x_pos-width/2, x_pos+width/2, x_pos+width/2, x_pos-width/2, x_pos-width/2],
y=[-y_pos-height/2, -y_pos-height/2, -y_pos+height/2, -y_pos+height/2, -y_pos-height/2],
mode='lines',
line=dict(width=0),
fill='toself',
fillcolor='darkgrey',
showlegend=False
))
fig.add_trace(go.Scatter(
x=[x_pos],
y=[-y_pos],
mode='text',
text=[f"{percentage}%"],
marker=dict(color="white"),
hoverinfo='skip',
textposition="middle center",
showlegend=False
))
## prevent the axes from resizing if traces are removed
fig.update_xaxes(range=[-width+xaxis_padding, xaxis_length-xaxis_padding])
fig.update_layout(template='simple_white')
fig.update_yaxes(visible=False)
fig.show()
注意:我知道您并没有要求 select 或 deselect 痕迹的功能,但我不认为可以在 [=13] 中禁用此功能=] 即使你想(见此 open issue)。该功能如下所示:
Matplotlib 有 plt.Rectangle()
创建彩色矩形和 ax.text
为每个添加的矩形放置文本。
示例数据
data_dict = {"Trace": [["A-M", "B&M", "B&Q", "BLOG", "BYPAS", "CIM"],
["B&M", "B&Q", "BLOG", "BYPAS"],
["BLOG", "BYPAS", "CIM"],
["A-M", "B&M", "B&Q", "BLOG"]],
"Percentage": [28.09, 32, 0.98, 18.68]}
acronym = {"A-M": "Alternating Maximization",
"B&M": "Business & Management",
"B&Q": "Batch-And-Queue",
"BLOG": "Buy Locally Owned Group",
"BYPAS": "Bypass",
"CIM": "Common Information Model"
}
plotly
是否支持向图中添加矩形。如何在 plotly 中绘制“Trace Explorer”类型的图?
为了让图例条目连接到您绘制的矩形,您需要使用 go.Scatter
来绘制矩形。注释将不起作用,因为它们没有对应的图例条目。
每个矩形将使用包含五个 (x,y) 坐标(从起始位置回到原始起始位置)的 go.Scatter
轨迹绘制,我们可以用特定于其名称的颜色映射填充它。由于多个矩形具有相同的名称,我们希望通过使用图例组来避免重复条目。
还有一些与格式相关的其他事情,例如行之间的填充、框的宽度和高度,以及设置 y-axes 的范围,以便 selecting 和 deselecting traces 不会调整图的大小(我认为 plotly 的默认行为在这里是不可取的)。
import pandas as pd
import plotly.graph_objects as go
data_dict = {"Trace": [["A-M", "B&M", "B&Q", "BLOG", "BYPAS", "CIM"],
["B&M", "B&Q", "BLOG", "BYPAS"],
["BLOG", "BYPAS", "CIM"],
["A-M", "B&M", "B&Q", "BLOG"]],
"Percentage": [28.09, 32, 0.98, 18.68]}
acronym = {"A-M": "Alternating Maximization",
"B&M": "Business & Management",
"B&Q": "Batch-And-Queue",
"BLOG": "Buy Locally Owned Group",
"BYPAS": "Bypass",
"CIM": "Common Information Model"
}
color_map = {"A-M": "DodgerBlue",
"B&M": "DarkTurquoise",
"B&Q": "Aquamarine",
"BLOG": "LightGreen",
"BYPAS": "Khaki",
"CIM": "Tomato"
}
check_legend_entry = {key:False for key in acronym.keys()}
fig = go.Figure()
## xaxis legnth is the number of categories + 1 for the percentage boxes
xaxis_length = max([len(trace_list) for trace_list in data_dict['Trace']]) + 1
width, height = 1, 1
y_row_padding = width/4
xaxis_padding = width/4
## draw out of the rectangles by iterating through each trace
## and plotting in coordinates starting from upper left to lower right
## the rectangles will be centered at (0,0), (1,0), ... (0,-1), (1,-1), ... ()
for row_number, trace_list in enumerate(data_dict['Trace']):
## this will add y-padding between any boxes that aren't in the first row
y_pos = (row_number-1)*(1+y_row_padding)
for x_pos, name in enumerate(trace_list):
## check whether a legend entry has been created for a particular name
## to avoid duplicate legend entries for the same type of rectangle
if check_legend_entry[name] == False:
check_legend_entry[name] = True
showlegend=True
else:
showlegend=False
fig.add_trace(go.Scatter(
x=[x_pos-width/2, x_pos+width/2, x_pos+width/2, x_pos-width/2, x_pos-width/2],
y=[-y_pos-height/2, -y_pos-height/2, -y_pos+height/2, -y_pos+height/2, -y_pos-height/2],
mode='lines',
name=acronym[name],
meta=[name],
hovertemplate='%{meta[0]}<extra></extra>',
legendgroup=acronym[name],
line=dict(color="black"),
fill='toself',
fillcolor=color_map[name],
showlegend=showlegend
))
## add the text in the center of each rectangle
## skip hoverinfo since the rectangle itself already has hoverinfo
fig.add_trace(go.Scatter(
x=[x_pos],
y=[-y_pos],
mode='text',
legendgroup=acronym[name],
text=[name],
hoverinfo='skip',
textposition="middle center",
showlegend=False
))
## add the percentage boxes
for row_number, percentage in enumerate(data_dict['Percentage']):
y_pos = (row_number-1)*(1+y_row_padding)
x_pos = max([len(trace_list) for trace_list in data_dict['Trace']]) + width/4
fig.add_trace(go.Scatter(
x=[x_pos-width/2, x_pos+width/2, x_pos+width/2, x_pos-width/2, x_pos-width/2],
y=[-y_pos-height/2, -y_pos-height/2, -y_pos+height/2, -y_pos+height/2, -y_pos-height/2],
mode='lines',
line=dict(width=0),
fill='toself',
fillcolor='darkgrey',
showlegend=False
))
fig.add_trace(go.Scatter(
x=[x_pos],
y=[-y_pos],
mode='text',
text=[f"{percentage}%"],
marker=dict(color="white"),
hoverinfo='skip',
textposition="middle center",
showlegend=False
))
## prevent the axes from resizing if traces are removed
fig.update_xaxes(range=[-width+xaxis_padding, xaxis_length-xaxis_padding])
fig.update_layout(template='simple_white')
fig.update_yaxes(visible=False)
fig.show()
注意:我知道您并没有要求 select 或 deselect 痕迹的功能,但我不认为可以在 [=13] 中禁用此功能=] 即使你想(见此 open issue)。该功能如下所示: