Unable to display panel at the desired position - python-2.7

I created a Panel in a wxFrame and then created a FigureCanvas. I would like to fit the FigureCanvas into the panel completely, but somehow the FigureCanvas does not go into the panel2_2, but exactly on just the opposite side.
Following is my code.
import wx
from numpy import arange, sin, pi
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
class Frame1(wx.Frame):
def __init__(self, prnt):
wx.Frame.__init__(self, parent=prnt,
pos=wx.Point(0, 0), size=wx.Size(1340, 720),
style=wx.DEFAULT_FRAME_STYLE)
self.panel2_2 = wx.Panel(parent=self,
pos=wx.Point(940, 30), size=wx.Size(400, 690),
style=wx.TAB_TRAVERSAL)
self.figure = Figure()
self.axes = self.figure.add_subplot(111)
self.canvas = FigureCanvas(self.panel2_2, -1, self.figure)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.canvas, 0, wx.EXPAND)
self.panel2_2.SetSizer(sizer)
self.panel2_2.Fit()
t = arange(0.0, 3.0, 0.01)
s = sin(2 * pi * t)
self.axes.plot(t, s)
#Every wxWidgets application must have a class derived from wxApp
class MyApp(wx.App):
# wxWidgets calls this method to initialize the application
def OnInit(self):
# Create an instance of our customized Frame class
self.frame = Frame1(None)
self.SetTopWindow(self.frame)
self.frame.Show()
return True
if __name__ == '__main__':
application = MyApp(0)
application.MainLoop()
and the result
I would like to have the image on the panel2_2 ( that is on the right hand side ) and not on the left hand side

I think the canvas is indeed going to panel2_2. The problem in your MWE is that you do not define a sizer for panel2_2. Therefore, panel2_2 is rendered from the upper left corner of the frame. This results in panel2_2 plus the canvas showing in the left of the frame. What you see to the right of the canvas is not panel2_2 but the rest of the frame since the size of the frame is larger than the size of panel2_2. If you add a blue panel1_1 and assign another wx.BoxSizer to the frame you get the canvas showing to the right.
import wx
from numpy import arange, sin, pi
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
class Frame1(wx.Frame):
def __init__(self, prnt):
wx.Frame.__init__(self, parent=prnt,
pos=wx.Point(0, 0), size=wx.Size(1340, 720),
style=wx.DEFAULT_FRAME_STYLE)
self.panel1_1 = wx.Panel(parent=self, size=(400, 690))
self.panel1_1.SetBackgroundColour('blue')
self.panel2_2 = wx.Panel(parent=self,
pos=wx.Point(940, 30), size=wx.Size(400, 690),
style=wx.TAB_TRAVERSAL)
self.figure = Figure()
self.axes = self.figure.add_subplot(111)
self.canvas = FigureCanvas(self.panel2_2, -1, self.figure)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.canvas, 0, wx.EXPAND)
self.panel2_2.SetSizer(sizer)
self.panel2_2.Fit()
sizerPanels = wx.BoxSizer(wx.HORIZONTAL)
sizerPanels.Add(self.panel1_1)
sizerPanels.Add(self.panel2_2)
sizerPanels.Fit(self)
self.SetSizer(sizerPanels)
t = arange(0.0, 3.0, 0.01)
s = sin(2 * pi * t)
self.axes.plot(t, s)
self.Center()
#Every wxWidgets application must have a class derived from wxApp
class MyApp(wx.App):
# wxWidgets calls this method to initialize the application
def OnInit(self):
# Create an instance of our customized Frame class
self.frame = Frame1(None)
self.SetTopWindow(self.frame)
self.frame.Show()
return True
if __name__ == '__main__':
application = MyApp(0)
application.MainLoop()

Related

Tkinter remove stored file from memory

