Tkinter: Configure method for labels dynamically generated - python

I am trying to change the labels of my application with the configure method. The Labels are dynamically made in a for loop. Here is part of the code:
# create a list of reference for labels equal to zero
self.lbl_areas = []
for i in range(0, len(self.samples)): # number of labels
lbl=tk.IntVar()
lbl.set(0)
self.lbl_areas.append(tk.Label(self.win,textvariable=lbl))
# Place labels on the application using grid
for i,v in enumerate(self.lbl_areas):
v.grid(row=2+i,column=1,sticky=tk.W)
# Try to change the value
for i in range(0, len(self.samples)):
self.lbl_areas[i].configure(textvariable=lbl_val[i]) # other values
The default zero values are displayed but the configure method seems not to work. What do I do wrong?

There are two ways to update a label after it's been created. The first is to use a textvariable, where you update the variable and the label automatically picks up the change. The second is where you don't use a textvariable, and instead just change the label's text. You're trying to mix the two.
In my opinion, the best way is to not use a textvariable. It's an extra object you need to keep track of which provides no extra benefit (in this case, anyway).
In your case I would write the code like this:
for i in range(0, len(self.samples)): # number of labels
self.lbl_areas.append(tk.Label(self.win,text="0"))
...
for i in range(0, len(self.samples)):
self.lbl_areas[i].configure(text=lbl_val[i])
If you want to use the textvariable attribute, then you need to save a reference to the variable so that you can set it later:
for i in range(0, len(self.samples)): # number of labels
lbl=tk.IntVar()
lbl.set(0)
self.lbl_areas.append(tk.Label(self.win,textvariable=lbl))
self.lbl_vars.append(lbl)
...
for i in range(0, len(self.samples)):
self.lbl_vars[i].set(lbl_val[i])
Notice that in both cases, you must call a function (configure or set) to change the value. You either call it on the widget (widget.configure(...)) or on the variable (var.set(...)). Unless you're taking advantage of the special properties of a tkinter variable -- such as sharing the variable between two or more widgets, or using variable traces -- your code will be less complicated without the textvariable.

Related

Python bokeh modify axis scale

How can I modify the y-axis scale at figures and at charts? I want something like this: my_figure.y_range.end = my_figure.y_range.end * 1.3
So I want a bit higher y-axis. Thank you!
Figure uses DataRange1d objects by default, which causes the range to automatically computed. But this happens on the browser, because it takes into account information like glyph extent that are only available at render time. The reason that my_figure.y_range.end * 1.3 does not work is because the "automatic" value of end is not known yet. It is only set automatically inside the browser. You can override the "automatic" behaviour of a DataRange by supplying start and end, but you have to give it an explicit, numeric value that you want, i.e.:
my_figure.y_range.end = 10
Alternatively, DataRange1d models have range_padding property that you can set, which controls the amount of "extra padding" added to the automatically computed bounds. It is described here:
http://docs.bokeh.org/en/latest/docs/reference/models/ranges.html#bokeh.models.ranges.DataRange1d.range_padding
This might accomplish what you want in a different way, but note that it affects both start and end.
Finally, if you'd just like to completely control the range, without having auto ranging at all, you can do this when you create the figure:
p = figure(..., x_range=(10, 20))
This will create a fixed Range1d for the x-axis with start=10 and end=20.

wxpython dynamically referring to widgets (wxformbuilder)

