QWebEngineView:“静音散景图

时间:2017-08-29 17:05:07

标签: python pyqt5 bokeh qtwebengine

我正在使用PyQt5创建GUI,并在此GUI中使用Bokeh可视化QWebEngineView图表。

它工作正常,但当我尝试实现像this这样的“静音”传奇时,我收到错误:

js: Uncaught TypeError: Cannot read property 'pageX' of undefined

如果我使用show方法,我会在浏览器中得到期望的结果。但是,如果我使用保存并将其显示到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 个答案:

答案 0 :(得分:1)

首先,免责声明:使用Qt浏览器小部件,Bokeh不会完全或部分声明功能。我们根本没有能力在持续测试下严格维护这一说法,因此我们无法做到。如果有人愿意作为该功能的维护者介入,将来我们可以提出更强有力的支持声明。

Bokeh使用第三方库 Hammer.js 在不同平台上提供统一的低级事件处理。 Bokeh期望生成的事件具有pageXpageY属性。似乎Qt的浏览器小部件不满足这种期望,导致您看到的错误。更新Bokeh使用的Hammer版本可能会解决问题。可能会引入一种解决方法。无论如何,它需要BokehJS本身的新工作。

简短的回答是:这个互动传奇可能只是在Qt上不起作用。作为一种解决方法,使用Bokeh小部件或Qt小部件来高并显示字形,而不依赖于交互式图例功能。

长期:Wo可以研究上面提出的一些想法。但我们需要帮助才能做到。 我们没有自己构建Qt应用程序的带宽,能力或经验来测试潜在的修复程序。如果您有能力与核心开发人员一起寻找解决方案,请随时制作问题issue tracker