from Tkinter import *
import Tkinter as tk
import ttk
import tkFileDialog
import numpy as np
import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
class Look():
def __init__(self, master):
self.master = master
self.master.title("Demo")
self.master.configure(background = "grey91") #the color will be changed later
self.master.minsize(500, 300) # width + height
self.master.resizable(False, False)
self.top_frame = ttk.Frame(self.master, padding = (10, 10))
self.top_frame.pack()
ttk.Button(self.top_frame, text = "Load file", command = self.load_file,
style = "TButton").pack()
ttk.Button(self.top_frame, text = "Reset", command = self.clear_file,
style = "TButton").pack()
ttk.Button(self.top_frame, text = "Plot", command = self.plot_file,
style = "TButton").pack()
self.bottom_frame = ttk.Frame(self.master, padding = (10, 10))
self.bottom_frame.pack()
self.fig = plt.figure(figsize=(12, 5), dpi=100) ##create a figure; modify the size here
self.fig.add_subplot()
plt.title("blah")
self.canvas = FigureCanvasTkAgg(self.fig, master = self.bottom_frame)
self.canvas.show()
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.bottom_frame)
self.toolbar.update()
self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
def load_file(self):
self.file = tkFileDialog.askopenfilename(defaultextension = ".txt", filetypes = [("Text Documents", "*.txt")])
def clear_file(self):
self.fig.clf()
self.fig.add_subplot()
plt.xticks()
plt.yticks()
self.canvas.draw()
def plot_file(self):
self.r, self.g = np.loadtxt(self.file).transpose()
self.fig.clf()
plt.plot(self.r, self.g)
self.canvas.show()
def main():
root = Tk()
GUI = Look(root)
root.mainloop()
if __name__ == "__main__": main()
The code above creates a program has three buttons. The Load file buttom loads a txt file, Reset button is supposed to clear the plot and delete the file just loaded into the memory. Plot button is to plot the figure onto canvas below.
I have a question about how to write function associated with Reset function, i.e. clear_file function. Currently what it does is just clear the plot from canvas. But it seems the file that has been loaded to plot is stored in memory, since click again Plot, it will display the plot. My goal is to use Reset button to bring it to a fresh start--nothing stored in memory. I know loading a new file will overwrite the previous file. But when there are multiple buttons for loading different files, the situations could become complicated. Therefore I hope Reset can do the job.
If you want to try this little program, you may create a simple txt with two column data to be loaded into the program.
Thanks.
I would make 2 changes. Move the code that sets up your plot into its own method and reset the frame each time the method is called. This can be done with destroying the frame and remaking it. The 2nd change I would change the command on your reset to reference this new method.
Taking your code this is what I would change to be able to reset the plot.
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import filedialog
import numpy as np
import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
class Look():
def __init__(self, master):
self.master = master
self.master.title("Demo")
self.master.configure(background = "grey91") #the color will be changed later
self.master.minsize(500, 300) # width + height
self.master.resizable(False, False)
self.top_frame = ttk.Frame(self.master, padding = (10, 10))
self.top_frame.pack()
ttk.Button(self.top_frame, text = "Load file", command = self.load_file,style = "TButton").pack()
ttk.Button(self.top_frame, text = "Reset", command = self.new_plot,style = "TButton").pack()
ttk.Button(self.top_frame, text = "Plot", command = self.plot_file,style = "TButton").pack()
self.bottom_frame = ttk.Frame(self.master, padding = (10, 10))
self.bottom_frame.pack()
self.new_plot()
# this function will reset your plot with a fresh one.
def new_plot(self):
self.bottom_frame.destroy()
self.bottom_frame = ttk.Frame(self.master, padding = (10, 10))
self.bottom_frame.pack()
self.fig = plt.figure(figsize=(12, 5), dpi=100) ##create a figure; modify the size here
self.fig.add_subplot()
plt.title("blah")
self.canvas = FigureCanvasTkAgg(self.fig, master = self.bottom_frame)
self.canvas.show()
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.bottom_frame)
self.toolbar.update()
self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
def load_file(self):
self.file = filedialog.askopenfilename(defaultextension = ".txt", filetypes = [("Text Documents", "*.txt")])
def clear_file(self):
self.fig.clf()
self.fig.add_subplot()
plt.xticks()
plt.yticks()
self.canvas.draw()
def plot_file(self):
self.r, self.g = np.loadtxt(self.file).transpose()
self.fig.clf()
plt.plot(self.r, self.g)
self.canvas.show()
if __name__ == "__main__":
root = tk.Tk()
GUI = Look(root)
root.mainloop()

