Repetitive PyQT references - python

I have a PyQT UI designed in QT Designer, with 40 figures (on different tabs), and a bunch of repetitive references to elements in the UI. For example, the following unique text fields, which are used to set the title of each figure.
# Tab 1
self.tab1_tl1.canvas.axes.set_title(self.tab1_tl1_title.text())
self.tab1_tl2.canvas.axes.set_title(self.tab1_tl2_title.text())
self.tab1_tl3.canvas.axes.set_title(self.tab1_tl3_title.text())
self.tab1_tl4.canvas.axes.set_title(self.tab1_tl4_title.text())
self.tab1_tl1.canvas.axes.set_ylabel(self.tab1_tl1_ylabel.text())
self.tab1_tl2.canvas.axes.set_ylabel(self.tab1_tl2_ylabel.text())
self.tab1_tl3.canvas.axes.set_ylabel(self.tab1_tl3_ylabel.text())
self.tab1_tl4.canvas.axes.set_ylabel(self.tab1_tl4_ylabel.text())
# Tab 2
self.tab2_tl1.canvas.axes.set_title(self.tab2_tl1_title.text())
self.tab2_tl2.canvas.axes.set_title(self.tab2_tl2_title.text())
self.tab2_tl3.canvas.axes.set_title(self.tab2_tl3_title.text())
self.tab2_tl4.canvas.axes.set_title(self.tab2_tl4_title.text())
self.tab2_tl1.canvas.axes.set_ylabel(self.tab2_tl1_ylabel.text())
self.tab2_tl2.canvas.axes.set_ylabel(self.tab2_tl2_ylabel.text())
self.tab2_tl3.canvas.axes.set_ylabel(self.tab2_tl3_ylabel.text())
self.tab2_tl4.canvas.axes.set_ylabel(self.tab2_tl4_ylabel.text())
As you can imagine, the code gets very wordy. Is there a more efficient way to loop through all these references and fields?

As I said in the comments, you could use getattr, but without further context, this is the best I can suggest:
for i in range(1, 41):
for j in range(1, 5):
ax = getattr(self, f'tab{i}_tl{j}').canvas.axes
title = getattr(self, f'tab{i}_tl{j}_title').text()
ylabel = getattr(self, f'tab{i}_tl{j}_ylabel').text()
ax.set_title(title)
ax.set_ylabel(ylabel)

You should put the corresponding tl, title and ylabel in a dictionary and arange them in a nested list instead of putting names as tab1_tl1
Create them like this:
tabs = []
for i in range(tabCount):
tab = []
tabs.append(tab)
for j in range(tlCount):
tab.append(dict(
obj = create_tl(i,j)),
title = create_title(i,j),
ylabel = create_ylabel(i,j) )
Now tabs[i][j] correspond to tabi_tlj and it is a dict containing the acutal tl object, the title and the ylabel.
So you can update the properties like this:
for tab in tabs:
for tl in tab:
tl['obj'].canvas.axes.set_title(tl['title'])
tl['obj'].canvas.axes.set_ylabel(tl['ylabel'])
In general create numbered variables is not good. Lists are there for that. Also always gather related repeated objects in dicts or objects.

Related

pass in a list of labels for generation of figures in for loop

Currently trying to save figures each with a name coming from a list in a for loop.
Input:
plot_l=['test1','test2',.........]
for i in range(ydata.shape[1]):
plt.figure()
fig, ax = plt.subplots(constrained_layout=True)
ax.plot(dsfg,ydata[i])
ax.set_xlabel('dsfg')
ax.set_ylabel('tzui')
ax.set_title('misc ')
secax.set_xlabel('len')
plt.savefig('plot_l{0}.jpg'.format(i))
plt.close()
Output: The figures are generated but with incorrect figure name, ie,
plot_l1.png
plot_l2.png
plot_l3.png
Desired Output:
test1.png
test2.png
test3.png
I have also tried plt.savefig(plot_l[i]+'.png') in place of plt.savefig('plot_l{0}.jpg'.format(i)) Suggestions are welcome....thanks
You are iterating on integers generated by range:
for i in range(ydata.shape[1]):
And you are naming the files with this parameter i.
plt.savefig('plot_l{0}.jpg'.format(i))
Assuming there is no error and the list of names contains as many names as there are iteration on i (i.e. ydata.shape[1] == len(plot_l)), then you can replace the savefig with:
plt.savefig(f'{plot_l[i]}.jpg')
The notation f followed by a string is equivalent to str.format(), but is more explicit as you can place the variable you are formatting inside the {}.

