6

私は Tkinter と ttk を使用して GUI を構築し、インタラクティブなプロットを作成するために matplotlib を使用しています。これまでに遭遇したほとんどの問題は十分に文書化されていますが、これはまれなようです:

3D でプロットし、後でコマンドで軸スケールを調整するとset_lim()、プロットされた線が座標系を超えて見栄えがよくありません。また、フレームが少し小さすぎて不満です。次に例を示します。

# Missmatch.py
"""Graphical User Interface for plotting the results
calculated in the script in Octave"""

# importing libraries
import matplotlib, ttk, threading
matplotlib.use('TkAgg')
import numpy as nm
import scipy as sc
import pylab as pl
import decimal as dc
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
from mpl_toolkits.mplot3d import Axes3D
from oct2py import octave as oc
import Tkinter as tki

class CS:
    """CS - Controlset. This part creates the GUI with all important
    Elements. Major changes and calculations will be executed 
    in the Calculation-Class in a seperate thread. This prevents the 
    GUI from hanging"""

    def __init__(self,parent):
        """Building the main GUI"""
        self.ThisParent=parent
        ### Entire Window
        # Mainframe that contains everything.
        self.main=tki.Frame(parent) 
        # Pack manager to expand the mainframe as the windowsize changes.
        self.main.pack(fill=tki.BOTH, expand=tki.YES)
        # Configure the grid of the mainframe so that only the top left
        # cell grows if the users expands the window.
        self.main.grid_rowconfigure(0, weight=1)
        self.main.grid_rowconfigure(1, weight=1)


        ### Canvas for drawings
        # Creating a figure of desired size
        self.f = Figure(figsize=(6,6), dpi=100)
        # Creating a canvas that lives inside the figure
        self.Paper=FigureCanvasTkAgg(self.f, master=self.main)
        # Making the canvas's drawings visible (updating)
        self.Paper.show()
        # positioning the canvas
        self.Paper.get_tk_widget().grid(row=0,rowspan=3, column=0, sticky='NSWE')
        # creating a toolbarframe for options regarding the plots
        self.toolbarframe=tki.Frame(self.main)
        self.toolbarframe.grid(row=3, column=0, sticky='NWE')
        # Creating a toolbar for saving, zooming etc. (matplotlib standard)
        self.toolbar = NavigationToolbar2TkAgg(self.Paper, self.toolbarframe)
        self.toolbar.grid(row=0,column=0, sticky='NWE')
        # setting the standard option on zoom
        self.toolbar.zoom()



        ### Axis configuration toolbar
        # A frame containing the axis config-menu
        self.axisscaleframe=tki.Frame(self.main)
        self.axisscaleframe.grid(row=5, column=0, sticky='SNEW')
        # In that Frame, some Entry-boxes to specify scale
        self.xaxisscalef=ttk.Entry(self.axisscaleframe, width=10)
        self.xaxisscalef.insert(0,0)
        self.xaxisscalet=ttk.Entry(self.axisscaleframe, width=10)
        self.xaxisscalet.insert(0,15)
        self.yaxisscalef=ttk.Entry(self.axisscaleframe, width=10)
        self.yaxisscalef.insert(0,0)
        self.yaxisscalet=ttk.Entry(self.axisscaleframe, width=10)
        self.yaxisscalet.insert(0,15)
        self.zaxisscalef=ttk.Entry(self.axisscaleframe, width=10)
        self.zaxisscalef.insert(0,0)
        self.zaxisscalet=ttk.Entry(self.axisscaleframe, width=10)
        self.zaxisscalet.insert(0,15)
        # And some Labels so we know what the boxes are for
        self.xaxlab=ttk.Label(self.axisscaleframe, text='X-Axis', width=10)
        self.yaxlab=ttk.Label(self.axisscaleframe, text='Y-Axis', width=10)
        self.zaxlab=ttk.Label(self.axisscaleframe, text='Z-Axis', width=10)
        self.axinfolab=ttk.Label(self.axisscaleframe, text='Adjust axis scale:')
        # And a Button to validate the desired configuration
        self.scaleset=ttk.Button(self.axisscaleframe, text='Set', command=self.SetAxis2)
        self.scaleset.bind('<Return>', self.SetAxis)
        # Let's organize all this in the axisscaleframe-grid
        self.axinfolab.grid(row=0, column=0, sticky='W')
        self.xaxlab.grid(row=1, column=0, sticky='W')
        self.yaxlab.grid(row=2, column=0, sticky='W')
        self.zaxlab.grid(row=3, column=0, sticky='W')
        self.xaxisscalef.grid(row=1,column=1, sticky='W')
        self.yaxisscalef.grid(row=2,column=1, sticky='W')
        self.xaxisscalet.grid(row=1,column=2, sticky='W')
        self.yaxisscalet.grid(row=2,column=2, sticky='W')
        self.zaxisscalef.grid(row=3,column=1,sticky='W')
        self.zaxisscalet.grid(row=3,column=2,sticky='W')
        self.scaleset.grid(row=3,column=3,sticky='E')


    def SetAxis(self,event):
        self.SetAxis2()

    def SetAxis2(self):
        self.x1=float(self.xaxisscalef.get())
        self.x2=float(self.xaxisscalet.get())
        self.y1=float(self.yaxisscalef.get())
        self.y2=float(self.yaxisscalet.get())
        self.z1=float(self.zaxisscalef.get())
        self.z2=float(self.zaxisscalet.get())
        self.a.set_xlim(self.x1, self.x2)
        self.a.set_ylim(self.y1, self.y2)
        self.a.set_zlim(self.z1, self.z2)
        self.Paper.show()
        print "Set axis"



