【问题标题】:Embedding visvis figure in a wx application在 wx 应用程序中嵌入 visvis 图形
【发布时间】:2019-09-10 08:45:06
【问题描述】:

下面的代码尝试在 wx 应用程序中嵌入 visvis figure 以制作带有 3D 数据的电影。问题是每次我朗读代码时,我都会收到错误

"./src/unix/glx11.cpp(86):在 SetCurrent() 中断言“xid”失败:窗口 必须在调用 Figure = app.GetFigureClass() 后立即显示” self.fig = 图(自我)

我花了一些时间研究这个错误,但没有一个答案适合我。有谁知道如何解决它?

import wx
import h5py
import numpy as np
import visvis as vv

app = vv.use('wx')

class CPlot3D (wx.Frame) :
    """
    Class for plotting 3D Dirac 
    """

    def data_for_plotting (self, frame_number) :
        """
        Load the data to be plotted for the frame with the frame_number 
        """
        frame = str(self.frame_names[frame_number])
        return self.f[frame][...]

    def draw_curent_frame (self, event=None) :
        """
        Display the current frame
        """
        # Load data
        data = self.data_for_plotting (self.frame_number.GetValue())    

        try :
            self.volume_plot.SetData (data)
        except AttributeError :
            vv.clf()
            self.volume_plot = vv.volshow (data, clim=(self.global_min, self.global_max), renderStyle='mip', cm=vv.CM_JET)
            a = vv.gca()
            vv.ColormapEditor(a)

            def GetTicks (axis_num, min_val, max_val, label_format="%.2f") :
                size = data.shape[axis_num]
                # Number of ticks
                nticks = int(np.ceil(np.log2(size)))
                nticks += 1 - nticks % 2 # Make <nticks> odd
                ticks_position = np.linspace(0, size-1, nticks)
                ticks_label = map( lambda x : label_format % x, np.linspace(min_val, max_val, nticks) ) 
                return dict( zip(ticks_position, ticks_label)  )

            a.axis.xTicks = GetTicks(0, self.x_min, self.x_max) 
            a.axis.xLabel = "x (rel. units)"

            a.axis.yTicks = GetTicks(1, self.y_min, self.y_max) 
            a.axis.yLabel = "y (rel. units)"

            a.axis.zTicks = GetTicks(2, self.z_min, self.z_max) 
            a.axis.zLabel = "z (rel. units)"

            self.fig.Draw()


    def __init__ (self, parent, file_name, title="Plot Dirac 3D") :
        # Open files
        self.f = h5py.File (file_name, 'r')

        # Extract the dimension
        self.x_gridDIM = int(self.f['x_gridDIM'][...])
        self.y_gridDIM = int(self.f['y_gridDIM'][...])
        self.z_gridDIM = int(self.f['z_gridDIM'][...])

        self.dx = self.f['dx'][...]

        self.x_min = self.f['x_min'][...]
        self.x_max = self.x_min + self.x_gridDIM * self.dx

        self.y_min = self.f['y_min'][...]
        self.y_max = self.y_min + self.y_gridDIM * self.dx

        self.z_min = self.f['z_min'][...]
        self.z_max = self.z_min + self.z_gridDIM * self.dx


        # Collect the frame names
        self.frame_names = []

        for key in self.f.keys () :
            try : self.frame_names.append (int(key)) 
            except ValueError: pass

        self.frame_names.sort ()

        print "\nGet global maximum and minimum..."

        # Find the min and max values in all the frames
        for frame_number in range(len(self.frame_names)) :
            data = self.data_for_plotting (frame_number)
            try :           
                self.global_min = min( self.global_min, data.min() )
                self.global_max = max( self.global_max, data.max() )
            except AttributeError :
                self.global_min = data.min()
                self.global_max = data.max()  

        print "\nStart animation..."

        # Create GUI
        dw, dh = wx.DisplaySize()
        wx.Frame.__init__ (self, parent, title=title, size=(0.4*dw, 0.6*dh) )

        self.ConstructGUI ()
        self.Center()
        self.Show ()
        wx.EVT_CLOSE(self, self.on_close)
        self.On_animation_button ()

    def on_close (self, event) :
        try : self.animation_timer.Stop() 
        except AttributeError : pass
        self.Destroy()

    def ConstructGUI (self) :
        """
        Make a GUI
        """
        ######################### Navigation bar ##############################
        panel = wx.Panel(self)  
        boxsizer = wx.BoxSizer (wx.HORIZONTAL)

        # Frame number indicator    
        boxsizer.Add (wx.StaticText(panel, label="Frame Number:"))
        self.frame_number = wx.SpinCtrl (panel, value="0", min=0, max=len(self.frame_names)-1)
        self.frame_number.Bind (wx.EVT_SPINCTRL, self.draw_curent_frame )
        boxsizer.Add (self.frame_number)

        # Go to the beginning button
        self.go_beginnign_button = wx.Button (panel, label="<<")
        self.Bind (wx.EVT_BUTTON, self.go_to_beginning, self.go_beginnign_button)
        boxsizer.Add (self.go_beginnign_button) 

        # Animation button
        self.animation_button_start_label = "Play  animation  "
        self.animation_button_stop_label =  "STOP animation"
        self.animation_button = wx.Button (panel, label=self.animation_button_start_label) 
        self.Bind (wx.EVT_BUTTON, self.On_animation_button, self.animation_button)
        boxsizer.Add (self.animation_button)

        # Go to the end button
        self.go_end_button = wx.Button (panel, label=">>")
        self.Bind (wx.EVT_BUTTON, self.go_to_end, self.go_end_button)
        boxsizer.Add (self.go_end_button) 

        panel.SetSizer (boxsizer)   
        ############################# Setting up visvis binding #######################################
        Figure = app.GetFigureClass()
        self.fig = Figure(self)
        ################################### Layout #####################################################    
        sizer = wx.BoxSizer (wx.VERTICAL)
        sizer.Add (panel, flag=wx.CENTER)
        sizer.Add(self.fig._widget, 1, flag=wx.EXPAND)

        self.SetSizer(sizer)
        self.SetAutoLayout(True)
        self.Layout() 


    def On_animation_button (self, event=None) :
        """
        <self.animation_button> was clicked
        """
        if self.animation_button.GetLabel() == self.animation_button_start_label :
            # Begin playing animation

            # Set up timer for animation
            timer_id = wx.NewId ()
            self.animation_timer = wx.Timer (self, timer_id) 
            self.animation_timer.Start (200)

            def on_animation_timer (event) :
                self.draw_curent_frame() 
                position = self.frame_number.GetValue()
                if position > len(self.frame_names)-2 : self.On_animation_button ()         
                else : self.frame_number.SetValue (position+1)

            wx.EVT_TIMER (self, timer_id, on_animation_timer)  
            # Channing the button's label
            self.animation_button.SetLabel(self.animation_button_stop_label)
        else : # Stop playing animation
            self.animation_timer.Stop ()
            del self.animation_timer
            # Channing the button's label
            self.animation_button.SetLabel(self.animation_button_start_label)

    def go_to_beginning (self, event) :
        """
        <self.go_beginnign_button> was clicked
        """
        self.frame_number.SetValue (0)  
        self.draw_curent_frame()

    def go_to_end (self, event) :
        """
        <self.go_end_button> was clicked
        """
        self.frame_number.SetValue (len(self.frame_names)-1)
        self.draw_curent_frame()

