Adding custom names for vertices - julia

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.

Related

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'])

Julia : construct Dictionary with tuple values

Is there a possibility to construct dictionary with tuple values in Julia?
I tried
dict = Dict{Int64, (Int64, Int64)}()
dict = Dict{Int64, Tuple(Int64, Int64)}()
I also tried inserting tuple values but I was able to change them after so they were not tuples.
Any idea?
Edit:
parallel_check = Dict{Any, (Any, Any)}()
for i in 1:10
dict[i] = (i+41, i+41)
end
dict[1][2] = 1 # not able to change this way, setindex error!
dict[1] = (3, 5) # this is acceptable. why?
The syntax for tuple types (i.e. the types of tuples) changed from (Int64,Int64) in version 0.3 and earlier to Tuple{Int64,Int64} in 0.4. Note the curly braces, not parens around Int64,Int64. You can also discover this at the REPL by applying the typeof function to an example tuple:
julia> typeof((1,2))
Tuple{Int64,Int64}
So you can construct the dictionary you want like this:
julia> dict = Dict{Int64,Tuple{Int64,Int64}}()
Dict{Int64,Tuple{Int64,Int64}} with 0 entries
julia> dict[1] = (2,3)
(2,3)
julia> dict[2.0] = (3.0,4)
(3.0,4)
julia> dict
Dict{Int64,Tuple{Int64,Int64}} with 2 entries:
2 => (3,4)
1 => (2,3)
The other part of your question is unrelated, but I'll answer it here anyway: tuples are immutable – you cannot change one of the elements in a tuple. Dictionaries, on the other hand are mutable, so you can assign an entirely new tuple value to a slot in a dictionary. In other words, when you write dict[1] = (3,5) you are assigning into dict, which is ok, but when you write dict[1][2] = 1 you are assigning into the tuple at position 1 in dict which is not ok.

Copy or clone a collection in Julia

