You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置Plotly使图表自适应尺寸适配背景图像并保持宽高比

Plotly 背景图自适应宽高比实现方案

问题根因

高度不匹配问题来自两个默认机制:

  • dcc.Graph 组件默认高度固定为450px,即使开启autosize=True,也只会自动适配父容器宽度,不会根据内容反向计算所需高度
  • 使用xref/yref="paper"模式叠加图片时,图片只会被动适配现有绘图区尺寸,无法驱动绘图区调整大小
    之前手动改sizey=3能接近预期比例,但本质是硬编码拉伸图片参考系,不同宽度下会出现裁切或比例失调,无法适配多设备场景。

实现步骤

要实现「宽度适配容器、保持原图宽高比、无裁切」的效果,按以下逻辑修改即可:

  1. 预读取图片的原始宽高值,计算固定宽高比作为计算基准
  2. 调整图片叠加逻辑,改用坐标轴作为参考系,设置坐标轴范围与图片像素完全对齐,同时锁定xy轴缩放比例,从根源避免图片拉伸变形
  3. 新增轻量客户端回调,在浏览器端实时获取图表容器的实际渲染宽度,按宽高比+边距偏移动态计算所需高度,直接赋值给图表组件的样式,窗口尺寸变化、布局变动时自动重算。

完整修改代码

绘图函数修改

import cv2
import base64
import plotly.graph_objects as go
from django_plotly_dash import DjangoDash
import dash_bootstrap_components as dbc
from dash import html, dcc, clientside_callback, Input, Output

# 全局读取图片,预计算宽高比
img = cv2.imread("image.png")
IMG_HEIGHT, IMG_WIDTH = img.shape[:2]
# 原始宽高比 7490/4906 ≈ 1.527
IMG_ASPECT_RATIO = IMG_WIDTH / IMG_HEIGHT
# 对应layout中设置的上下边距总和 t=40 + b=10 = 50
MARGIN_VERTICAL = 50

def build_figure(image):
    # 编码图片
    _, buffer = cv2.imencode(".png", image)
    encoded_img = base64.b64encode(buffer).decode()

    figure = go.Figure(
        layout=go.Layout(
            autosize=True,
            font={"color": "black", "family": "Arial"},
            margin={"t": 40, "b": 10, "r": 5, "l": 10},
            paper_bgcolor="#ffffff",
            plot_bgcolor="#ffffff",
            xaxis={
                "range": [0, IMG_WIDTH],
                "showgrid": False,
                "visible": False,
                "fixedrange": True
            },
            yaxis={
                "range": [0, IMG_HEIGHT],
                "showgrid": False,
                "visible": False,
                "fixedrange": True,
                # 锁定xy轴比例,防止图片拉伸
                "scaleanchor": "x"
            },
        )
    )

    figure.add_layout_image(
        go.layout.Image(
            source=f"data:image/png;base64,{encoded_img}",
            xref="x",
            yref="y",
            x=0,
            y=0,
            sizex=IMG_WIDTH,
            sizey=IMG_HEIGHT,
            xanchor="left",
            yanchor="bottom",
            layer="below"
        )
    )
    return figure

Dash应用与回调修改

app = DjangoDash("circuits", suppress_callback_exceptions=True)
app.layout = html.Div(
    children=[
        dbc.Card(
            dbc.CardBody(
                dcc.Graph(
                    id="circuit-image-graph",
                    config={"displaylogo": False},
                    figure=build_figure(img),
                    style={"width": "100%"}
                ),
            ),
        ),
    ],
)

# 客户端回调动态计算高度,无后端请求开销
clientside_callback(
    f"""
    function() {{
        const graphNode = document.getElementById('circuit-image-graph');
        if (!graphNode) return {{"width": "100%", "height": "450px"}};
        // 获取容器实际渲染宽度
        const currentWidth = graphNode.clientWidth;
        // 按比例算高度,加上下边距偏移
        const calcHeight = (currentWidth / {IMG_ASPECT_RATIO}) + {MARGIN_VERTICAL};
        return {{"width": "100%", "height": `${{calcHeight}}px`}};
    }}
    """,
    Output("circuit-image-graph", "style"),
    Input("circuit-image-graph", "figure"),
    prevent_initial_call=False
)

注意事项

  • 如果后续调整layout的上下margin值,同步修改MARGIN_VERTICAL的数值即可,否则会出现上下留白过多或图片被裁切的问题
  • 客户端回调会在页面加载、窗口大小变化、父容器布局变动时自动触发,不需要额外绑定resize事件,适配PC、平板、手机等所有设备尺寸
  • 不需要手动调整sizey参数,scaleanchor配置会保证图片比例始终和原图一致,不会出现拉伸变形

内容的提问来源于stack exchange,提问作者Julian_Orteil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 20:09:11