This is my first time creating a GUI using Tkinter to simulate a DSP setup. I'm stuck.
This GUI requires multiple scales. Therefore I wrote a generic scale function.
# Overlap percent scale
def overlap_percent():
print("Testing")
# op=var.get()
# olive_features['overlap_perc']=op
# generic scale function
def create_scale(self,parent,xval,yval,start,end,resolution,orient,default,lng,clr,cmdtrig):
OHA_scale = tk.Scale(parent,resolution=resolution, from_=start, to=end, orient=orient,length=lng,fg=clr,command=cmdtrig)
OHA_scale.grid(row=xval, column=yval, sticky=tk.E + tk.W + tk.N + tk.S, padx=20, pady=4)
OHA_scale.set(default)
# Overlap %
yval=yval+2
xval=1
self.create_label(Oliveframe,xval,yval,"Overlap %")
xval=3
self.create_scale(Oliveframe,xval,yval,25,75,25,"vertical",75,90,'Black',"overlap_percent")
xval=1
yval=yval+1
self.create_arrow(Oliveframe,xval,yval)
Based on the code above, i figured it would print 'Testing' on the cmd line, when i adjust the Overlap scale. Nothing happened. To test the code, i replaced the command in generic scale to
def create_scale(self,parent,xval,yval,start,end,resolution,orient,default,lng,clr,cmdtrig):
OHA_scale = tk.Scale(parent,resolution=resolution, from_=start, to=end, orient=orient,length=lng,fg=clr,command=overlap_percent)
This resulted in an error.
OHA_scale = tk.Scale(parent,resolution=resolution, from_=start, to=end, orient=orient,length=lng,fg=clr,command=overlap_percent)
NameError: name 'overlap_percent' is not defined
I can't quite figure out what I'm doing wrong. How exactly can i use the generic scale function to control multiple scales?
on this line
OHA_scale = tk.Scale(parent,resolution=resolution, from_=start, to=end,
orient=orient,length=lng,fg=clr,command=cmdtrig)
command take function parameters but you send a string value
self.create_scale(Oliveframe,xval,yval,25,75,25,"vertical",75,90,'Black',overlap_percent)
If you do it will be alright
Related
I've encountered something very strange when having a function which generates an NdOverlay of Points to a DynamicMap, where the function is tied to panel widgets (I don't think the panel widgets are important).
The below code is a working example which produces the expected behavior. Whenever you change the widget values a new plot is generated with two sets of Points overlaid, with different colors and respective legend entries. Image shown below code.
a_widget = pn.widgets.Select(name='A', options=[1,2,3,4])
b_widget = pn.widgets.IntSlider(name='B', start=10, end=20, value=10)
widget_box = pn.WidgetBox(a_widget, b_widget, align='center')
#pn.depends(a=a_widget.param.value, b=b_widget.param.value)
def get_points(a, b):
return hv.NdOverlay({x: hv.Points(np.random.rand(10,10)) for x in range(1,3)})
points = hv.DynamicMap(get_points)
pn.Row(widget_box, points)
The second example shown below, is meant to demonstrate that in certain situations you might want to just simply return an empty plot and the way that I've done it in this example is done in the same way as in this example: http://holoviews.org/gallery/demos/bokeh/box_draw_roi_editor.html#bokeh-gallery-box-draw-roi-editor
The result of this code is an empty plot as expected when a == 1, but when a has values other than 1, the result is quite strange as illustrated in the image below the code.
The points all have the same color
When changing the slider for instance, some points are frozen and never changes, which is not the case in the above working example.
a_widget = pn.widgets.Select(name='A', options=[1,2,3,4])
b_widget = pn.widgets.IntSlider(name='B', start=10, end=20, value=10)
widget_box = pn.WidgetBox(a_widget, b_widget, align='center')
#pn.depends(a=a_widget.param.value, b=b_widget.param.value)
def get_points(a, b):
if a == 1:
return hv.NdOverlay({None: hv.Points([])})
else:
return hv.NdOverlay({x: hv.Points(np.random.rand(10,10)) for x in range(1,3)})
points = hv.DynamicMap(get_points)
pn.Row(widget_box, points)
While I can not help the observed issue with NdOverlay, creating plots with or without content can be done with the help of Overlay.
As b_widget is never used in your code, I removed it for simplicity.
a_widget = pn.widgets.Select(name='A', options=[1,2,3,4])
widget_box = pn.WidgetBox(a_widget, align='center')
#pn.depends(a=a_widget.param.value)
def get_points(a):
images = []
if a == 3:
images.append(hv.Points(np.random.rand(10,10), label='None'))
else:
for x in range(1,3):
images.append(hv.Points(np.random.rand(10,10), label=str(x)))
return hv.Overlay(images)
points = hv.DynamicMap(get_points)
pn.Row(widget_box, points)
The way how to use NdOverlay that is described in the documentation for NdOverlay is different to your approach, this might be a reason for the observed problems.
Anyway, to narrow down which part of the code is responsible for the observed issue, I removed all code that is not necessary to reproduce it.
For clarity, I renamed the values of a, and I also made sure, that a start value for a is provided.
It turned out while testing the code, that the if-else-statement is neither important, so I removed that too.
And just to make sure, that variables behave like expected, I added some print-statements.
This gives the following minimal reproducable example:
a_widget = pn.widgets.Select(name='A', value='Test', options=['Test','Test1', 'Test2'])
#pn.depends(a=a_widget.param.value)
def get_points(a):
dict_ = {}
dict_[str(a)] = hv.Points(np.random.rand(10,10))
print(dict_)
overlay = hv.NdOverlay(dict_)
print(overlay)
return overlay
points = hv.DynamicMap(get_points)
# using the server approach here to see the outpout of the
# print-statements
app = pn.Row(a_widget, points)
app.app()
When running this code, and choosing the different options in the select widget, it turns out that option Test is not updated, once one of the options Test1 and Test3 have been choosen.
When we change the default value in the first line like this
a_widget = pn.widgets.Select(name='A', value='Test2', options=['Test','Test1', 'Test2'])
now Test2 is not updated correctly.
So it looks like this is an issue of DynamicMap using NdOverlay.
So I suggest you report this issue to the developers (if not already done), either wait for new release or use a different approach (e.g. as shown above).
I'm developening an Abaqus/CAE plug-in, in this plug-in i'm using the gui toolkit, and i have a button that uses the PickStep, on click the button i can select a PartInstance in the viewport.
Then i want to export the selected PartInstance to an .obj file but when i try it, abaqus displays an error.
This is an example of my PICK BUTTON:
# PICK BUTTON 1
pickHf = FXHorizontalFrame(p=col2, opts=0, x=0, y=0, w=0, h=0, pl=0, pr=0, pt=0, pb=0, hs=DEFAULT_SPACING,
vs=DEFAULT_SPACING)
# Note: Set the selector to indicate that this widget should not be
# colored differently from its parent when the 'Color layout managers'
# button is checked in the RSG Dialog Builder dialog.
pickHf.setSelector(99)
label1 = FXLabel(p=pickHf, text='' + ' (None)', ic=None, opts=LAYOUT_CENTER_Y | JUSTIFY_LEFT)
pickHandler1 = DBPickHandler(form, form.uper, 'Select a 3D, discrete and dependent meshed instance', INSTANCES,
1, label1)
icon = afxGetIcon('select', AFX_ICON_SMALL)
FXButton(p=pickHf, text='\tPick Items in Viewport', ic=icon, tgt=pickHandler1, sel=AFXMode.ID_ACTIVATE,
opts=BUTTON_NORMAL | LAYOUT_CENTER_Y, x=0, y=0, w=0, h=0, pl=2, pr=2, pt=1, pb=1)
I save the value in an ObjectKeyword:
self.uper = AFXObjectKeyword(self.cmd, 'uper', True, pickedDefault)
This is how i export the PartInstance to .obj:
print 'Uper - ' + uper[0].name
f.write('Uper - '+uper[0].name+'\n')
session.writeOBJFile(fileName='C:/temp/Uper.obj', canvasObjects=(uper[0]))
That displays and error, and i also tried this:
print 'Fixed - ' + fixed[0].name
f.write(fixed[0].name+'\n')
fixedobj = open('Fixed.obj', 'w')
pickle.dump(fixed[0], fixedobj)
fixedobj.close()
But that does not work either.
I get this error:
canvasObjects;found PartInstance, expecting tuple
This answer will help you. On your call to session.writeOBJFile you are trying to create a one element tuple for the canvasObjects argument. Simply wrapping the item in parentheses won't achieve that. You need to add a comma to make it a tuple:
session.writeOBJFile(fileName='C:/temp/Uper.obj', canvasObjects=(uper[0],))
The Abaqus documentation says this about canvasObjects:
canvasObjects
A sequence of canvas objects to export.
I'm not sure if PartInstance is considered a canvas object or not, but you may still have problems even after correcting the argument to be a tuple. If so, make sure the items of the tuple are proper canvas objects.
I'm working with Python 2.6.5, and TKinter.TkVersion 8.5
Here is a MWE of the buggy behavior :
import Tkinter as tk
root = tk.Tk()
classic_var = tk.IntVar()
classic_var.set(2)
classic_spinbox = tk.Spinbox(root, from_=0, to=3,textvariable=classic_var)
classic_spinbox.pack()
values_var = tk.IntVar()
values_var.set(2)
values_spinbox = tk.Spinbox(root, values=(0, 1, 2, 3), textvariable=values_var)
values_spinbox.pack()
print classic_var.get() #expected : 2, actual : 2
print values_var.get() #expected : 2, actual : 0
root.mainloop()
I would expect for value_var to be "2" even after the Spinbox initialization.
Here you can see a screenshot of the result :
Is it a known bug ? Is there a workaround other than this ?
initial_value = 2
values_var = tk.IntVar()
values_spinbox = tk.Spinbox(root, ...
values_var.set(initial_value)
From testing it myself and from doing some research the best way is to do the workaround you suggested which would be to set the default value after it has initialised.
I found this answer from another user through a google search actually, haha: How can I establish a default String value on a Tkinter Spinbox?
This is intended behaviour actually due to how values is coded. The way values works is that it overrides other arguments in a sense, so it uses the first value you declare in values as the initial value and not your textvariable. I don't believe there is any way to fix this.
For reference: https://www.tcl.tk/man/tcl8.4/TkCmd/spinbox.htm#M22 then click on values and it will explain it.
I have got 2 classes, one that's called MineField and one that's called Options, in the options-class there is scales that i get the values from through a function inside that class, def assign():, the MineField-class have three parameters (w,h,m). I want to assign values to these parameters from the scales in the Options-class. (I use tkinter)
Class Options:
def __init__(self, w, h, m)
...
minorinput = Scale.(...)
mainloop()
...
def assign():
self.width = widthinput.get()
self.height = heightinput.get()
self.minor = minorinput.get()
def main():
ins = Options(0,0,0)
ins.assign()
w = ins.width
h = ins.height
m = ins.minor
game.MineField(w,h,m)
So how do I get these values from the scales into game.MineField?
Your code is highly unusual. In essence, you can't do what you are asking to do. At least, not in the way you're trying to do it.
Are you aware that once you call mainloop, the remainder of your code after that statement won't run until you destroy your window? Once the window is destroyed, you can't query the widgets for their values since they don't exist.
I have a program which works fine but when i try to do it with buttons,when i run it,it gives me
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1413, in call
return self.func(*args) File "fire_buttons.py", line 193, in Plot
result=la.Graph(grids) File "fire_buttons.py", line 181, in Graph
n=sc.shape(data)[2] IndexError: tuple index out of range
The function is that:
def Graph(self,data):
"""Make the plot"""
plt.colormaps()
n=sc.shape(data)[2]
ims=[]
for i in range(n):
mydata=data[:,:,i]
im=plt.imshow(mydata,cmap=plt.get_cmap('jet'))
ims.append([im])
return ims
Some code for the buttons:
def createWidgets(self):
"""Add widgets to main frame"""
top_frame=Frame(self)
self.Tree=StringVar()
self.Tree_entry=Entry(top_frame,textvariable=self.Tree)
self.label1=Label(top_frame,text="Probability of existence of a tree")
self.Tree_entry.pack(side='right')
self.label1.pack()
top_frame.pack(side=TOP)
......
bottom_frame=Frame(self)
bottom_frame.pack(side=TOP)
self.QUIT=Button(bottom_frame,text='Quit',command=self.quit)
self.QUIT.pack(side=LEFT)
self.operate=Button(bottom_frame,text='Run',command=self.Plot)
self.operate.pack(side=LEFT)
def Plot(self):
if (self.area.get().isdigit() and p.match(self.Tree.get()) and p.match(self.Burning.get()) and p.match(self.Lighting.get()) and p.match(self.ResistBurn.get()) and p.match(self.RegenerateTree.get()) and self.time_step.get().isdigit()):
la=myfire()
grids=la.fire(int(self.area.get()),float(self.Tree.get()),float(self.Burning.get()),float(self.Lighting.get()),float(self.ResistBurn.get()),float(self.RegenerateTree.get()),int(self.time_step.get()))
result=la.Graph(grids)
fig=plt.gcf()
ArtistAnimation(fig,result,interval=10,repeat=False)
plt.show()
Also,if i want to use slide widget i tried sth like:
self.Tree_entry=Scale(top_frame,from_=0,to=1,orient=HORIZONTAL,length=1000, tickinterval=0.001)
self.Tree_entry.set(40)
I want values from 0 to 1 and increment by 0.0001.But this just gives me 0 and 1 only.
--------------------UPDATE--------------------
In the version without the buttons instead of Plot function i use:
grids=fire(area,Tree,Burning,Lighting,ResistBurn,RegenerateTree,time_step)
result=Graph(grids)
fig=plt.gcf()
ani=ArtistAnimation(fig,result,interval=10,repeat=False)
plt.show()
and it runs fine,so maybe i have sth wrong in the Plot?
Your first question might be answered by getting the size of grids, prior to using it in the la.Graph(grids) line of code. Perhaps it's just a tuple with a single item? (Or less than three anyway, since [2] is giving the error.)
EDIT: Your second question needs to=100 I believe. I misread that you wanted to go between 0 and 1. You may be only seeing 0 or 1 since you set the value to 40.
EDIT: The following has been tested.
import tkinter as tk
if __name__ == "__main__":
root = tk.Tk()
tree_entry = tk.Scale(root, from_=0, to=1, resolution=0.001)
tree_entry.pack()
tree_entry.set(0.5)
root.mainloop()
Your error is on this line:
n=sc.shape(data)[2]
From the evidence you've given, this has nothing to do with buttons or widgets in any way. You're simply trying to get element 2 from a tuple but the tuple doesn't have that many elements. You need to find where you define sc.shape(data) and see why it doesn't have as many items as you think it should.