Collections#

The Collection class is a versatile way of grouping and manipulating multiple Magpylib objects. A basic introduction is given in Collections. Here things are explained in more detail with examples.

Constructing collections#

Collections have the attributes children, sources, sensors and collections. These attributes are ordered lists that contain objects that are added to the collection by reference (not copied). children returns is list of all objects in the collection. sources returns a list of the sources, sensors a list of the sensors and collections a list of “sub-collections” within the collection.

import magpylib as magpy

x1 = magpy.Sensor(style_label='x1')
s1 = magpy.magnet.Cuboid(style_label='s1')
c1 = magpy.Collection(style_label='c1')

coll = magpy.Collection(x1, s1, c1, style_label='coll')

print(f"children:    {coll.children}")
print(f"sources:     {coll.sources}")
print(f"sensors:     {coll.sensors}")
print(f"collections: {coll.collections}")
children:    [Sensor(id=139829444294976, label='x1'), Cuboid(id=139828691102592, label='s1'), Collection(id=139829444293728, label='c1')]
sources:     [Cuboid(id=139828691102592, label='s1')]
sensors:     [Sensor(id=139829444294976, label='x1')]
collections: [Collection(id=139829444293728, label='c1')]

New additions are always added at the end. Add objects to an existing collection using these parameters, or the add method.

# automatically adjusts object label
x2 = x1.copy()
s2 = s1.copy()
c2 = c1.copy()

# add objects with add method
coll.add(x2, s2)

# add objects with parameters
coll.collections += [c2]

print(f"children:    {coll.children}")
print(f"sources:     {coll.sources}")
print(f"sensors:     {coll.sensors}")
print(f"collections: {coll.collections}")
children:    [Sensor(id=139829444294976, label='x1'), Cuboid(id=139828691102592, label='s1'), Sensor(id=139829444295360, label='x2'), Cuboid(id=139829520958080, label='s2'), Collection(id=139829444293728, label='c1'), Collection(id=139829520959808, label='c2')]
sources:     [Cuboid(id=139828691102592, label='s1'), Cuboid(id=139829520958080, label='s2')]
sensors:     [Sensor(id=139829444294976, label='x1'), Sensor(id=139829444295360, label='x2')]
collections: [Collection(id=139829444293728, label='c1'), Collection(id=139829520959808, label='c2')]

The describe method is a very convenient way to view a Collection structure, especially when the collection is nested, i.e. when containing other collections:

# add more objects
c1.add(x2.copy())
c2.add(s2.copy())

coll.describe(format='label')
coll
├── x1
├── s1
├── x2
├── s2
├── c1
│   └── x3
└── c2
    └── s3

For convenience, any two Magpylib object can be added up with + to form a collection:

import magpylib as magpy

x1 = magpy.Sensor(style_label='x1')
s1 = magpy.magnet.Cuboid(style_label='s1')

coll = x1 + s1

coll.describe(format='label')
Collection
├── x1
└── s1

Child-parent relations#

Objects that are part of a collection become children of that collection, and the collection itself becomes their parent. Every Magpylib object has the parent attribute, which is None by default.

import magpylib as magpy

x1 = magpy.Sensor()
c1 = magpy.Collection(x1)

print(f"x1.parent:   {x1.parent}")
print(f"c1.parent:   {c1.parent}")
print(f"c1.children: {c1.children}")
x1.parent:   Collection(id=139829444294592)
c1.parent:   None
c1.children: [Sensor(id=139829444294544)]

Rather than adding objects to a collection, as described above, one can also set the parent parameter. A Magpylib object can only have a single parent, i.e. it can only be part of a single collection. As a result, changing the parent will automatically remove the object from it’s previous collection.

import magpylib as magpy

x1 = magpy.Sensor(style_label='x1')
c1 = magpy.Collection(style_label='c1')
c2 = magpy.Collection(c1, style_label='c2')

print("Two empty, nested collections")
c2.describe(format='label')

print("\nSet x1 parent to c1")
x1.parent = c1
c2.describe(format='label')

print("\nChange x1 parent to c2")
x1.parent = c2
c2.describe(format='label')
Two empty, nested collections
c2
└── c1

Set x1 parent to c1
c2
└── c1
    └── x1

Change x1 parent to c2
c2
├── c1
└── x1

Working with collections#

Collections have __getitem__ through the attribute children defined which enables using collections directly as iterators,

import magpylib as magpy

x1 = magpy.Sensor()
x2 = magpy.Sensor()

coll = x1 + x2

for child in coll:
    print(child)
Sensor(id=139828690856448)
Sensor(id=139828690855824)

and makes it possible to directly reference to a child object by index:

print(coll[0])
Sensor(id=139828690856448)

Collection nesting is powerful to create a self-consistent hierarchical structure, however, it is often in the way of simple construction and children access in nested trees. For this, the children_all, sources_all, sensors_all and collections_all read-only parameters, give quick access to all objects in the tree:

import magpylib as magpy

s1 = magpy.Sensor(style_label='s1')
s2 = s1.copy()
s3 = s2.copy()

# this creates anested collection
coll = s1 + s2 + s3
coll.describe(format='label')

# _all gives access to the whole tree
print([s.style.label for s in coll.sensors_all])
Collection
├── Collection
│   ├── s1
│   └── s2
└── s3
['s1', 's2', 's3']

How to work with collections in a practical way is demonstrated in the introduction section Collections.

How to make complex compound objects is documented in Collections - Compounds.

Efficient 3D models#

The Matplotlib and Plotly libraries were not designed for complex 3D graphic outputs. As a result, it becomes often inconvenient and slow when attempting to display many 3D objects. One solution to this problem when dealing with large collections, is to represent the latter by a single encompassing body, and to deactivate the individual 3D models of all children. This is demonstrated in the following example.

import magpylib as magpy

# create collection
coll = magpy.Collection()
for index in range(10):
    cuboid = magpy.magnet.Cuboid(
        magnetization=(0, 0, 1000 * (index%2-.5)),
        dimension=(10,10,10),
        position=(index*10,0,0),
    )
    coll.add(cuboid)

# add 3D-trace
plotly_trace = magpy.graphics.model3d.make_Cuboid(
    backend='matplotlib',
    dimension=(104, 12, 12),
    position=(45, 0, 0),
    alpha=0.5,
)
coll.style.model3d.add_trace(plotly_trace)

coll.style.label='Collection with visible children'
coll.show()

# hide the children default 3D representation
coll.set_children_styles(model3d_showdefault=False)
coll.style.label = 'Collection with hidden children'
coll.show()
../_images/24715fa1cccf58f70bf54b2605593640b5e884256ed79407043c4d1c4ede879f.png ../_images/1a6522a2c3616e3fe2f86fe1c12756d021f69cd3399b48038eb3b93863723ab2.png

Note

The Collection position is set to (0,0,0) at creation time. Any added extra 3D-model will be bound to the local coordinate system of to the Collection and rotated/moved together with its parent object.