<p>感谢Rob,根据他的回答,我用以下代码解决了我的问题:</p>
<pre><code>import pandas as pd
import plotly.express as px
from plotly.subplots import make_subplots
# parameters
files = ["JQ038231.1_RSCU_stack.csv", "MG970255.1_RSCU_stack.csv"]
fig_n = len(files)
space_figs = 0.07
y_offset = 0.8
text_size = 12
width_ = 900
height_ = 700
bottom2fig_ratio = 0.4
row_heights_ = [1/(fig_n+bottom2fig_ratio)]*fig_n + [1/(fig_n+bottom2fig_ratio)*bottom2fig_ratio] # [1/2.5]*2 + [1/2.5*0.5] = [0.4, 0.4, 0.2]
# subplots figure...
figall = make_subplots(rows=fig_n+1, row_heights=row_heights_, vertical_spacing=space_figs, subplot_titles=files)
for num, file in enumerate(files):
row_ = num + 1
rscu = pd.read_csv(file)
rscu = rscu.astype({"Fill": "category"})
rscu = rscu.astype({"aaRatio": "object"})
max_rscu = rscu.groupby(by=["AA"]).sum().max()["RSCU"]
fig = px.bar(rscu, x="AA", y="RSCU", color="Fill", barmode = 'stack', text="aaRatio",
hover_data=['AA', "RSCU"], color_discrete_map={1: "#6598c9", 2: "#cb4a28", 3: "#9ac664", 4: "#7f5499"})
fig.update_traces(textposition='outside') # show text to outside
# set xaxis style
if row_ != fig_n:
fig.update_xaxes(showline=True, linewidth=1, linecolor="black", ticks="outside",
tickangle=0, title=None, showticklabels=False)
else:
fig.update_xaxes(showline=True, linewidth=1, linecolor="black", ticks="outside",
title=None)
# set y range to show annotation text
fig.update_yaxes(showline=True, linewidth=1, linecolor="black", ticks="outside", range=[0, max_rscu + y_offset])
# add all the traces to appropriate subplot
for f in fig.data:
figall.add_trace(f, row=row_, col=1)
# to make fig's layout works in figall
fig.for_each_trace(lambda trace_: trace_.update(xaxis=f"x{row_}", yaxis=f"y{row_}"))
fig.layout[f"xaxis{row_}"] = fig.layout.pop("xaxis")
fig.layout[f"yaxis{row_}"] = fig.layout.pop("yaxis")
fig.layout[f"xaxis{row_}"]["anchor"] = f"y{row_}"
fig.layout[f"yaxis{row_}"]["anchor"] = f"x{row_}"
fig.layout[f"yaxis{row_}"].pop("domain") # otherwise it will affect figall's domain
figall.update_layout(fig.layout)
fig_bottom = px.bar(rscu, x="AA", y="Equality", color="Fill", barmode = 'stack', text="Codon",
hover_data=['AA'], color_discrete_map={1: "#6598c9", 2: "#cb4a28", 3: "#9ac664", 4: "#7f5499"})
fig_bottom.update_traces(textposition='inside') # show text to inside
bottom_row = fig_n+1
fig_bottom.for_each_trace(lambda trace_: trace_.update(xaxis=f"x{bottom_row}", yaxis=f"y{bottom_row}"))
# add all the traces of bottom figure to appropriate subplot
for f in fig_bottom.data:
figall.add_trace(f, row=bottom_row, col=1)
dict_layout = {"barmode": "stack",
"autosize": False,
"showlegend": False,
"plot_bgcolor": "rgba(0, 0, 0, 0)",
"paper_bgcolor": "rgba(0, 0, 0, 0)",
"uniformtext_minsize": text_size,
"uniformtext_mode": "show",
"width": width_,
"height": height_}
# for bottom figure
dict_layout[f"yaxis{fig_n+1}"] = {"title": None, "showticklabels": False}
dict_layout[f"xaxis{fig_n+1}"] = {"title": None, "showticklabels": False}
figall.update_layout(dict_layout)
figall.for_each_annotation(lambda x: x.update(x=0.12, font={"size": 13, "family": "Arial", "color": "black"})) # adjust title of each sub-figure
figall.for_each_trace(lambda trace_: trace_.update(width=0.9)) # set bar width
figall.show()
</code></pre>
<p><a href="https://i.stack.imgur.com/CzVxW.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/CzVxW.png" alt="enter image description here"/></a></p>