QWebEngineView:静音散景图例时“无法读取未定义的属性‘pageX’”
Posted
技术标签:
【中文标题】QWebEngineView:静音散景图例时“无法读取未定义的属性‘pageX’”【英文标题】:QWebEngineView: "cannot read property 'pageX' of undefined" when muting bokeh legend 【发布时间】:2017-08-29 17:05:07 【问题描述】:我正在使用PyQt5
创建一个GUI
,在这个GUI
中,我使用QWebEngineView
可视化Bokeh
图表。
它工作正常,但是当我尝试实现像 this 这样的“静音”图例时,我收到一个错误:
js: Uncaught TypeError: Cannot read property 'pageX' of undefined
如果我使用 show 方法,我会在浏览器中得到预期的结果。但是,如果我使用 save 并将其显示到 QWebEngineView
我会收到上述错误。
有什么想法吗?
Gui
类中要在 QWebEngineView
中绘制和显示的插槽:
注意:忽略 Bar 和 Pizza 的图,与此事相关的是散点和线
def plotGraph(self, df=None):
# Get parameters to plot
x = str(self.ui.comboBox_x_axis.currentText())
y = str(self.ui.comboBox_y_axis.currentText())
# Define axis types
try:
x_axis_type = str(
self.ui.comboBox_plot_scale.currentText()).split('-')[0]
y_axis_type = str(
self.ui.comboBox_plot_scale.currentText()).split('-')[1]
except:
x_axis_type = 'auto'
y_axis_type = 'auto'
# Define kind of graph
kind = str(self.ui.comboBox_plot_style.currentText())
# For bar chart define groups
group = str(self.ui.comboBox_group.currentText())
# Prepare data for plot
if (kind == 'bar' and group != "Don't group"):
data = df[[x, y, group]]
else:
data = df[[x, y]]
data = data.sort_values(x, axis=0)
# Dynamically define plot size
width = round(self.ui.webViewer.frameGeometry().width())
height = round(self.ui.webViewer.frameGeometry().height())
# Plot and save html
self.plot = self.graph.plot(
data, kind, x_axis_type, y_axis_type, width, height)
self.plot_num = 1
# Display it at QWebEngineView
self.ui.webViewer.setUrl(QtCore.QUrl(
"file:///C:/Users/eandrade_brp/Documents/git/tl-data-viewer/plot.html"))
这是处理所有散景图的 Graph 类(我省略了一些不必要的代码)
class Graph(object):
"""docstring for ClassName"""
def __init__(self, file_name="plot.html"):
super(Graph, self).__init__()
output_file(file_name)
def plot(self, data, kind, x_axis_type, y_axis_type, width, height):
p = None
if kind == 'scatter' or kind == 'line':
layout, p = self.createFigure(
data, kind, x_axis_type, y_axis_type, width, height)
elif kind == 'bar':
layout = self.plot_Bar(data, width, height)
elif kind == 'pizza':
layout = self.plot_Pizza(
data, width, height)
# Show/save
save(layout)
return p
def createFigure(self, data, kind, x_axis_type, y_axis_type, width, height):
source, xdata, ydata, xvalues, yvalues = self.prepare_data(data)
# Define tool
tools = "pan, box_zoom, lasso_select, undo, redo"
wheel_zoom = WheelZoomTool()
hover = HoverTool(
tooltips=[
(data.columns[0], '$x'),
(data.columns[1], '$y')],
mode='mouse')
# Create first figure and customize
fig1 = figure(title=" vs " .format(ydata, xdata), tools=tools,
x_axis_type=x_axis_type, y_axis_type=y_axis_type,
toolbar_location="right", plot_width=round(0.9 * width),
plot_height=round(0.75 * height))
fig1.add_tools(wheel_zoom)
fig1.add_tools(hover)
fig1.toolbar.active_scroll = wheel_zoom
fig1.background_fill_color = "beige"
fig1.background_fill_alpha = 0.4
# Create second figure and customize
fig2 = figure(title='Overview', title_location="left",
x_axis_type=x_axis_type, y_axis_type=y_axis_type,
tools='', plot_width=round(0.9 * width), plot_height=round(0.25 * height))
fig2.xaxis.major_tick_line_color = None
fig2.xaxis.minor_tick_line_color = None
fig2.yaxis.major_tick_line_color = None
fig2.yaxis.minor_tick_line_color = None
fig2.xaxis.major_label_text_color = None
fig2.yaxis.major_label_text_color = None
# Add View box to second figure
rect = Rect(x='x', y='y', width='width', height='height', fill_alpha=0.1,
line_color='black', fill_color='black')
fig2.add_glyph(source, rect)
# Add JS callBacks
self.JS_linkPlots(fig1, source)
# Plots
plots = self.plot_continuous(source, xvalues, yvalues, fig1, kind)
self.plot_continuous(source, xvalues, yvalues, fig2, kind)
s2 = ColumnDataSource(data=dict(ym=[0.5, 0.5]))
fig1.line(x=[0, 1], y='ym', color="orange",
line_width=5, alpha=0.6, source=s2)
# Add legends
legend = Legend(items=[
(ydata, plots)],
location=(0, 0),
click_policy="mute")
# Add legend to fig layout
fig1.add_layout(legend, 'below')
# Layout
layout = col(fig1, fig2)
return layout, fig1
def plot_continuous(self, source, xvalues, yvalues, fig, kind, color=0):
if kind == 'scatter':
s = fig.scatter(
xvalues, yvalues,
fill_color='white', fill_alpha=0.6,
line_color=Spectral10[color], size=8,
selection_color="firebrick",
nonselection_fill_alpha=0.2,
nonselection_fill_color="blue",
nonselection_line_color="firebrick",
nonselection_line_alpha=1.0)
return [s]
elif kind == 'line':
l = fig.line(
xvalues, yvalues, line_width=2, color=Spectral10[color], alpha=0.8,
muted_color=Spectral10[color], muted_alpha=0.2)
s = fig.scatter(
xvalues, yvalues,
fill_color="white", fill_alpha=0.6,
line_color=Spectral10[color], size=8,
selection_color="firebrick",
nonselection_fill_alpha=0.2,
nonselection_fill_color="blue",
nonselection_line_color="firebrick",
nonselection_line_alpha=1.0)
return [s, l]
else:
raise 'Wrong type of plot'
def prepare_data(self, data):
xdata = data.columns[0]
xvalues = data[xdata]
ydata = data.columns[1]
yvalues = data[ydata]
source = ColumnDataSource(data)
return source, xdata, ydata, xvalues, yvalues
【问题讨论】:
【参考方案1】:首先,免责声明: Bokeh 没有声称可以完全或部分使用 Qt 浏览器小部件。我们根本没有能力在持续测试下严格地维持这一主张,因此我们无法做到。如果有人愿意作为该功能的维护者介入,那么我们将来可能会提出更强有力的支持声明。
Bokeh 使用第三方库 Hammer.js 跨不同平台提供统一的低级事件处理。 Bokeh 期望生成的事件具有pageX
和pageY
属性。似乎 Qt 的浏览器小部件不满足这种期望,导致您看到的错误。更新 Bokeh 使用的 Hammer 版本可能会解决问题。可能会引入一种解决方法。无论如何,这需要对 BokehJS 本身进行新的工作。
简短的回答是:这个交互式图例可能不适用于 Qt。作为一种解决方法,使用 Bokeh 小部件或 Qt 小部件来显示字形,不要依赖交互式图例功能。
长期:Wo 可以研究上面提出的一些想法。但是我们需要帮助才能做。 我们没有足够的带宽、能力或经验自行构建 Qt 应用程序来测试潜在的修复。 如果您有能力与核心开发人员一起寻找解决方案,请随时issue tracker 上的一个问题。
【讨论】:
以上是关于QWebEngineView:静音散景图例时“无法读取未定义的属性‘pageX’”的主要内容,如果未能解决你的问题,请参考以下文章