if __name__ == '__main__' :

    import sys
    app.Create()

    # Loading files
    if len(sys.argv) <> 2 :
        openFileDialog = wx.FileDialog(None, "Open HDF5 file to load 3D Dirac", "", "",
                                       "HDF5 files (*.hdf5)|*.hdf5", wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_CHANGE_DIR)
        # Check whether user canceled
        if openFileDialog.ShowModal() == wx.ID_CANCEL:
            print "Error:  file name is  needed as argument"
            exit()
        else : filename = openFileDialog.GetPath()  

    else : filename = sys.argv[1]

    CPlot3D (None, filename)
    app.Run ()

【问题讨论】:

    标签: python python-2.7 wxwidgets


    【解决方案1】:

    当您手动调用On_animation_button() 时,您的框架实际上还没有显示,即使您在其上调用了Show(),因为至少在X11 中,显示是异步发生的。所以你需要延迟调用它直到以后。这可以通过例如将执行此操作的 lambda 绑定到 EVT_SIZE 事件(因为在您获取它时,窗口已经初始化)或仅使用 CallAfter()

    【讨论】:

    • 感谢您的评论。但由于我仍然不熟悉这一切,我实际上并不知道如何在我的代码中使用 CallAfter() 函数。你能通过编辑代码来展示如何吗?谢谢
    • CallAfter() 只需要调用函数,参见the wiki page 所以CallAfter(self.On_animation_button) 应该这样做。
    猜你喜欢
    • 2010-09-18
    • 1970-01-01
    • 2011-01-23
    • 1970-01-01
    • 1970-01-01
    • 2015-04-19
    • 1970-01-01
    • 2012-10-14
    • 1970-01-01
    相关资源
    最近更新 更多