有没有办法合并两个堆叠的plotly.express.bar图形

2024-07-04 04:55:14 发布

您现在位置:Python中文网/ 问答频道 /正文

我想在plotly.express中合并两个堆叠条形图

第一幅图的代码是:

import pandas as pd
import plotly.express as px
from plotly.subplots import make_subplots

rscu1 = pd.read_csv("JQ038231.1_RSCU_stack.csv")
rscu2 = pd.read_csv("MG970255.1_RSCU_stack.csv")

rscu = pd.concat([rscu1, rscu2], keys=["JQ038231", "MG970255"])
rscu["species"] = rscu.index.get_level_values(0)
rscu = rscu.astype({"Fill": "category"})
rscu = rscu.astype({"aaRatio": "object"})

fig = px.bar(rscu, x="AA", y="RSCU", color="Fill", barmode = 'stack', text="aaRatio",
                hover_data=['AA', "RSCU"], facet_row="species",
                color_discrete_map={1: "#6598c9", 2: "#cb4a28", 3: "#9ac664", 4: "#7f5499"})

fig.update_xaxes(tickangle=0, title=None, ticks="outside") 
fig.update_layout(
    autosize=False,
    width=950,
    height=450,
    showlegend=False)
for data in fig.data:
    data["width"] = 0.9

fig.update_traces(textposition='outside')
fig.update_layout(uniformtext_minsize=8, uniformtext_mode='show')

这些代码生成此图: enter image description here

第二幅图的代码是:

fig_bottom = px.bar(rscu1, x="AA", y="Equality", color="Fill", barmode = 'stack', text="AA",
                hover_data=['AA'], height=220, width=950,
                color_discrete_map={1: "#6598c9", 2: "#cb4a28", 3: "#9ac664", 4: "#7f5499"})
fig_bottom.update_traces(textposition='inside', textfont_size=14)
fig_bottom.update_layout(uniformtext_minsize=9, uniformtext_mode='show', showlegend=False,)
fig_bottom.update_layout({"plot_bgcolor": "rgba(0, 0, 0, 0)",
                        "paper_bgcolor": "rgba(0, 0, 0, 0)"})
fig_bottom.update_yaxes(title=None, showticklabels=False)
fig_bottom.update_xaxes(title=None, showticklabels=False)
for data in fig_bottom.data:
    data["width"] = 0.9

这些代码生成此图: enter image description here

是否有办法将它们合并为一个图形,最终图形(由ggplot制作)为: enter image description here

这里使用的数据可以在https://github.com/dongzhang0725/sample_data中找到


Tags: csvfalsedatastackfigupdatewidthcolor
2条回答

更新

根据前面的回答,您可以make_subplots()add_trace()和最后update_layout()

来自GitHub的

import requests
import io

rscu1 = pd.read_csv(io.StringIO(requests.get("https://raw.githubusercontent.com/dongzhang0725/sample_data/main/JQ038231.1_RSCU_stack.csv").text))
rscu2 = pd.read_csv(io.StringIO(requests.get("https://raw.githubusercontent.com/dongzhang0725/sample_data/main/MG970255.1_RSCU_stack.csv").text))


溶液

# want "bottom" figure to use it's own axis to add to subplots
fig_bottom.data[0]["xaxis"]="x3"
fig_bottom.data[0]["yaxis"]="y3"

# subplots figure...
figall = make_subplots(rows=3, row_heights=[.4,.4,.2])

# add all the traces to appropriate subplot
for f in fig.data:
    if f["yaxis"] == "y":
        figall.add_trace(f, row=1, col=1)
    else:
        figall.add_trace(f, row=2, col=1)

figall.add_trace(fig_bottom.data[0], row=3, col=1)

# copy / modify layout of subplots figure
figall.update_layout(fig.layout)
fh = .38 # height of first two charts
figall.update_layout(
    yaxis={"domain":[(1-2*fh)-.03,(1-fh)-.03]},
    yaxis2={"domain":[1-fh,1]},
    xaxis3={"title": None, "showticklabels": False},
    yaxis3={"title": None, "showticklabels": False},
    height=fig.layout["height"] + fig_bottom.layout["height"],
)
figall.update_traces(marker_coloraxis=None)
# recenter annotations....
for i, a in enumerate(figall.layout["annotations"]):
    a["y"] = (1-i*(fh+.03))-fh/2
    
figall

enter image description here

感谢Rob,根据他的回答,我用以下代码解决了我的问题:

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()

enter image description here

相关问题 更多 >

    热门问题