how to insert buttons on the west side an Image file on the East Side or simply as a background using Tk

Here is my script
# Python 2.7.14 version
from Tkinter import *
import Tkinter
import tkMessageBox
from urllib2 import urlopen
import PIL
from PIL import ImageTk
import ImageTk
FILENAME = 'Fleur_de_lys.jpg'
root = Tk()
background = Canvas(root, width=250, height=250)##AttributeError: class Tk has no attribute 'Canvas'
canvas.pack()
tk_img = ImageTk.PhotoImage( file = FILENAME)
canvas.create_image(125, 125, image=tk_img)
quit_button = tk.Button(root, text = "Quit", command = root.quit, anchor = 'w',
width = 10, activebackground = "#33B5E5")
quit_button_window = canvas.create_window(10, 10, anchor='nw', window=quit_button)
root.mainloop()
No matter what attempt I do I keep getting AttributeError: class Tk has no attribute 'Canvas' where is my error if I just create button I have no issue what so ever all work but when I attempt to have a background image everything does not work
The problem appears to be that you're creating a canvas, and storing it in a variable named background, yet the very next line you are trying to call something called 'canvas', which you've never created.
Change this:
background = Canvas(root, width=250, height=250)
canvas.pack()
...
canvas.create_image(125, 125, image=tk_img)
to this:
background = Canvas(root, width=250, height=250)
background.pack()
...
background.create_image(125, 125, image=tk_img)
I fixed the issue jpg image was not being accepted I made it with a gif. Also found how to correct the buttons location and posn.
Here is the example without all the program
canvas = Canvas(root, width = 500, height = 500, bg='black')
canvas.pack(expand=YES, fill=BOTH)
my_image = PhotoImage(file='C:\\MOTD\\fleur_de_lys.gif')
canvas.create_image(0, 0, anchor = NW, image=my_image)
b1 = Button(root, text="From the Commander", command=callback,anchor = 'w',
width = 18, activebackground = "#33B5E5")
button_window1 = canvas.create_window(10, 10, anchor='nw', window=b1)

Image does not display in tkinter Canvas

I am trying to create a new class of Canvas that will be able to display and resize images. However The image does not display. I searched for similar questions and all the answers said to keep a reference of the PhotoImage in the class.( This answer for example). I tried doing that in a number of ways and none worked. In this example I tried saving a reference in a dictionary. I also tried self.tkimage = ImageTk.PhotoImage(image=img) which didn't work. And also tried using globals. I assume it has something to do with the garbage collector, but don't know how to solve.
Please assist.
import Tkinter as tk
from PIL import ImageTk, Image
import numpy as np
# a subclass of Canvas
class MyCanvas(tk.Canvas):
def __init__(self,parent,**kwargs):
tk.Canvas.__init__(self,parent,**kwargs)
self.tkimg = {}
self.images = []
self.image_on_canvas = []
def my_create_image(self, *args, **kw):
img = kw['image']
self.images.append(img)
self.tkimg[img] = ImageTk.PhotoImage(image=img)
kw['image'] = self.tkimg[img]
item = self.create_image(*args, **kw)
self.image_on_canvas.append(item)
def main():
root = tk.Tk()
myframe = tk.Frame(root)
myframe.pack(fill=tk.BOTH, expand=tk.YES)
mycanvas1 = MyCanvas(myframe, width=850, height=400, bg="red", highlightthickness=0)
mycanvas2 = MyCanvas(myframe, width=850, height=400, bg="green", highlightthickness=0)
mycanvas1.pack(side=tk.LEFT, fill=tk.BOTH, expand=tk.YES)
mycanvas2.pack(side=tk.RIGHT, fill=tk.BOTH, expand=tk.YES)
# add some widgets to the canvas
mycanvas2.create_line(0, 100, 200, 0, fill="red", dash=(4, 4))
mycanvas2.create_rectangle(50, 25, 150, 75, fill="blue")
arr1 = np.random.random([256,256])*255
img1 = Image.fromarray(arr1)
mycanvas1.my_create_image(0, 0, image=img1, anchor=tk.NW)
root.mainloop()
if __name__ == "__main__":
main()