class Calculate3D(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        self.x=range(100)
        self.y=range(100)
        self.z=range(100)
        print 'Done!'
        controlset.a = controlset.f.add_subplot(111, projection='3d')
        controlset.a.clear()
        controlset.a.plot(self.x,self.y,self.z)
        controlset.a.mouse_init()
        controlset.a.set_xlabel('X')
        controlset.a.set_ylabel('Y')
        controlset.a.set_zlabel('Z')
        controlset.a.set_title('Title')
        controlset.Paper.show()
        return


mainw=tki.Tk()
mainw.title("Example")
mainw.geometry('+10+10')
controlset=CS(mainw) 
#for this example code, we run our Calculate3D class automatically
CL=Calculate3D()
CL.run()

mainw.mainloop()

コードを実行し、「SET」ボタンを押すだけです。私の問題があります。

編集:スクリーンショットを追加: ここに画像の説明を入力

4

2 に答える 2

3

ここでの問題は、mplot3d に OpenGL バックエンドがないことです。したがって、データを表示するための計算は 2d に基づいています。ここで同じ問題を見つけ、ここで回避策を見つけまし。データの解像度に依存するため、回避策は私の意見では最善ではありませんが。

とにかく、2番目のリンクをたどりました。したがって、私が今行っているのは、配列をコピーし、目的のスケールの上と下のすべての値を NaN に設定することです。それらをプロットすると、データポイントが目的の制限を超える場所で線が切り取られます。

def SetAxis2(self):
    self.dummyx=CL.x*1
    self.dummyy=CL.y*1
    self.dummyz=CL.z*1
    #clipping manually
    for i in nm.arange(len(self.dummyx)):
        if self.dummyx[i] < self.x1:
            self.dummyx[i] = nm.NaN
        else:
            pass

    for i in nm.arange(len(self.dummyy)):
        if self.dummyy[i] < self.y1:
            self.dummyy[i] = nm.NaN
        else:
            pass

    for i in nm.arange(len(self.dummyz)):
        if self.dummyz[i] < self.z1:
            self.dummyz[i] = nm.NaN
        else:
            pass     

    controlset.a.plot(self.dummyx,\
    self.dummyy,\
    self.dummyz)

    self.a.set_xlim3d(self.x1, self.x2)
    self.a.set_ylim3d(self.y1, self.y2)
    self.a.set_zlim3d(self.z1, self.z2)

スケールが 0 から 10 に設定され、6 つ[-1, 3 4 12 5 1]のデータポイントがある場合: -1 と 12 が NaN に設定されるため、線は 3 から 4 および 5 から 1 になります。その問題に関する改善は良いでしょう。 Mayaviの方が良いかもしれませんが、matplotlibに固執したかったので、これは試していません。

于 2013-04-23T11:11:59.783 に答える