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

如何在cefpython3中嵌入离线Plotly图表并实现单脚本双服务运行

问题根源

你当前代码无法同时运行的核心原因是app.run_server()为阻塞调用,启动后会独占主线程,导致后续的CEF消息循环cef.MessageLoop()无法执行,因此两个服务只能二选一。

解决方案1:多线程运行Dash服务(保留Dash完整交互能力)

将Dash服务放到独立的守护线程中启动,不阻塞主线程的CEF逻辑执行,修改后的完整代码如下:

from cefpython3 import cefpython as cef
import platform
import sys
import threading
#dash (plotly)---------------------
import dash
from dash import dcc
from dash import html
import plotly.express as px
import pandas as pd
#---------------------------------

def main():
    check_versions()
    sys.excepthook = cef.ExceptHook  # To shutdown all CEF processes on error
    cef.Initialize()
    cef.CreateBrowserSync(url="http://127.0.0.1:8050/",
                          window_title="Test")
    # 启动Dash服务到独立守护线程
    dash_thread = threading.Thread(target=DashApp, daemon=True)
    dash_thread.start()
    cef.MessageLoop()
    cef.Shutdown()

def check_versions():
    ver = cef.GetVersion()
    print("[dashtest.py] CEF Python {ver}".format(ver=ver["version"]))
    print("[dashtest.py] Chromium {ver}".format(ver=ver["chrome_version"]))
    print("[dashtest.py] CEF {ver}".format(ver=ver["cef_version"]))
    print("[dashtest.py] Python {ver} {arch}".format(
           ver=platform.python_version(),
           arch=platform.architecture()[0]))
    assert cef.__version__ >= "57.0", "CEF Python v57.0+ required to run this"


def DashApp():
    app = dash.Dash()

    df = pd.DataFrame({
        "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
        "Amount": [4, 1, 2, 2, 4, 5],
        "City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"]
    })

    fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")

    app.layout = html.Div(children=[
        html.H1(children='Hello Dash'),

        html.Div(children='''
            Dash: A web application framework for your data.
        '''),

        dcc.Graph(
            id='example-graph',
            figure=fig
        )
    ])
    # 关闭use_reloader避免多线程冲突
    app.run_server(debug=False, use_reloader=False)

if __name__ == '__main__':
    main()

注意事项:app.run_server要加use_reloader=False参数,避免Flask的重载机制触发多线程冲突。

解决方案2:静态HTML直接加载(更适合纯离线场景)

如果不需要Dash的服务端交互能力,完全可以跳过启动本地服务的步骤,直接将Plotly图表生成静态HTML字符串交给CEF加载,性能更高、完全离线可用,无需占用本地端口,代码示例如下:

from cefpython3 import cefpython as cef
import platform
import sys
import plotly.express as px
import pandas as pd

def main():
    check_versions()
    sys.excepthook = cef.ExceptHook
    cef.Initialize()
    browser = cef.CreateBrowserSync(window_title="离线Plotly示例")
    
    # 生成Plotly图表
    df = pd.DataFrame({
        "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
        "Amount": [4, 1, 2, 2, 4, 5],
        "City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"]
    })
    fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")
    # 转成完整HTML字符串
    html_content = f"""
    <html>
    <head>
        <meta charset="utf-8">
        <title>离线Plotly</title>
    </head>
    <body>
        <h1>Hello 离线Plotly</h1>
        {fig.to_html(full_html=False, include_plotlyjs='cdn')}
        <!-- 如果需要完全离线,把上面的include_plotlyjs参数改为本地plotly.min.js的路径即可 -->
    </body>
    </html>
    """
    # 直接加载HTML内容,无需启动服务
    browser.LoadString(html_content, "http://local/")
    
    cef.MessageLoop()
    cef.Shutdown()

def check_versions():
    ver = cef.GetVersion()
    print("[dashtest.py] CEF Python {ver}".format(ver=ver["version"]))
    print("[dashtest.py] Chromium {ver}".format(ver=ver["chrome_version"]))
    print("[dashtest.py] CEF {ver}".format(ver=ver["cef_version"]))
    print("[dashtest.py] Python {ver} {arch}".format(
           ver=platform.python_version(),
           arch=platform.architecture()[0]))
    assert cef.__version__ >= "57.0", "CEF Python v57.0+ required to run this"

if __name__ == '__main__':
    main()

如果需要完全离线不依赖网络,只要提前下载plotly.min.js到本地,将include_plotlyjs参数替换为本地文件路径即可。

实时刷新实现说明

如果需要图表实时更新:

  • 用方案1的话,可以在CEF和Dash之间通过接口请求、WebSocket等方式做数据同步,也可以直接在Dash侧做定时回调更新数据
  • 用方案2的话,可以通过CEF的JS绑定功能,将Python侧的数据注入到前端JS,调用Plotly的JS接口更新图表,性能更优。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 23:36:03