如何重新打开 bokeh html 文件并恢复每个图形的最后缩放状态?

问题描述 投票:0回答:2

我有一个由

bokeh
gridplot
生成的 html 文件,其中包含多个数字。

假设我打开 html 文件,将一些(或全部)图形放大到不同级别,然后关闭文件。下次我重新打开这个文件时,我希望所有图形自动设置为之前的缩放级别。

你能告诉我怎么做吗?

这里是一个示例代码,可以快速生成一个包含两个数字的 html 文件。

import numpy as np
from bokeh.io import save
from bokeh.layouts import gridplot
from bokeh.plotting import figure

x = np.linspace(0, 4 * np.pi, 100)
y = np.sin(x)

TOOLS = "pan,wheel_zoom,box_zoom,reset,save,box_select"

p1 = figure(title="Legend Example", tools=TOOLS)

p1.circle(x, y, legend_label="sin(x)")
p1.circle(x, 2 * y, legend_label="2*sin(x)", color="orange")
p1.circle(x, 3 * y, legend_label="3*sin(x)", color="green")

p1.legend.title = "Markers"

p2 = figure(title="Another Legend Example", tools=TOOLS)

p2.circle(x, y, legend_label="sin(x)")
p2.line(x, y, legend_label="sin(x)")

p2.line(
    x,
    2 * y,
    legend_label="2*sin(x)",
    line_dash=(4, 4),
    line_color="orange",
    line_width=2,
)

p2.square(x, 3 * y, legend_label="3*sin(x)", fill_color=None, line_color="green")
p2.line(x, 3 * y, legend_label="3*sin(x)", line_color="green")

p2.legend.title = "Lines"
p2.x_range = p1.x_range

save(gridplot([p1, p2], ncols=2, width=400, height=400))

谢谢。

python bokeh
2个回答
1
投票

为此,您可以使用 Bokeh 的 ResetTool 和 CustomJS 回调将缩放级别存储在浏览器的本地存储中,并在再次打开 HTML 文件时检索它们。

像这样

import numpy as np
from bokeh.io import save
from bokeh.layouts import gridplot
from bokeh.models import ResetTool, CustomJS
from bokeh.plotting import figure

x = np.linspace(0, 4 * np.pi, 100)
y = np.sin(x)

TOOLS = "pan,wheel_zoom,box_zoom,reset,save,box_select"

p1 = figure(title="Legend Example", tools=TOOLS, x_range=(0, 4 * np.pi), y_range=(-3, 3))
p1.circle(x, y, legend_label="sin(x)")
p1.circle(x, 2 * y, legend_label="2*sin(x)", color="orange")
p1.circle(x, 3 * y, legend_label="3*sin(x)", color="green")

p1.legend.title = "Markers"

p2 = figure(title="Another Legend Example", tools=TOOLS, x_range=(0, 4 * np.pi), y_range=(-3, 3))
p2.circle(x, y, legend_label="sin(x)")
p2.line(x, y, legend_label="sin(x)")

p2.line(
    x,
    2 * y,
    legend_label="2*sin(x)",
    line_dash=(4, 4),
    line_color="orange",
    line_width=2,
)

p2.square(x, 3 * y, legend_label="3*sin(x)", fill_color=None, line_color="green")
p2.line(x, 3 * y, legend_label="3*sin(x)", line_color="green")

p2.legend.title = "Lines"
p2.x_range = p1.x_range

# Add ResetTool to the plot tools
p1.add_tools(ResetTool())
p2.add_tools(ResetTool())

# Define CustomJS callback function to store the zoom levels in local storage
callback = CustomJS(args=dict(p1=p1, p2=p2), code="""
    localStorage.setItem('p1_x_range', JSON.stringify(p1.x_range.start + ',' + p1.x_range.end));
    localStorage.setItem('p1_y_range', JSON.stringify(p1.y_range.start + ',' + p1.y_range.end));
    localStorage.setItem('p2_x_range', JSON.stringify(p2.x_range.start + ',' + p2.x_range.end));
    localStorage.setItem('p2_y_range', JSON.stringify(p2.y_range.start + ',' + p2.y_range.end));
""")

