Appending data to an AT Field using transmogrifier - plone

I have a CSV file of data like this:
1, [a, b, c]
2, [a, b, d]
3, [a]
and some Plone objects which should be updated like this:
ID, LinesField
a, [1,2,3]
b, [1,2]
c, [1]
d, [2]
So, to clarify, the object with the id a is named on lines 1, 2 and 3 of the CSV, and thus the LinesField property of object a needs to have those line ids (the first number on the line) listed.
Ideally I'd like to use Transmogrifier to import this information (and avoid doing any manipulation in Excel beforehand), and I can see two ways, theoretically of doing this, but I can't work out how to do this in practice. I'd be grateful for some pointers to examples. I think that either I need to transform the entire pipeline so that the items reflect the structure of my Plone objects and then use the ATSchemaUpdater blueprint, but I can't see any examples on how to add items to the pipeline (do I need to write my own blueprint?) Or, alternatively I could loop through the items as they exist and append the value in the left column to the items in the list in the right. For that I need a way of appending values with ATSchemaUpdater rather than overwriting them - again, is there a blueprint for that anywhere?
Here's a few sample csv lines:
"Name","Themes"
"Bessie Brown","cah;cab;cac"
"Fred Blogs","cah;cac"
"Dinah Washington","cah;cab"
The Plone object will be a theme and the lines field a list of names:
cah, ['Bessie Brown', 'Fred Boggs' etc etc]

I'm not pretty sure you want to read the CVS file using transmogrifier, but I think you can create a section to insert these values to the items in the pipeline using a function like this:
def transpose(cvs):
keys = []
[keys.extend(v) for v in cvs.values()]
keys = set(keys)
d = {}
for key in keys:
values = [k for k, v in cvs.iteritems() if key in v]
d[key] = values
return d
In this context, cvs is {1: ['a', 'b', 'c'], 2: ['a', 'b', 'd'], 3: ['a']}; keys will contain all possible values set(['a', 'c', 'b', 'd']); and d will be what you want {'a': [1, 2, 3], 'c': [1], 'b': [1, 2], 'd': [2]}.
Probably there are better ways to do it, but I'm not a Python magician.
The insert section could look like this one:
class Insert(object):
"""Insert new keys into items.
"""
classProvides(ISectionBlueprint)
implements(ISection)
def __init__(self, transmogrifier, name, options, previous):
self.previous = previous
self.new_keys = transpose(cvs)
def __iter__(self):
for item in self.previous:
item.update(self.new_keys)
yield item
After that you can use the SchemaUpdater section.

Related

Adding custom names for vertices

I want to create a graph with custom vertex names. Is this possible with MetaGraphs.jl ?
using MetaGraphs
using LightGraphs
using GraphPlot
# Create empty graph
gm = MetaGraph()
# Add vertices with properties
add_vertex!(gm, :A, [7.2,8.6])
add_vertex!(gm, :B, [3.2,6.7])
add_vertex!(gm, :C, [6.3,3.9])
add_vertex!(gm, :D, [2.4,6.7])
gplot(gm, nodelabel = vertices(gm))
However is it possible for the vertex to have a name called :A instead of 1. Since in the next step I want to add an edge add_edge!(gm, :A,:B) (This is incorrect, currently the names of the nodes 1,2,3... , so the way to create an edge is add_edge!(gm, 1,2))
In otherwords have A,B,C, ... instead of 1,2,3.
The best way to do this is to use set_indexing_prop! like so:
g = MetaGraph(path_graph(3))
set_prop!(g, 1, :name, 'a')
set_prop!(g, 2, :name, 'b')
set_prop!(g, 3, :name, 'c')
set_indexing_prop!(g, :name)
Then, you can refer to the names and they will be translated into vertex indices, which are integers:
g['a', :name] # returns 1
g['b', :name] # returns 2
g['c', :name] # returns 3
has_edge(g, g['b', :name], g['c', :name]) # returns true
From what I understand, one way to do that in MetaGraphs.jl is to define an "indexing property", for instance :name, which would contain :A, :B, etc.
Then, you can add an edge using the syntax add_edge!(gm, gm[:A, :name], gm[:B, :name]) if my memory serves me. As for plotting, you can simply retrieve the property with get_prop.

Getting second and third highest value in a dictionary