I have created a one-dimensional array(vector) in Julia, namely, a=[1, 2, 3, 4, 5]. Then I want to create a new vector b, where b has exactly same elements in a, i.e b=[1, 2, 3, 4, 5].
It seems that directly use b = a just create a pointer for the original collection, which means if I modify b and a is mutable, the modification will also be reflected in a. For example, if I use !pop(b), then b=[1, 2, 3, 4] and a=[1, 2, 3, 4].
I am wondering if there is a official function to merely copy or clone the collection, which the change in b will not happen in a. I find a solution is use b = collect(a). I would appreciate that someone provide some other approaches.
b=copy(a)
Should do what you want.
methods(copy) will give you a list of methods for copy, which will tell you what types of a this will work for.
julia> methods(copy)
# 32 methods for generic function "copy":
copy(r::Range{T}) at range.jl:324
copy(e::Expr) at expr.jl:34
copy(s::SymbolNode) at expr.jl:38
copy(x::Union{AbstractString,DataType,Function,LambdaStaticData,Number,QuoteNode,Symbol,TopNode,Tuple,Union}) at operators.jl:194
copy(V::SubArray{T,N,P<:AbstractArray{T,N},I<:Tuple{Vararg{Union{AbstractArray{T,1},Colon,Int64}}},LD}) at subarray.jl:29
copy(a::Array{T,N}) at array.jl:100
copy(M::SymTridiagonal{T}) at linalg/tridiag.jl:63
copy(M::Tridiagonal{T}) at linalg/tridiag.jl:320
copy{T,S}(A::LowerTriangular{T,S}) at linalg/triangular.jl:36
copy{T,S}(A::Base.LinAlg.UnitLowerTriangular{T,S}) at linalg/triangular.jl:36
copy{T,S}(A::UpperTriangular{T,S}) at linalg/triangular.jl:36
copy{T,S}(A::Base.LinAlg.UnitUpperTriangular{T,S}) at linalg/triangular.jl:36
copy{T,S}(A::Symmetric{T,S}) at linalg/symmetric.jl:38
copy{T,S}(A::Hermitian{T,S}) at linalg/symmetric.jl:39
copy(M::Bidiagonal{T}) at linalg/bidiag.jl:113
copy(S::SparseMatrixCSC{Tv,Ti<:Integer}) at sparse/sparsematrix.jl:184
copy{Tv<:Float64}(A::Base.SparseMatrix.CHOLMOD.Sparse{Tv<:Float64}, stype::Integer, mode::Integer) at sparse/cholmod.jl:583
copy(A::Base.SparseMatrix.CHOLMOD.Dense{T<:Union{Complex{Float64},Float64}}) at sparse/cholmod.jl:1068
copy(A::Base.SparseMatrix.CHOLMOD.Sparse{Tv<:Union{Complex{Float64},Float64}}) at sparse/cholmod.jl:1069
copy(a::AbstractArray{T,N}) at abstractarray.jl:349
copy(s::IntSet) at intset.jl:34
copy(o::ObjectIdDict) at dict.jl:358
copy(d::Dict{K,V}) at dict.jl:414
copy(a::Associative{K,V}) at dict.jl:204
copy(s::Set{T}) at set.jl:35
copy(b::Base.AbstractIOBuffer{T<:AbstractArray{UInt8,1}}) at iobuffer.jl:38
copy(r::Regex) at regex.jl:65
copy(::Base.DevNullStream) at process.jl:98
copy(C::Base.LinAlg.Cholesky{T,S<:AbstractArray{T,2}}) at linalg/cholesky.jl:160
copy(C::Base.LinAlg.CholeskyPivoted{T,S<:AbstractArray{T,2}}) at linalg/cholesky.jl:161
copy(J::UniformScaling{T<:Number}) at linalg/uniformscaling.jl:17
copy(A::Base.SparseMatrix.CHOLMOD.Factor{Tv}) at sparse/cholmod.jl:1070
You can use the copy and deepcopy functions:
help?> copy
search: copy copy! copysign deepcopy unsafe_copy! cospi complex Complex complex64 complex32 complex128 complement
copy(x)
Create a shallow copy of x: the outer structure is copied, but not all internal values. For example, copying an
array produces a new array with identically-same elements as the original.
help?> deepcopy
search: deepcopy
deepcopy(x)
Create a deep copy of x: everything is copied recursively, resulting in a fully independent object. For example,
deep-copying an array produces a new array whose elements are deep copies of the original elements. Calling deepcopy
on an object should generally have the same effect as serializing and then deserializing it.
As a special case, functions can only be actually deep-copied if they are anonymous, otherwise they are just copied.
The difference is only relevant in the case of closures, i.e. functions which may contain hidden internal
references.
While it isn't normally necessary, user-defined types can override the default deepcopy behavior by defining a
specialized version of the function deepcopy_internal(x::T, dict::ObjectIdDict) (which shouldn't otherwise be used),
where T is the type to be specialized for, and dict keeps track of objects copied so far within the recursion.
Within the definition, deepcopy_internal should be used in place of deepcopy, and the dict variable should be
updated as appropriate before returning.
Like this:
julia> a = Any[1, 2, 3, [4, 5, 6]]
4-element Array{Any,1}:
1
2
3
[4,5,6]
julia> b = copy(a); c = deepcopy(a);
julia> a[4][1] = 42;
julia> b # copied
4-element Array{Any,1}:
1
2
3
[42,5,6]
julia> c # deep copied
4-element Array{Any,1}:
1
2
3
[4,5,6]
Notice that the help system hints of the existence of other copy related functions.

Pythonic way to iterate over a collections.Counter() instance in descending order?

In Python 2.7, I want to iterate over a collections.Counter instance in descending count order.
>>> import collections
>>> c = collections.Counter()
>>> c['a'] = 1
>>> c['b'] = 999
>>> c
Counter({'b': 999, 'a': 1})
>>> for x in c:
print x
a
b
In the example above, it appears that the elements are iterated in the order they were added to the Counter instance.
I'd like to iterate over the list from highest to lowest. I see that the string representation of Counter does this, just wondering if there's a recommended way to do it.
You can iterate over c.most_common() to get the items in the desired order. See also the documentation of Counter.most_common().
Example:
>>> c = collections.Counter(a=1, b=999)
>>> c.most_common()
[('b', 999), ('a', 1)]
Here is the example to iterate the Counter in Python collections:
>>>def counterIterator():
... import collections
... counter = collections.Counter()
... counter.update(('u1','u1'))
... counter.update(('u2','u2'))
... counter.update(('u2','u1'))
... for ele in counter:
... print(ele,counter[ele])
>>>counterIterator()
u1 3
u2 3
Your problem was solved for just returning descending order but here is how to do it generically. In case someone else comes here from Google here is how I had to solve it. Basically what you have above returns the keys for the dictionary inside collections.Counter(). To get the values you just need to pass the key back to the dictionary like so:
for x in c:
key = x
value = c[key]
I had a more specific problem where I had word counts and wanted to filter out the low frequency ones. The trick here is to make a copy of the collections.Counter() or you will get "RuntimeError: dictionary changed size during iteration" when you try to remove them from the dictionary.
for word in words.copy():
# remove small instance words
if words[word] <= 3:
del words[word]

Appending data to an AT Field using transmogrifier

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.

Resources