Delete array item based on dictionary value in python

I am trying to write a orientation routine for a 3-axis accelerometer. The part I am getting stuck on is, I have one dict with all my axis' listed, after taking the 'z-axis' reading, I want to remove that axis from the Availiable_axis list. Here is a portion of my code that demonstrates what I am trying to do.
import operator
Readings1 = { 0:{'x':0.1, 'y':-1, 'z':-0.1}, 1:{'x':.4, 'y':-.1, 'z':-0.1},
2:{'x':-0.4, 'y':-.8, 'z':-0.1}, 3:{'x':0.1, 'y':-.1, 'z':-0.6},
4:{'x':0.1, 'y':-.2, 'z':0.4}}
SetupValue = {'Axis':{'x-axis':'x','y-axis':'y','z-axis':'z'}}
Available_axis = [SetupValue['Axis']['x-axis'], SetupValue['Axis']['y-axis'], SetupValue['Axis']['z-axis']]
axes = Readings1[0]
print axes
for key in axes:
axes[key] = abs(axes[key])
print axes
print (max(axes.iteritems(), key = operator.itemgetter(1))[0])
Available_axis.pop(max(axes.iteritems(), key = operator.itemgetter(1))[0],0)
Any help would be appreciated.
Available_axis is a list. When popping from a list, you must specify the integer location.
You can also have a short list comprehension that removes the target variable.
Available_axis = [x for x in Available_axis
if x != max(axes.iteritems(), key = operator.itemgetter(1))[0]]

Using keyframe() to display nested dictionary info using Python in Maya

