Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
557 views
in Technique[技术] by (71.8m points)

python - set_xlim,set_ylim,set_zlim commands in matplotlib fail to clip displayed data

I'm building a GUI with Tkinter and ttk and using matplotlib in order to creat interactive plots - again, like millions other people do. Even though most problems I encountered so far are well documented, this one seems rare:

When plotting in 3d and adjusting the axis scale with set_lim() commands afterwards, the plotted line exceeds the coordinate-system which looks not good. Also, I'm not happy with the frame that seems to be a little to small. Here is an example:

# 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()

Just run the code, and hit the "SET" Button. There is my problem.

Edit: Added Screenshot: enter image description here

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The Problem here is, that mplot3d has no OpenGL backend. The calculations for displaying the data are thus based on 2d. I found the same issue here and a workaround here. Even though the workaround is not the best in my opinion because it depends on the resolution of your data.

I followed the second link anyway. So, what I'm doing now is copying the array and setting all the values above and under my desired scale to NaN. When plotting those, the lines will be cut off where the datapoints exceed the desired limit.

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)

If now your scale is set from 0 to 10 and you have six datapoints: [-1, 3 4 12 5 1] The line will go from 3 to 4 and 5 to 1 because -1 and 12 will be set to NaN. An improvement regarding that problem would be good. Mayavi might be better, but I haven't tried this as I wanted to stick with matplotlib.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...