dict = {'a':5 , 'b':4, 'c':3, 'd':3, 'e':1}
Second is 'b' with 4 times. Joint third are 'c' and 'd' with 3 times. As the dictionary changes over time, say, 'f' is added with a value of 3, then third will be 'c', 'd', and 'f' with 3 times.
just create a gencomp of tuple value,key and sort it. Print items
d = {'a':5 , 'b':4, 'c':3, 'd':3, 'e':1}
x = sorted(((v,k) for k,v in d.items()))
print(x[-2][1])
print(x[-3][1])
result:
b
d
(would fail if dict doesn't have at least 3 items)
Or directly with key parameter (avoids data reordering)
x = sorted(d.items(),key=(lambda i: i[1]))
print(x[-2][0])
print(x[-3][0])
result:
b
d
BTW avoid using dict as a variable.
EDIT: since there are several identical values, you may want to get the 2 second best values and the associated letters. You have to do it differently. I'd create a default list using key as value and store in a list, then sort it as done in the above code:
import collections
d = {'a':5 , 'b':4, 'c':3, 'd':3, 'e':1}
dd = collections.defaultdict(list)
for k,v in d.items():
dd[v].append(k)
x = sorted(dd.items())
print(x[-2])
print(x[-3])
result:
(4, ['b'])
(3, ['c', 'd'])

Groovy map creation, use value assigned to previous key

Is there a way to use the values assigned to the previous key in map, for eg:
def x = [
a: someList.sum(),
b: anotherList.sum(),
c: someList.sum() / anotherList.sum()
]
I want the value of 'c' to be a/b, so is there a shortcut so that I don't have to recompute the sums while computing 'c'
In order to use previously-added key/values to compute new key/values, you must be able to control the order in which the keys/values are added. I know that's obvious, but what may not be obvious is that Groovy Map declarations do not take order into account. For example, if you write this...
def x = [
a: 8,
b: 2,
c: a / b
]
..., when evaluating the expression for the value of key c, Groovy will attempt to access a variable or property named a, which will fail because the variable/property does not exist. However, you can take advantage of that property lookup and do this:
def x = [:].with {
a = 8
b = 2
c = a / b
delegate
}
You start by creating an empty Map. Then, use with(Closure) to execute putAt() and get() against the Map. The example above is the equivalent to...
def x = [:].with {
putAt('a', 8)
putAt('b', 2)
putAt('c', get('a') / get('b'))
delegate
}
Finally, return the Map itself so that it's assigned to x.

Use one dictionary to fetch value in another dictionary

I have this problem where I have 2 dictionaries. One dict has keys representative of names (i.e. sample 1, sample 2, etc.) and the values are coordinates. The second dict has keys that are coordinates, and the values are data for each coordinate.
I need to build a 3rd dict that takes the names (keys), and then retrieves the respective values from the 2nd dict. As seen below:
dict1 = {32.0: [[(1, 7)], [(1, 17)], [(1, 8)], [(1, 18)]]}
dict2 = {(1, 7): 25.746392, (1, 18): 19.4782, (1, 17): 21.7492, (1, 8): 34.492}
dict3 = {32.0: [[25.746392], [21.7492], [34.492], [19.4782]]}
There are many more data points. I'm not sure if this is a simple problem, or if I'm having issues due to how nested the first dict is.
I'm still relatively new to Python, so any help is appreciated!
Two nested for-loops:
dict3 = dict1
for k in dict3.keys():
for i in range(len(dict3[k])):
dict3[k][i] = [dict2[dict3[k][i][0]]]
print dict3
Output:
{32.0: [[25.746392], [21.7492], [34.492], [19.4782]]}
One-liner:
dict3 = {k: [[dict2[dict1[k][i][0]]] for i in range(len(dict1[k]))] for k in dict1.keys()}

dynamic values in kwargs

I have a layer which helps me populating records from the form to tables and viceversa, it does some input checking, etc.
Now several methods of this layer which are called several times in different parts of the webform take the same parameters, so I wanted to pack them at the begining of the codefile.
kwargs(): return
{"tabla":"nombre_tabla","id":[hf_id.Value]
,"container": Panel1,"MsgBox1":
MsgBox1}
then I call
IA.search(**kwargs)
but doing that way the values of the dictionary get fixed with the ones they had in the begining, and one of them is retrieved from a webcontrol so it needs to be dynamic. So I wrapped them in a function
def kwargs(): return
{"tabla":"nombre_tabla",
"id":[hf_id.Value] ,"container":
Panel1,"MsgBox1": MsgBox1}
and then I call
IA.search(*kwargs())
IA.save(*kwargs())
etc.
and that way the value of the dictionary which comes from the webform (hf_id) is dynamic and not fixed. But I was wondering if in this case there is another way, a pythonic way, to get the values of the dictionary kwargs to be dynamic and not fixed
Python objects are pointers (though they are not directly manipulatable by the user.)
So if you create a list like this:
>>> a = [1, 2, 3]
and then store it in a dictionary:
>>> b = { 'key': a, 'anotherkey': 'spam' }
you will find modifications to the value in the dictionary also modify the original list:
>>> b['key'].append(4)
>>> print b['key']
[1, 2, 3, 4]
>>> print a
[1, 2, 3, 4]
If you want a copy of an item, so that modifications will not change the original item, then use the copy module.
>>> from copy import copy
>>> a = [1, 2, 3]
>>> b['key'] = copy(a)
>>> print b['key']
[1, 2, 3]
>>> b['key'].append(4)
>>> print b['key']
[1, 2, 3, 4]
>>> print a
[1, 2, 3]

Resources