Obtaining matplotlib slider widget position from callback in non-global context

I wanted to use the matplotlib slider as seen in an example from a previous question (below) inside a GUI window (such as TkInter etc). But, in a non-global context, the variables for the plot ("spos, fig, ax") are not defined. My understanding is that because update is used as a callback function, one can't or shouldn't pass arguments.
If so, how can a plot be updated without global variables? or
How can I obtain the slider position outside the callback function?
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)
t = np.arange(0.0, 100.0, 0.1)
s = np.sin(2*np.pi*t)
l, = plt.plot(t,s)
plt.axis([0, 10, -1, 1])
axcolor = 'lightgoldenrodyellow'
axpos = plt.axes([0.2, 0.1, 0.65, 0.03], axisbg=axcolor)
spos = Slider(axpos, 'Pos', 0.1, 90.0)
def update(val):
pos = spos.val
ax.axis([pos,pos+10,-1,1])
fig.canvas.draw_idle()
spos.on_changed(update)
plt.show()
Related:
1) Another related question seems to cover this topic but does not seem to address how the position of the slider is obtained.
2) A similar question was asked and solved with Slider.set_val(). It seems in my case I would need Slider.get_val() instead.
It is possible to pass more arguments to the callback function, for example with functools.partial
def update(data, val):
pos = spos.val
ax.axis([pos,pos+10,-1,1])
fig.canvas.draw_idle()
data['position'] = pos
import functools
data = dict()
spos.on_changed(functools.partial(update, data))
plt.show()
try:
print data['position']
except KeyError:
pass
A class with __call__ method could also be used as a callback.

How to hide or cut a Qwidget() text when I change main window size

EDIT: When I change the main window size, I need cut the text of QLabel() that includes in QStatusBar() to fit the size of the form. As shown in the diagram below.
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class MyMainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setCentralWidget(QLabel("main widget"))
statusBar = QStatusBar()
self.setStatusBar(statusBar)
statusBar.addWidget(QLabel("first message"))
statusBar.addWidget(QLabel("second message"))
statusBar.addWidget(QLabel("a thrid long long long long long message"))
app = QApplication(sys.argv)
window = MyMainWindow()
window.show()
sys.exit(app.exec_())
The key to this is to set an appropriate minimum width on the labels, which will then allow them to resize smaller than the width of their text. However, this will simply crop the text on the right, rather eliding it (i.e. so that ... appears at the end).
The blog post Status bar and elided label explains how to get elided text, but the solution is written in C++. Below is an equivalent version written in PyQt4:
import sys
from PyQt4 import QtCore, QtGui
class ElidedLabel(QtGui.QLabel):
_width = _text = _elided = None
def __init__(self, text='', width=40, parent=None):
super(ElidedLabel, self).__init__(text, parent)
self.setMinimumWidth(width if width > 0 else 1)
def elidedText(self):
return self._elided or ''
def paintEvent(self, event):
painter = QtGui.QPainter(self)
self.drawFrame(painter)
margin = self.margin()
rect = self.contentsRect()
rect.adjust(margin, margin, -margin, -margin)
text = self.text()
width = rect.width()
if text != self._text or width != self._width:
self._text = text
self._width = width
self._elided = self.fontMetrics().elidedText(
text, QtCore.Qt.ElideRight, width)
option = QtGui.QStyleOption()
option.initFrom(self)
self.style().drawItemText(
painter, rect, self.alignment(), option.palette,
self.isEnabled(), self._elided, self.foregroundRole())
class MyMainWindow(QtGui.QMainWindow):
def __init__(self):
super(QtGui.QMainWindow, self).__init__()
self.setCentralWidget(QtGui.QLabel("main widget"))
statusBar = QtGui.QStatusBar()
self.setStatusBar(statusBar)
statusBar.addWidget(ElidedLabel("first message"))
statusBar.addWidget(ElidedLabel("second message"))
statusBar.addWidget(ElidedLabel("a third long long long long long message"))
app = QtGui.QApplication(sys.argv)
window = MyMainWindow()
window.show()
sys.exit(app.exec_())