# Add the callback to the ResetTool
for plot in [p1, p2]:
    plot.tools[-1].js_on_change('reset', callback)

# Load the zoom levels from local storage if available
p1_x_range = localStorage.getItem('p1_x_range')
if p1_x_range is not None:
    p1.x_range.start, p1.x_range.end = map(float, p1_x_range.split(','))
    p1.y_range.start, p1.y_range.end = map(float, localStorage.getItem('p1_y_range').split(','))

p2_x_range = localStorage.getItem('p2_x_range')
if p2_x_range is not None:
    p2.x_range.start, p2.x_range.end = map(float, p2_x_range.split(','))
    p2.y_range.start, p2.y_range.end = map(float, localStorage.getItem('p2_y_range').split(','))

save(gridplot([p1, p2], ncols=2, width=400, height=400))

在此代码中,为每个绘图添加了一个

ResetTool
,并定义了一个
CustomJS
回调,当使用
ResetTool
时,该回调将每个绘图的x和y范围存储在浏览器的本地存储中。

然后将回调添加到每个绘图的

ResetTool
,并从本地存储中加载 x 和 y 范围(如果可用)。

请注意,在创建每个绘图时为 x 和 y 范围添加默认值,以确保绘图在首次显示时具有相同的范围,即使尚未完成缩放。

通过此修改,每个绘图的缩放级别将在下次打开 HTML 文件时保存和恢复,从而允许用户从他们中断的地方继续他们的工作。

希望有帮助

我们需要将散景图嵌入到一个简单的 HTML 文件中,并在网络浏览器中打开它。这是一个加载散景图并执行所需 JavaScript 代码的示例 HTML 文件

<!DOCTYPE html>
<html>
<head>
  <title>Bokeh Plot with Zoom Persistence</title>
  <script src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.1.min.js"></script>
  <script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.1.min.js"></script>
  <script src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.1.min.js"></script>
  <script src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.1.min.js"></script>
</head>
<body>
  <div id="plot"></div>
  <script>
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'plot.html', true);
    xhr.onload = function() {
      var div = document.getElementById('plot');
      div.innerHTML = this.responseText;
      var doc = new Bokeh.Document();
      Bokeh.embed.add_document_standalone(doc);
      doc.from_json(JSON.parse(this.responseText));
      // Add the JavaScript code to save and restore the zoom level
      var p1 = doc.get_model_by_name('p1');
      var p2 = doc.get_model_by_name('p2');
      var callback = function() {
        localStorage.setItem('p1_zoom', p1.plot_width / p1.inner_width);
        localStorage.setItem('p2_zoom', p2.plot_width / p2.inner_width);
      };
      p1.js_on_event('reset', callback);
      p2.js_on_event('reset', callback);
      p1.js_on_event('zoom', callback);
      p2.js_on_event('zoom', callback);
      var p1_zoom = localStorage.getItem('p1_zoom');
      if (p1_zoom != null) {
        p1.plot_width = p1_zoom * p1.inner_width;
      }
      var p2_zoom = localStorage.getItem('p2_zoom');
      if (p2_zoom != null) {
        p2.plot_width = p2_zoom * p2.inner_width;
      }
    };
    xhr.send();
  </script>
</body>
</html>

此 HTML 文件从名为 plot.html 的单独文件加载散景图,该文件仅包含网格图代码。 XMLHttpRequest 对象用于异步加载 plot.html 文件。加载文件后,散景图将添加到文档中,并执行所需的 JavaScript 代码以保存和恢复缩放级别。要使用此 HTML 文件,请将其与更新后的 Python 脚本保存在同一目录中。然后,在网络浏览器中打开 HTML 文件以查看散景图。

希望对您有所帮助)


0
投票

在 Bokeh 的图形中将“match_aspect”的值设置为“TRUE”将导致在下次查看 HTML 文档时记住所做的任何缩放。这就是你所要做的。

© www.soinside.com 2019 - 2024. All rights reserved.