I often find myself in a situation where I want to create a number of wx.StaticTextor some other widget in wxFormbuilder and be able to refer to these dynamically. Say i have a number of statictexts named a0 through a10
How would I go about finding them in code?
One way is to do a list with all the variables in, but it is ugly, and feels inefficient? Maybe not but atleast the code gets cluttered with long lists everywhere.
def updateLabels(self, data):
guiLabels = [self.a0, self.a1, self.a2 ..... ]
for i in range(len(guiLabels)):
guiLabels[i].SetLabel(data[i)
How do you go about fixing this?
Another alternative is to make the guiLabels list when initiating the app. However, I've had some problems with finding them. you have to call GetChildren() on the top window and set a different wx.ID for every StaticText and then go through every element and find this ID you made.. And the formatting when I do this is really off key.. The text gets different background colors and doesnt respect it's alignments and other funky stuff.
Any thoughts on how I can do this?
maybe something like this could work for you:
for x in xrange(10):
name = "a%s" % x # dynamically generating reference names
obj = getattr(self, name) # getting the object reference from the parent object
obj.SetLabel("xyz")

Can I speed optimize the use of GridCellAttr in wxPython's wx.grid.Grid?

I'm making a Windows application using wx.grid.Grid that will handle very large Microsoft Excel documents. Currently it opens a file with 17 columns and 12 000+ rows quite quickly, and I can scroll around smoothly. (This is a virtual table that operates on data from a custom table class.)
Anyway, the problem starts when I use custom grid cell attribute objects, e.g:
grid.SetAttr(row, col, SomeGridCellAttr('#FF0000'))
Once every cell in a row has a custom grid cell attribute, the performance of the grid just goes 99.9% into the toilet. Instead of smooth scrolling around I'm lucky if I get 1 redraw per 3 seconds. I fixed most of these instances by using grid.SetColAttr instead, which restored performance to it's previous smoothness, but there is one case where that won't work. The application iterates over every cell in a column (12 000 cells), performs some processing on the data and applies a custom grid cell attribute based on the results. Once that is done, the grid becomes a sluggish nightmare to work with.
Is there any way of removing this gruesome performance hit and retain the custom cell attributes? I suspect the answer is quite simple to somebody who knows the inner workings of the grid and it's cell attributes.
Thanks.
Setting a cell attribute will add a new GridCellAttr to the list of the GridCellAttrProvider.
As the list grows, looking up a specific attribute for a cell (by iterating through the list and comparing the coordinates) gets slower and slower.
You can try to speed it up by implementing your own PyGridTableBase.SetAttr and GetAttr (using a dict for example):
EDIT: Updated code to allow overwriting attributes and emulate the default implementations attribute ownership.
class MyTable(wx.grid.PyGridTableBase):
atts = {}
def Hash(self,row,col):
#FIXME: assumes a constant number of rows and rows > cols
return col + row * self.GetNumberRows()
def SetAttr(self,attr,row,col):
HASH = self.Hash(row, col)
if HASH in self.atts:
# decrement usage count of existing attr
self.atts[HASH].DecRef()
#assign new attribute
self.atts[HASH] = attr
def GetAttr(self,row,col,kind):
HASH = self.Hash(row, col)
if HASH in self.atts:
attr = self.atts[HASH]
attr.IncRef() # increment reference count
return attr
return None
To allow setting entire rows and columns, you'll also have to implement:
def SetRowAttr(self,attr,row):
for col in range(self.GetNumberCols()):
attr.IncRef() # increment reference count for SetAttr
self.SetAttr(attr,row,col)
attr.DecRef() # attr passed to SetRowAttr no longer needed
def SetColAttr(self,attr,col):
for row in range(self.GetNumberRows()):
attr.IncRef()
self.SetAttr(attr,row,col)
attr.DecRef()
NOTE: when passing a GridCellAttr to Set*Attr(), the default implementation will take ownership of the attribute.
To re-use the same attribute (stored in a class variable for example), you have to either Clone() it or increment its usage count (IncRef())
before passing it to a Set*Attr() method (cloning may increase memory consumption).
The above example lacks proper removal of attributes: SetAttr() could check for a None attr and decrement the ref count at the coordinates specified, then delete the entry from the dict.
SetCol/RowAttr() can be optimized by adding dicts for row and col, similar to SetAttr(). GetAttr() could then check for an existing entry in the row and col dict and merge/override the attribute(s) with the one from the cell dict (that's the principle used by the default implementation). For proper cleanup of the dict(s), call DecRef on every entry before .clear().
Alternatively, you could derive from wx.grid.GridCellAttrProvider and attach it with PyGridTableBase.SetAttrProvider(). This would prevent direct access to the table, however.

Should I use Entry's .get() or its textvariable's for Tkinter in Python?

The code is something like:
myVar = StringVar()
myEntry = Entry(master, textvariable=myVar)
So when I need to retrieve input from myEntry, should I use
myText = myVar.get()
or
myText = myEntry.get()
Is there a better way ? (and why?)
Unless you are doing traces on the StringVars, I say stick with using the get method and don't create StringVars. Using the get method removes complexity -- one less object to maintain and one less object to take up space in memory (multiplied by however many times you use StringVars in your application).
Sure, it's an imperceptible amount of overhead, but all things being equal, the less complex solution is usually the best. Why add a variable that allows you to do what you can already do without the variable?

How are closures implemented?

"Learning Python, 4th Ed." mentions that:
the enclosing scope variable is looked up when the nested functions
are later called..
However, I thought that when a function exits, all of its local references disappear.
def makeActions():
acts = []
for i in range(5): # Tries to remember each i
acts.append(lambda x: i ** x) # All remember same last i!
return acts
makeActions()[n] is the same for every n because the variable i is somehow looked up at call time. How does Python look up this variable? Shouldn't it not exist at all because makeActions has already exited? Why doesn't Python do what the code intuitively suggests, and define each function by replacing i with its current value within the for loop as the loop is running?
I think it's pretty obvious what happens when you think of i as a name not some sort of value. Your lambda function does something like "take x: look up the value of i, calculate i**x" ... so when you actually run the function, it looks up i just then so i is 4.
You can also use the current number, but you have to make Python bind it to another name:
def makeActions():
def make_lambda( j ):
return lambda x: j * x # the j here is still a name, but now it wont change anymore
acts = []
for i in range(5):
# now you're pushing the current i as a value to another scope and
# bind it there, under a new name
acts.append(make_lambda(i))
return acts
It might seem confusing, because you often get taught that a variable and it's value are the same thing -- which is true, but only in languages that actually use variables. Python has no variables, but names instead.
About your comment, actually i can illustrate the point a bit better:
i = 5
myList = [i, i, i]
i = 6
print(myList) # myList is still [5, 5, 5].
You said you changed i to 6, that is not what actually happend: i=6 means "i have a value, 6 and i want to name it i". The fact that you already used i as a name matters nothing to Python, it will just reassign the name, not change it's value (that only works with variables).
You could say that in myList = [i, i, i], whatever value i currently points to (the number 5) gets three new names: mylist[0], mylist[1], mylist[2]. That's the same thing that happens when you call a function: The arguments are given new names. But that is probably going against any intuition about lists ...
This can explain the behavior in the example: You assign mylist[0]=5, mylist[1]=5, mylist[2]=5 - no wonder they don't change when you reassign the i. If i was something muteable, for example a list, then changing i would reflect on all entries in myList too, because you just have different names for the same value!
The simple fact that you can use mylist[0] on the left hand of a = proves that it is indeed a name. I like to call = the assign name operator: It takes a name on the left, and a expression on the right, then evaluates the expression (call function, look up the values behind names) until it has a value and finally gives the name to the value. It does not change anything.
For Marks comment about compiling functions:
Well, references (and pointers) only make sense when we have some sort of addressable memory. The values are stored somewhere in memory and references lead you that place. Using a reference means going to that place in memory and doing something with it. The problem is that none of these concepts are used by Python!
The Python VM has no concept of memory - values float somewhere in space and names are little tags connected to them (by a little red string). Names and values exist in separate worlds!
This makes a big difference when you compile a function. If you have references, you know the memory location of the object you refer to. Then you can simply replace then reference with this location.
Names on the other hand have no location, so what you have to do (during runtime) is follow that little red string and use whatever is on the other end. That is the way Python compiles functions: Where
ever there is a name in the code, it adds a instruction that will figure out what that name stands for.
So basically Python does fully compile functions, but names are compiled as lookups in the nesting namespaces, not as some sort of reference to memory.
When you use a name, the Python compiler will try to figure out where to which namespace it belongs to. This results in a instruction to load that name from the namespace it found.
Which brings you back to your original problem: In lambda x:x**i, the i is compiled as a lookup in the makeActions namespace (because i was used there). Python has no idea, nor does it care about the value behind it (it does not even have to be a valid name). One that code runs the i gets looked up in it's original namespace and gives the more or less expected value.
What happens when you create a closure:
The closure is constructed with a pointer to the frame (or roughly, block) that it was created in: in this case, the for block.
The closure actually assumes shared ownership of that frame, by incrementing the frame's ref count and stashing the pointer to that frame in the closure. That frame, in turn, keeps around references to the frames it was enclosed in, for variables that were captured further up the stack.
The value of i in that frame keeps changing as long as the for loop is running – each assignment to i updates the binding of i in that frame.
Once the for loop exits, the frame is popped off the stack, but it isn't thrown away as it might usually be! Instead, it's kept around because the closure's reference to the frame is still active. At this point, though, the value of i is no longer updated.
When the closure is invoked, it picks up whatever value of i is in the parent frame at the time of invocation. Since in the for loop you create closures, but don't actually invoke them, the value of i upon invocation will be the last value it had after all the looping was done.
Future calls to makeActions will create different frames. You won't reuse the for loop's previous frame, or update that previous frame's i value, in that case.
In short: frames are garbage-collected just like other Python objects, and in this case, an extra reference is kept around to the frame corresponding to the for block so it doesn't get destroyed when the for loop goes out of scope.
To get the effect you want, you need to have a new frame created for each value of i you want to capture, and each lambda needs to be created with a reference to that new frame. You won't get that from the for block itself, but you could get that from a call to a helper function which will establish the new frame. See THC4k's answer for one possible solution along these lines.
The local references persist because they're contained in the local scope, which the closure keeps a reference to.
I thought that when a function exits, all of its local references disappear.
Except for those locals which are closed over in a closure. Those do not disappear, even when the function to which they are local has returned.
Intuitively one might think i would be captured in its current state but that is not the case. Think of each layer as a dictionary of name value pairs.
Level 1:
acts
i
Level 2:
x
Every time you create a closure for the inner lambda you are capturing a reference to level one. I can only assume that the run-time will perform a look-up of the variable i, starting in level 2 and making its way to level 1. Since you are not executing these functions immediately they will all use the final value of i.
Experts?

Categories