I need help doing the following:
Using the keyframe method (and flags) to extract information from a selected set of keys to store them in a nested dictionary. These keyframes correspond to an animation that has the all the keyframes copied for pasting onto other joints as needed. I've been combing through the documentation and different sources on the net but am running into animation terms and concepts I'm not familiar with.
I will later access this dictionary to display the keyframe information in a nicely formatted window so the artist I'm writing this for can see what the effect will be before pasting the animation.
My code for this part so far:
else:
key_list = mc.copyKey()
# check to see if window exists already
if mc.window(copyAnim, exists = True):
mc.deleteUI(copyAnim)
# create window
copyAnim = mc.window(title="Transfer Animation Tool", backgroundColor= [0.3,0.3,0.3],sizeable=False,resizeToFitChildren=True)
#set the layout for UI
mc.columnLayout(adjustableColumn=True)
tx_src = mc.textFieldGrp(label="Source Object", editable=False, text=sel[0])
int_offset = mc.intFieldGrp(label="Frame Offset Amount", value1=0)
#displaying what info will be transferred - here is where I would use
#keyframe() instead -- getting an error because copyKey() returns an
#int which is not iterable. As you can see the return value for copyKey
#is being stored in key_list.
for key in key_list:
display_info = mc.textFieldGrp(label="Copy Value", editable=False, text=key_list[item])
Link to documentation:
http://download.autodesk.com/us/maya/2011help/CommandsPython/keyframe.html
It sounds like the only flags you need for this application are -vc, which gets you the values and -tc, which get you the times (when combined with the -q flag which does the query.
If all you want is a dictionary of keys to values, it's basically just using dict() and zip():
def keys_as_dictionary(channel):
"""return a dictionay of times:values for <channel>"""
keys = cmds.keyframe(channel, q=True, tc=True) or []
values = cmds.keyframe(channel, q=True, vc=True) or []
return dict(zip(keys, values))
def channels(object):
"""return a dictionary of <plug>:<channel_dict> for each animated plug on <object>"""
keys = cmds.keyframe(object, n=True, q=True)
result = {}
for k in keys:
plugs = cmds.listConnections(k, p=True)[0]
result[plugs]= keys_as_dictionary(k)
return result
Calling channels() on an object will give you back a dictionary keyed by animation curve where the values are dictionaries of times and values:
import pprint
pprint.pprint(channels('pCube2'))
{u'pCube2.translateX': {4.955: 4.164464499411458,
10.89: -0.8212519883789916,
15.465: -0.6405074625130949,
22.65: -1.7965970091598258},
u'pCube2.translateY': {4.955: 8.271115169656772,
10.89: 0.3862609404272041,
15.465: 7.77669517461548,
22.65: 0.6892861215369379},
u'pCube2.translateZ': {4.955: -1.4066258181614297,
10.89: -4.891368771063121,
15.465: 4.340776804349586,
22.65: -3.5676492042261776}}
word of warning: this should work for plain animated objects, but is not doing anything smart about shared animation curves, instanced nodes, constraints or locked channels.... FYI....

wxPython ListCtrl : write Colored text

Trying to write string to a ListCtrl , I don't understand the logic completely. Is this the proper way?
self.rightPanel = wx.ListCtrl(spliter, -1, style=wx.LC_REPORT)
self.rightPanel.InsertColumn(0, 'LineNumber')
self.rightPanel.InsertColumn(1, 'log')
self.rightPanel.SetColumnWidth(0, 8)
self.rightPanel.SetColumnWidth(1, 80)
def writeConsole(self,str):
item = wx.ListItem()
item.SetText(str)
item.SetTextColour(wx.RED)
item.SetBackgroundColour(wx.BLACK)
index = self.rightPanel.GetItemCount()
self.rightPanel.InsertItem(item)
self.rightPanel.SetStringItem(index, 0, str(index))
self.rightPanel.SetStringItem(index, 1, item.GetText())
1-Why text is not displayed in color ?
2-Why there are 2 different methods for display text in ListCtrl?
ListCtrl.InsertItem()
ListCtrl.SetStringItem()
I think InsertItem just loads the item to list.SetString but displays the item content.(Not Sure)
SetTextColour() and SetBackgroundColour() are methods of the entire listctrl, not of items.
For items you should use (valid only for report mode):
GetItemTextColour(idx_item)
SetItemTextColour(idx_item, col)
InsertItem(index, item) (item here is an instance of wx.ListItem) is one of the InsertItem() methods to add a new row on a ListCtrl.
SetStringItem(index, col, label, imageId=-1) (where index and col parameters are the row and column indexes for a cell) allows setting strings in any selected column. Other insert methods work only for the first column.
Reference: wxPython in Action, Noel Rappin and Robin Dunn.

higher level Python GUI toolkit, e.g. pass dict for TreeView/Grid

Started my first Python pet project using PyGTK. Though it is a really powerful GUI toolkit and looks excellent, I have some pet peeves. So I thought about transitioning to something else, as it's not yet too extensive. Had a look around on SO and python documentation, but didn't get a good overview.
What's nice about PyGTK:
Glade files
self.signal_autoconnect({...})
self.get_widget() as __getattr__
This is bugging me however:
manual gobject.idle_add(lambda: ... and False)
no standard functionality to save application/window states
TreeView needs array building
widget.get_selection().get_selected(), model.get_value(iter, liststore_index)
TreeView: Because this is the main interface element, it's the most distracting. Basically my application builds a list of dictionaries to be displayed name=column+row=>value. To display it using GTK there needs to be a manual conversion process, ordering, typecasts. This seems a lot of overhead, and I wished for something more object-oriented here. PyGtk has many abstractions atop gtk+ but still seems rather low-levelish. I'd prefer to pass my dict as-is and have columns pre-defined somehow. (GtkBuilder can predefine TreeView columns, but this doesn't solve the data representation overhead.)
When I get a mousclick on my TreeView list, I also have to convert everything back into my application data structures. And it's also irksome that PyGTK doesn't wrap gtk+ calls with gobject.idle itself, if run from a non-main thread. Right now there is a lot of GUI code that I believe shouldn't be necessary, or could be rationalized away.
? So, are there maybe additional wrappers on top of PyGTK. Or which other toolkit supports simpler interfaces for displaying a Grid / TreeView. I've read a lot about wxPython being everyones favourite, but it's less mature on Linux. And PyQT seems to be mostly the same abstraction level as PyGTK. Haven't used TkInter much so don't know about if it has simpler interfaces, but it anyway looks unattractive. As does PyFLTK. PyJamas sounds fascinating, but is already too far out (Desktop application).
.
So, GUI toolkit with dict -> Grid display. Which would you pick?
.
Just as exhibit, this is my current TreeView mapping function. Sort of works, but I would rather have something standard:
#-- fill a treeview
#
# Adds treeviewcolumns/cellrenderers and liststore from a data dictionary.
# Its datamap and the table contents can be supplied in one or two steps.
# When new data gets applied, the columns aren't recreated.
#
# The columns are created according to the datamap, which describes cell
# mapping and layout. Columns can have multiple cellrenderers, but usually
# there is a direct mapping to a data source key from entries.
#
# datamap = [ # title width dict-key type, renderer, attrs
# ["Name", 150, ["titlerow", str, "text", {} ] ],
# [False, 0, ["interndat", int, None, {} ] ],
# ["Desc", 200, ["descriptn", str, "text", {} ], ["icon",str,"pixbuf",{}] ],
#
# An according entries list then would contain a dictionary for each row:
# entries = [ {"titlerow":"first", "interndat":123}, {"titlerow":"..."}, ]
# Keys not mentioned in the datamap get ignored, and defaults are applied
# for missing cols. All values must already be in the correct type however.
#
#staticmethod
def columns(widget, datamap=[], entries=[], pix_entry=False):
# create treeviewcolumns?
if (not widget.get_column(0)):
# loop through titles
datapos = 0
for n_col,desc in enumerate(datamap):
# check for title
if (type(desc[0]) != str):
datapos += 1 # if there is none, this is just an undisplayed data column
continue
# new tvcolumn
col = gtk.TreeViewColumn(desc[0]) # title
col.set_resizable(True)
# width
if (desc[1] > 0):
col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
col.set_fixed_width(desc[1])
# loop through cells
for var in xrange(2, len(desc)):
cell = desc[var]
# cell renderer
if (cell[2] == "pixbuf"):
rend = gtk.CellRendererPixbuf() # img cell
if (cell[1] == str):
cell[3]["stock_id"] = datapos # for stock icons
expand = False
else:
pix_entry = datapos
cell[3]["pixbuf"] = datapos
else:
rend = gtk.CellRendererText() # text cell
cell[3]["text"] = datapos
col.set_sort_column_id(datapos) # only on textual cells
# attach cell to column
col.pack_end(rend, expand=cell[3].get("expand",True))
# apply attributes
for attr,val in cell[3].iteritems():
col.add_attribute(rend, attr, val)
# next
datapos += 1
# add column to treeview
widget.append_column(col)
# finalize widget
widget.set_search_column(2) #??
widget.set_reorderable(True)
# add data?
if (entries):
#- expand datamap
vartypes = [] #(str, str, bool, str, int, int, gtk.gdk.Pixbuf, str, int)
rowmap = [] #["title", "desc", "bookmarked", "name", "count", "max", "img", ...]
if (not rowmap):
for desc in datamap:
for var in xrange(2, len(desc)):
vartypes.append(desc[var][3]) # content types
rowmap.append(desc[var][0]) # dict{} column keys in entries[] list
# create gtk array storage
ls = gtk.ListStore(*vartypes) # could be a TreeStore, too
# prepare for missing values, and special variable types
defaults = {
str: "",
unicode: u"",
bool: False,
int: 0,
gtk.gdk.Pixbuf: gtk.gdk.pixbuf_new_from_data("\0\0\0\0",gtk.gdk.COLORSPACE_RGB,True,8,1,1,4)
}
if gtk.gdk.Pixbuf in vartypes:
pix_entry = vartypes.index(gtk.gdk.Pixbuf)
# sort data into gtk liststore array
for row in entries:
# generate ordered list from dictionary, using rowmap association
row = [ row.get( skey , defaults[vartypes[i]] ) for i,skey in enumerate(rowmap) ]
# autotransform string -> gtk image object
if (pix_entry and type(row[pix_entry]) == str):
row[pix_entry] = gtk.gdk.pixbuf_new_from_file(row[pix_entry])
# add
ls.append(row) # had to be adapted for real TreeStore (would require additional input for grouping/level/parents)
# apply array to widget
widget.set_model(ls)
return ls
pass
Try Kiwi, maybe? Especially with its ObjectList.
Update: I think Kiwi development has moved to PyGTKHelpers.
I hadn't come across Kiwi before. Thanks, Johannes Sasongko.
Here are some more tooklits that I keep bookmarked. Some of these are wrappers around other toolkits (GTK, wxWidgets) while others stand alone:
AVC
Dabo
pyFLTK
pyglet
PyGTK
PyGUI
uxPython
Wax
wxPython
wxpita
WxWrappers
(I've included a few that were already mentioned for the sake of others who come across this post. I would have posted this as a comment, but it's a bit too long.)
See also pygtkhelpers' ObjectList
I would suggest taking a look at wxPython. I found it really easy to pick up and very powerful too although I'd have to admit I've not done a lot with Treeviews myself.
wxWidgets calls the equivalent control a wxTreeCtrl
[Edit] The wxDataViewTreeCtrl might actually be of more use in your case.

Categories