diff --git a/README.md b/README.md
index 7b7f0dd0..0c16fed5 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
-
Mathematical graphs for Python
+
Graphs for Python
[](https://pypi.org/project/pgraph-python/)
@@ -35,7 +35,15 @@
[](https://matplotlib.org)
[](https://github.com/petercorke/spatialmath-python)
-This Python package allows the manipulation of directed and non-directed graphs. Also supports embedded graphs. It is suitable for graphs with thousands of nodes.
+This package provides classes for directed and undirected graphs: vertices
+connected by edges, with edge costs and path planning. Self-loops and
+parallel edges are permitted.
+
+Vertices can optionally be *embedded*: given a coordinate in a space of any
+dimension. Edge costs are then computed from the vertex positions using a
+distance metric (Euclidean, Manhattan, SE(2), or your own), the vertex nearest
+a point can be found, `A*` uses the metric as its heuristic, and the graph can
+be plotted, or exported with its layout preserved.

@@ -89,18 +97,18 @@ Graphs belong to the class `UGraph` or `DGraph` for undirected or directed graph
- `g.incidence()` incidence matrix
### Properties and methods of a vertex
-Vertices belong to the class `UVertex` (for undirected graphs) or `DVertex` (for directed graphs), which are each subclasses of `Vertex`.
+Vertices belong to the class `UVertex` (for undirected graphs) or `DVertex` (for directed graphs), which are each subclasses of `BaseVertex`.
- `v.coord` the coordinate vector for embedded graph (optional)
- `v.name` the name of the vertex (optional)
-- `v.neighbours()` is a list of the neighbouring vertices
+- `v.adjacent()` is a list of the adjacent vertices (`neighbours()` and `neighbors()` are the same)
- `v1.samecomponent(v2)` predicate for vertices belonging to the same component
Vertices can be named and referenced by name.
### Properties and methods of an edge
Edges are instances of the class `Edge`.
-Edges are not referenced by the graph object, each edge references a pair of vertices, and the vertices reference the edges. For a directed graph only the start vertex of an edge references the edge object, whereas for an undirected graph both vertices reference the edge object.
+Each edge references a pair of vertices, the graph lists all of its edges in `g.edges()`, and the vertices reference the edges. For a directed graph only the start vertex of an edge references the edge object, whereas for an undirected graph both vertices reference the edge object.
- `e.cost` cost of edge for planning methods
- `e.next(v)` vertex on edge `e` that is not `v`
@@ -135,12 +143,6 @@ for f in f1.neighbours():
# say hi to the neighbours
```
-## Under the hood
-
-The key objects and their interactions are shown below.
-
-
-
## MATLAB version
This is a re-engineered version of [PGraph.m](https://github.com/petercorke/spatialmath-matlab/blob/main/PGraph.m) which ships as part of the [Spatial Math Toolbox for MATLAB](https://github.com/petercorke/spatialmath-matlab). This class is used to support bundle adjustment, pose-graph SLAM and various planners such as PRM, RRT and Lattice.
diff --git a/docs/figs/datastructures.ezdraw b/docs/figs/datastructures.ezdraw
new file mode 100644
index 00000000..1cb41848
--- /dev/null
+++ b/docs/figs/datastructures.ezdraw
@@ -0,0 +1,2904 @@
+
+
+
+
+ AAAA_CurrentOSVersion
+ macOS Tahoe: 5026.500000
+ AAAA_DKDDocumentVersion
+ 9.0.0 : Mobile Friendly
+ AAAA_EazyDrawVersion
+ 12.3.6
+ AAAB_Build
+ 51059
+ AAAB_Distribution
+ Free Market
+ ArchiveMatchStore
+
+ Archive_Stores
+
+
+ Class_Store
+ DKDLock
+ Match_Hashes
+
+
+ BinIndex
+ 10
+ BinMatches
+
+
+ CenterLock
+ YES
+
+
+
+
+ NHashBins
+ 16
+
+
+ Class_Store
+ DKDGraphicStyle
+ Match_Hashes
+
+
+ BinIndex
+ 8
+ BinMatches
+
+
+ DrawsFill
+ NO
+ DrawsLine
+ YES
+ LineCapStyle
+ Square
+ LineJoinStyle
+ Miter
+ LineRGB
+
+ BluePlus
+ 0
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0
+ OpacityPlus
+ 1
+ RedPlus
+ 0
+
+ LineWidth
+ 1
+ MiterLimit
+ 10
+ StrokePosition
+ Front
+ WindingRule
+ Non-Zero
+
+
+ DrawsFill
+ NO
+ DrawsLine
+ YES
+ LineCapStyle
+ Square
+ LineJoinStyle
+ Miter
+ LineRGB
+
+ BluePlus
+ 0
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0.149131
+ OpacityPlus
+ 0.796019
+ RedPlus
+ 1
+
+ LineWidth
+ 6.34521484375
+ MiterLimit
+ 10
+ StrokePosition
+ Front
+ WindingRule
+ Non-Zero
+
+
+ DrawsFill
+ NO
+ DrawsLine
+ YES
+ LineCapStyle
+ Square
+ LineJoinStyle
+ Miter
+ LineRGB
+
+ BluePlus
+ 0
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0
+ OpacityPlus
+ 1
+ RedPlus
+ 0
+
+ LineWidth
+ 2.53369140625
+ MiterLimit
+ 10
+ StrokePosition
+ Front
+ WindingRule
+ Non-Zero
+
+
+ DrawsFill
+ NO
+ DrawsLine
+ YES
+ LineCapStyle
+ Square
+ LineJoinStyle
+ Miter
+ LineRGB
+
+ BluePlus
+ 0
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0
+ OpacityPlus
+ 1
+ RedPlus
+ 0
+
+ LineWidth
+ 2.5
+ MiterLimit
+ 10
+ StrokePosition
+ Front
+ WindingRule
+ Non-Zero
+
+
+ DrawsFill
+ NO
+ DrawsLine
+ YES
+ LineCapStyle
+ Square
+ LineJoinStyle
+ Miter
+ LineRGB
+
+ BluePlus
+ 0.570465
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0.570472
+ OpacityPlus
+ 1
+ RedPlus
+ 0.570459
+
+ LineWidth
+ 1
+ MiterLimit
+ 10
+ StrokePosition
+ Front
+ WindingRule
+ Non-Zero
+
+
+ DrawsFill
+ NO
+ DrawsLine
+ YES
+ LineCapStyle
+ Square
+ LineJoinStyle
+ Miter
+ LineRGB
+
+ BluePlus
+ 0
+ ColorSpacePlus
+ DKDP3ColorSpace
+ GreenPlus
+ 0
+ OpacityPlus
+ 1
+ RedPlus
+ 0
+
+ LineWidth
+ 1
+ MiterLimit
+ 10
+ StrokePosition
+ Front
+ WindingRule
+ Non-Zero
+
+
+ DrawsFill
+ NO
+ DrawsLine
+ YES
+ LineCapStyle
+ Square
+ LineJoinStyle
+ Miter
+ LineRGB
+
+ BluePlus
+ 0.474303
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0.981323
+ OpacityPlus
+ 1
+ RedPlus
+ 0.450094
+
+ LineWidth
+ 2.628856658936
+ MiterLimit
+ 10
+ StrokePosition
+ Front
+ WindingRule
+ Non-Zero
+
+
+ DrawsFill
+ NO
+ DrawsLine
+ YES
+ LineCapStyle
+ Square
+ LineJoinStyle
+ Miter
+ LineRGB
+
+ BluePlus
+ 1
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0.991439
+ OpacityPlus
+ 1
+ RedPlus
+ 0
+
+ LineWidth
+ 2.628856658936
+ MiterLimit
+ 10
+ StrokePosition
+ Front
+ WindingRule
+ Non-Zero
+
+
+
+
+ BinIndex
+ 10
+ BinMatches
+
+
+ DrawsFill
+ NO
+ DrawsLine
+ NO
+ LineCapStyle
+ Square
+ LineJoinStyle
+ Miter
+ LineWidth
+ 1
+ MiterLimit
+ 10
+ StrokePosition
+ Front
+ WindingRule
+ Non-Zero
+
+
+
+
+ NHashBins
+ 16
+
+
+ Class_Store
+ DKDArrow
+ Match_Hashes
+
+
+ BinIndex
+ 2
+ BinMatches
+
+
+ ArrowAngle
+ 160
+ ArrowArchiveVersion
+ 9
+ ArrowBackEnd
+ YES
+ ArrowForEachSegment
+ NO
+ ArrowForm
+ solid
+ ArrowFrontEnd
+ NO
+ ArrowLineWidthFraction
+ 0.25
+ ArrowOffset
+ 0
+ ArrowSize
+ 8
+ ReferenceArrow
+ Relief
+ UseCurveFillAndStroke
+ YES
+
+
+
+
+ BinIndex
+ 10
+ BinMatches
+
+
+ ArrowAngle
+ 159.730010986
+ ArrowArchiveVersion
+ 9
+ ArrowBackEnd
+ YES
+ ArrowForEachSegment
+ NO
+ ArrowForm
+ solid
+ ArrowFrontEnd
+ NO
+ ArrowLineWidthFraction
+ 0.25
+ ArrowOffset
+ 0
+ ArrowSize
+ 10.7576407035
+ ReferenceArrow
+ Relief
+ UseCurveFillAndStroke
+ YES
+
+
+ ArrowAngle
+ 160
+ ArrowArchiveVersion
+ 9
+ ArrowBackEnd
+ YES
+ ArrowForEachSegment
+ NO
+ ArrowForm
+ solid
+ ArrowFrontEnd
+ NO
+ ArrowLineWidthFraction
+ 0.25
+ ArrowOffset
+ 0
+ ArrowSize
+ 10.6271449412
+ ReferenceArrow
+ Relief
+ UseCurveFillAndStroke
+ YES
+
+
+ ArrowAngle
+ 160
+ ArrowArchiveVersion
+ 9
+ ArrowBackEnd
+ YES
+ ArrowForEachSegment
+ NO
+ ArrowForm
+ solid
+ ArrowFrontEnd
+ NO
+ ArrowLineWidthFraction
+ 0.25
+ ArrowOffset
+ 0
+ ArrowSize
+ 37.5449518519
+ ReferenceArrow
+ Relief
+ UseCurveFillAndStroke
+ YES
+
+
+
+
+ NHashBins
+ 16
+
+
+ Class_Store
+ DKDParagraph
+ Match_Hashes
+
+
+ BinIndex
+ 0
+ BinMatches
+
+
+ FirstLineHeadIndent
+ 0
+ HeadIndent
+ 0
+ LineFragmentPadding
+ 5
+ LineSpacing
+ 0
+ ParagraphSpacing
+ 0
+ ParagraphSpacingBefore
+ 0
+ TailIndent
+ 0
+ TextAlignment
+ Left
+
+
+
+
+ NHashBins
+ 16
+
+
+ Class_Store
+ DKDFont
+ Match_Hashes
+
+
+ BinIndex
+ 0
+ BinMatches
+
+
+ Family
+ Courier
+ Name
+ Courier
+ Size
+ 12
+ Traits
+ 400
+
+
+ Family
+ Avenir
+ Name
+ Avenir-Book
+ Size
+ 12
+
+
+ Family
+ Avenir
+ Name
+ Avenir-Heavy
+ Size
+ 22
+ Traits
+ 2
+
+
+ Family
+ Bradley Hand
+ Name
+ BradleyHandITCTT-Bold
+ Size
+ 12
+ Traits
+ 22
+
+
+ Family
+ Courier
+ Name
+ Courier
+ Size
+ 11
+ Traits
+ 400
+
+
+
+
+ NHashBins
+ 16
+
+
+ Class_Store
+ DKDTextAttributes
+ Match_Hashes
+
+
+ BinIndex
+ 0
+ BinMatches
+
+
+ Font
+ 0
+ ForeColor
+
+ ColorSpace
+ NSCalibratedWhiteColorSpace
+ Opacity
+ 1
+ White
+ 0
+
+ Paragraph
+ 0
+
+
+ Font
+ 0
+ ForeColor
+
+ BluePlus
+ 1
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0
+ OpacityPlus
+ 1
+ RedPlus
+ 0
+
+ Paragraph
+ 0
+
+
+ Font
+ 16
+ ForeColor
+
+ BluePlus
+ 1
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0
+ OpacityPlus
+ 1
+ RedPlus
+ 0
+
+ Paragraph
+ 0
+
+
+ Font
+ 32
+ ForeColor
+
+ BluePlus
+ 0
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0.333
+ OpacityPlus
+ 1
+ RedPlus
+ 1
+
+ Paragraph
+ 0
+
+
+ Font
+ 48
+ ForeColor
+
+ BluePlus
+ 0.570465
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0.570472
+ OpacityPlus
+ 1
+ RedPlus
+ 0.570459
+
+ Paragraph
+ 0
+
+
+ Font
+ 64
+ ForeColor
+
+ ColorSpace
+ NSCalibratedWhiteColorSpace
+ Opacity
+ 1
+ White
+ 0
+
+ Paragraph
+ 0
+
+
+
+
+ NHashBins
+ 16
+
+
+ Class_Store
+ DKDDashPattern
+ Match_Hashes
+
+
+ BinIndex
+ 0
+ BinMatches
+
+
+ DashOn
+ YES
+ DashSequence
+
+ 4
+ 5
+
+
+
+ DashOn
+ YES
+ DashSequence
+
+ 4
+ 5
+
+
+
+ DashOn
+ YES
+ DashSequence
+
+ 4
+ 5
+
+
+
+ DashOn
+ YES
+ DashSequence
+
+ 4
+ 5
+
+
+
+ DashOn
+ YES
+ DashSequence
+
+ 4
+ 5
+
+
+
+ DashOn
+ YES
+ DashSequence
+
+ 4
+ 5
+
+
+
+
+
+ NHashBins
+ 16
+
+
+
+ BBB_DKDQuicklookData
+
+ /9j/4AAQSkZJRgABAQAASABIAAD/4QCARXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEA
+ AAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAA
+ AAAAAABIAAAAAQAAAEgAAAABAAKgAgAEAAAAAQAAA1KgAwAEAAAAAQAAAyYAAAAA/+0A
+ OFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAAOEJJTQQlAAAAAAAQ1B2M2Y8AsgTpgAmY
+ 7PhCfv/iAihJQ0NfUFJPRklMRQABAQAAAhhhcHBsBAAAAG1udHJSR0IgWFlaIAfmAAEA
+ AQAAAAAAAGFjc3BBUFBMAAAAAEFQUEwAAAAAAAAAAAAAAAAAAAAAAAD21gABAAAAANMt
+ YXBwbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ CmRlc2MAAAD8AAAAMGNwcnQAAAEsAAAAUHd0cHQAAAF8AAAAFHJYWVoAAAGQAAAAFGdY
+ WVoAAAGkAAAAFGJYWVoAAAG4AAAAFHJUUkMAAAHMAAAAIGNoYWQAAAHsAAAALGJUUkMA
+ AAHMAAAAIGdUUkMAAAHMAAAAIG1sdWMAAAAAAAAAAQAAAAxlblVTAAAAFAAAABwARABp
+ AHMAcABsAGEAeQAgAFAAM21sdWMAAAAAAAAAAQAAAAxlblVTAAAANAAAABwAQwBvAHAA
+ eQByAGkAZwBoAHQAIABBAHAAcABsAGUAIABJAG4AYwAuACwAIAAyADAAMgAyWFlaIAAA
+ AAAAAPbVAAEAAAAA0yxYWVogAAAAAAAAg98AAD2/////u1hZWiAAAAAAAABKvwAAsTcA
+ AAq5WFlaIAAAAAAAACg4AAARCwAAyLlwYXJhAAAAAAADAAAAAmZmAADypwAADVkAABPQ
+ AAAKW3NmMzIAAAAAAAEMQgAABd7///MmAAAHkwAA/ZD///ui///9owAAA9wAAMBu/8AA
+ EQgDJgNSAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//E
+ ALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHw
+ JDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0
+ dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
+ 09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAAB
+ AgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKB
+ CBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZX
+ WFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2
+ t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/bAEMAHBwcHBwc
+ MBwcMEQwMDBEXERERERcdFxcXFxcdIx0dHR0dHSMjIyMjIyMjKioqKioqMTExMTE3Nzc
+ 3Nzc3Nzc3P/bAEMBIiQkODQ4YDQ0YOacgJzm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm
+ 5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5v/dAAQANv/aAAwDAQACEQMRAD8A6SiiigAo
+ oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
+ KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
+ oooAKKKKAP/Q6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
+ oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiigkDrQAUU
+ hZRyTSb1xnPFK4rjqKbvUgnPSgOp6Gi6C6HUU0Mp4Bpcg9DTuO4tFFFABRRRQAUUUUAF
+ FFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFA
+ BRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRR
+ QB//0ekooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igAooooAKKKKACiiigAooooAKKKKACiikJAGTQAtFMD7gdooAc/eNK4rj8jpTBIpOBQq
+ KvI60/GOlGoake5yenFBVyfvYFSUUWCwxkDHJJpSinGe1Ooosgshu1cYx0pdoxjFLRTs
+ OwmB6UYHpS0UAIFUHIFN8tAcgU+ilZCsiMx85BIpT5mcrjFPoosFhjOVPI/Gnbhx70tN
+ ZVbqKNQ1HUUwqwACHpRv2gb+CaL9wv3H0UAg8iimMKKKKACiiigAooooAKKKKACiiigA
+ ooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoooo
+ AKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/0ukooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoopGYKMmgBaaW
+ AGetN+Zxz8tOVQowKVxXGjcwOflpyoF9806iiwWCiiimMKKKKACiiigAooooAKKKrSXl
+ rF/rJVHtnn8qALNFZTazaZxEHkP+yv8Ajim/b7yT/U2jfVjigDXorI36zJ0SKP6nP8s0
+ fZtVf79yq/7q/wD6qANeisj+zbhv9ZdyH6cf1o/seE/fllb6t/8AWoA1iQOpxTfMj/vD
+ 86zBotj3DH6mn/2Pp/8AzzP/AH0f8aANHzE/vD86Xgj1rM/sbT/7h/M03+xbL+Hcv0NA
+ GmVIHyHGKN2AN/BNZf8AZCL/AKqeVD/vUGwvl+5dk+zDNK3YVuxr0VQhW+jVhMVb0Kjj
+ 8agbUpYGIuYGCj+JeR/Si4XNaiqMOpWU3CSAH0bj+dXqYwooooAKKKKACiiigAooooAK
+ KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA
+ CiiigAooooAKKKKACiiigAooooAKKKKAP//T6SiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKjBL54+Wk2JsXduyE60qrt
+ 6nJNKAAMClot3C3cKKKKYwooooAKKKKACiiqtze21oP3zc/3RyfyoAtUySWOJd0rBR6k
+ 4rJ87Urz/UIIIz/E33vyqSPSYN3mXLNM/qx4/KgBG1aEtstUeZv9kcUmdXuOgSBffk/1
+ rVREjXagCgdhxTqAMj+yjLzdzvL7ZwPy5qzHptjF92JT9ef51eooARVVRhQAPaloooAK
+ KKKACiiigAooooAKKKKACiiigApjJnkHBp9FJq4mrlOW1tJztmjUt64wfzqn/Zs9vzYz
+ sn+y3K1rsobrTAxDbWHXpRe24XtuZY1Ce2O3UIio/vpytakU0U674WDD2p5AIwRkGsub
+ TFDedYt5Mnt90/UUxmrRWTFqLxOINQTymPRv4TWt15FABRRRQAUUUUAFFFFABRRRQAUU
+ UUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAF
+ FFFABRRRQAUUUUAFFFFAH//U6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
+ KKKKACiiigAooooAKKKKACiiigAoJA5NFRkeYQc/LSbE2GGLZPAFSUUUJAkFFFFMYUUU
+ UAFFFFABTXdI1LyEKo6k0yeeO3jMspworJjgm1NhcXeVhHKR+vuaAHG6ur9ilgNkfQyt
+ /T/P5VattOt7c7yPMk6l25OavKqqAqjAHQCloAKKKKACiiigAooooAKKKKACiiigApGZ
+ VGWOBS1HJ/D/ALwoAPNi/vD86PNi/vD86V5AnXJ78egpvnLztBODj8aAF82L+8Pzo82L
+ +8PzqIT4UsRklsACplkVyQM8cGgBPNi/vD86PNi/vD86Z5uZAo4HP44oNwoGQDk9BQA/
+ zYv7w/OjzYv7w/Ok80Zbjhepo80MG2ckfrQAvmxf3h+dHmxf3hRG5fORjBIqSgCGN+SM
+ ggd6mqIgGQg/3R/OlHyDDH6UthbBNDFOhjmUMp9ax/8ASNJPeW2/VP8A61blBAIweQaY
+ xkciTIJIzuU9CKfWHJHJpUnnwAtbsfnT+77itmORJUEkZyrDINAD6KKKACiiigAooooA
+ KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigD/1ekooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAoopCQoyaAGsQ3yZ5pwAAwKaqgZb1p9JdxLuFFFFMYUUUU
+ AFFFFABQSAMnpRWXqsrLAtvH9+dgg+h60AV4lOqXJnk/494jhB/ePqa3KihiSCJYU6KM
+ VLQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAVHJ/D/vCpOnJqAlmKt0XPHv70ASNGrHL
+ UGNCNpHBOabJLsIGMk5x+FMFwpUkdhx70ASGJD04+lPVQowO5zVZZnbGAD82OOh4zS+c
+ 4TO3LEkD86AJRDGO1J5KY7/XPNCyFmK46dT9RUtAERhjJyRnPHU07y0BDAcjgU+igBoV
+ QSR3p1FFAEf/AC1P+6P509lDDBpn/LU/7o/nUlADAwUhD+dPpCobrTVfJKtwaWwthxAY
+ FSMg1iITpVyImP8Ao0p+U/3W9K3KguIEuYWhk6N+h9aYyeisvTZ3Iazn/wBbDx9R2Nal
+ ABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRR
+ RQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQB//9bpKKKKACiiigAooooARiFUsewzVVJ5
+ 3UOsPDDI+Yd6sS/6tvoaZb/6iP8A3R/KgBnm3H/PH/x4Uebcf88f/HhVmigCt5tx/wA8
+ f/HhR5tx/wA8f/HhVmigCt5tx/zx/wDHhR5tx/zx/wDHhVmigCt5tx/zx/8AHhR5tx/z
+ x/8AHhVmigCt5tx/zx/8eFHm3H/PH/x4VZooArebcf8APH/x4Uebcf8APH/x4VZooAre
+ bcf88f8Ax4Uebcf88f8Ax4VZooArebcf88f/AB4Uebcf88f/AB4VZooArebcf88f/HhT
+ Gknb5TFz6bhVymKASXBzmk+wn2IfNuP+eP8A48KPNuP+eP8A48Ks0Uxlbzbj/nj/AOPC
+ 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
+ 8zIwTggj+nFTNbxMqpjAQYXBII/Ec0020Lbc7vl6YZh/I0Xh2AYZpxMkflj5lJPPcEf4
+ 0x70LKYwmQrBSe+T6DH9asyQxy4Lg5HQgkdfpTTbQlt2CPXBIBx6jPNJOPVARfaX+0fZ
+ 9g3Zz1/h9en6VJLOY5Vj28N3Jx37cdaPssO7fg53bs5PX86e8MchDPnj3OOPUUXjfYCG
+ SfMXAxu3D6bQf8KYLlo41MyYyuRg5Jx2NT/ZoS24g557nHPXj3oW2hUYxkY24JJwPQZo
+ vECNnk8yMyALyehyOn0FRi9JVjs5GOhOMHPOce3pVkW8QGCCevUk9RjuaaLWIZxuycc7
+ jnjpzn3p3j1QDBdZkRNoAYA5z6+nGD+dW6gFtCCpAPy4wMnHHTip6iVugwoooqQCiiig
+ AooooAKKKKACiiigAooooAKKKKACiiigAooooA//1ukooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAY6k4I6inAg9KWo8BCWzwaWwt
+ iSiiimMKKKKACiiigArH0/8A0e6uLI8fNvX6H/IrYrI1JHhePUIhkxcMPVTQBr0UyN1l
+ RZEOVYZFPoAKKKKACiiigAooooAKKKKACiiigAooooAKzb68aMi1thunfoPT3NLe3pgI
+ ggG+d/ur6e5p1lZC2BkkO+Z+Wb+goAdZWa2kZyd0jcu3qau0UUAFFFFABRR05NUJ7v8A
+ hi/P/Ck3YqMXLYsTXCQjHVvSswmW5f1P6CnQ27zHceB61qxxpEu1BUayNrxhtuQwWyxf
+ M3LVZooq0rGDberCiiimIKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoooo
+ AKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKK
+ KAP/1+kooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igAooooAKQgEYNLRQAxSEwhp9NZQ3WkD/NtPBpbC2H0UUUxhRRRQAUjKrqUYZBGCKWig
+ DFs2awuTp8p+RuYif5VtVTvbRbuHZnDryrehqOwu2nUwzfLNHww9fegDQooooAKKKKAC
+ iiigAooooAKKKKACs+9vfIxBAN87/dX09zRe3vkEQQDfO/3V9Pc0tlZfZ8yynfM/3m/o
+ KACysvs4Msp3zP8Aeb+gq/RRQAUUUUAFMeRI13OcVDNcrFwOW9KzsS3L+p/QVLl0RrCn
+ fV7D5rh5jtHC+lTwWn8Uv5f41Yht0i56t60+OZZGZFzlTg0ku5Up6WgSgAcCiojMolEP
+ OSM+1S1dzFoKKKiml8lN+M0N2BK+iJaKhM6h1Qg5cZqalcGrBRRRTEFFFIGUkgEEjrQA
+ tFFFABRUU0vkpvxmpFO5QfWlfoO2lxaKKKYgooooAKKKKACioVm3TNDj7o61NSTuNq24
+ UUUUxBRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFF
+ ABRRRQB//9DpKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igAooooAKKKKACiiigApCM896WigCNSwOG/OpKCARg1GFKZI59qWwtiSimq4bpTqYwoo
+ ooAKyr+2kDC+tf8AWx9R/eHpWrRQBXtbmO7hE0ffqPQ+lWKxLhW024+2RD9zIcSKOx9a
+ 0Tch8LbYkYjOf4QD6n+lAFkkKMscAVX+1I3+pVpfdRx+ZwKBbBjvuD5je/3R9B/k1ZoA
+ rbrtuiIv1Yk/kB/WjF5/ej/I/wCNWaKAK267XqqN9GI/oaPtIX/XI0fuRkfmM/rVmigB
+ qsrqGQgg9xzWDqWqS21yIoMYVfmz6n/CthrZNxeImNz3Xv8AUdDWdDaQxXBe8XdK7ZDH
+ 7p9h6H2P4UAS6ZbosX2piXll5Zj1+lalFFABRRUckqRLuc0AlckJAGT0rOnu8/LF+dQS
+ zyTnaOnYCrMFoB80vJ9Ki7eiN1BR1kV4bZ5fmbhfX1rVRFjXagwKdRTUbGc5uQVStf8A
+ XTfX+pq7VN4JVkMsDAE9QaJdGELaoRv+P5f93/GoxJcyM4RgApqeGB1kMsxyxp0MLRtI
+ WI+Y5FTZluSRALpxbeYfvZxUVwLkRZlIIP6VOtqfIMTEZzkEUx4LqRdjsMCpadtSk4p6
+ EhkZZYkHQjmo1e5ld1RgAp6mpzCxljfIwgwaWCJo2ctj5jkYqrO5N1Yqtcu7ttcIB046
+ 1It0fs5kI+YHFBtpEdmi24b+8OlS/Z90HlOeT3ApJSG3DQjVbw4YsOR+VQwLN574YZB+
+ b3qxHHdKyhmG0frSCGZJy8ZG1jzmi2wX3WhC1y7u21wgHTjrTxdt9n3/AMWcUptpEdmi
+ 24b+8OlPNsWg8tiN3XOKLSBuGhWuBciLMpBB/StJPuL9BVF4LqRdjsMCr6jCgHsKqK1J
+ m9Eim0k8sxjhIUL1NEUk3nNFKR8q9qbIhWctDIFY9QaZbBjcOSd3HJqbu5VlYdbvczYY
+ sNoPPvTZZ5FJIlXIPAAq1bwtFGUYjJPaqwtZlVowVwe/eizsCcbsWS4lIiMfBft70pku
+ IHXzSGVjio5Y2XyY84b1/GphBNI6tOwIXsKNR+6kRESm7cREA46n8KsWsryBlk6qcU5I
+ mW4aU4wwogiaNnLY+Y5GKaTTJlJNFiiiitDEKKKKACiiigAooooAKKKKACiiigAooooA
+ KKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/R6SiiigAooooAKKKKACiiigAooooA
+ KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigBCoII6Zpg3
+ IDu5FSUUrCsNVg3SnU0qCDjjNNG5Qd3NF+4X7klFMWRWOBUc8jIoWP77nC/4/QUJ3BO5
+ HOTcFrWPp0duuAew9z+lULNmsLk6fKfkb5o2/pWtFGsSBF59SepPcmquoWv2qD5OJE+Z
+ D7imMvUVTsbr7XbiQ8MOGHuKuUAFFFFABRRRQAU10WRSjjIPUGnUUAVEZrdxFKco3CMf
+ /QT/AEP+Tbpkqo8bLJ90jmss3chTys5I43dyOxpN2LjBy2Ls90sfyry38qz1WW4fPU9z
+ 6VLBatJ8z8L+prTVFRdqjAqLN7mrkoaLcihgSEccn1qeiitLGDberCiiigQUUUUAFFFF
+ ABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAEL28Mh3MvNPSNIxhBin0UrIfM9gooopiGNG
+ jsGYZK9KfRRQFwooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAK
+ KKKACiiigAooooAKKKKACiiigD//0ukooooAKKKKACiiigAooooAKKKKACiiigAooooA
+ KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigBnlpUEX72Z
+ 5j0X5F/D7x/Pj8Kmmk8qJ5P7oJ/Kkgj8qFIz1A5+velYViWiiimMxl/0LVCo4juRn/gQ
+ /wA/rWzWVq6H7MJ1+9CwYVpo4kRXXowBH40AOooooAKKKKACg9OOaKKAMaWWWd9pH0Wp
+ Db+QFnfnaRuHseP061phEDFwOT1NDqroUbkMMH8alR6s1lU0tEdRUFszPApb7wG0/UcH
+ 9RU9UZBRRRQAUVEGkbJAGMkcn0OKN0mcfLk89T/hQBLRUf730X8zR+99F/M0ASUVCXcE
+ KduT7n/CnfvfRfzNAElFR5k6fLz70fvfRfzNAElFR/vfRfzNH730X8zQBJRUTNKqliBw
+ M9aloAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooo
+ oAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA//0+kooooAKKKKACii
+ igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
+ oooAKKKKACiiigCtd8w7f7zIPzYCrNVrr7in0kT/ANCFWaAKUcbTNIzSOMOQADgACpPs
+ 3/TWT86Lb/lp/wBdGqzQBnXltm1l/eOcITgnjgVHYRGSzifzHHy9AfTitKVPNiePONyk
+ Z+tR20H2aBIAd20YzQA37N/01k/Oj7N/01k/OrNFAFb7N/01k/Oj7N/01k/OrNFAFb7N
+ /wBNZPzo+zf9NZPzqzRQBW+zf9NZPzpbUsY2DEttdhk9cA1YqpbhyH2nA8xu3vQA624M
+ q+kh/UA/1qzVOBSzzfMfv9u/yirHlL3yfqTQA8kDqcUzzY/7wP0pRHGOij8qfQBFHzGc
+ erfzNRq7AABTgL6d6ejooIY4O4/zNO82P1oArgudrHdweePbtxU0rOCAnp6ZyfSnebH6
+ 0ebH60ANQOZWLEcYHSoirea2RnJ44J4/PFTCSIEkHrS+bH60AV8yF9+CcZ49+1LvlXPJ
+ ORkZ9eO3pU/mx+tMVoU5B/M5oAjDuNoyzD2HXn6VbqPzY/WjzY/WgAl/1TfQ1JUEkiGN
+ gDkkGp6ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAK
+ KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP//U6SiiigAooooA
+ KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKAK92Cbd8dQNw+o5/pU4IYBh0PNL14qtanbGYT1iO38B0/TFACfZ3
+ DMY5WUMc4wp5/EUvkzf892/Jf8Ks0UAVvJm/57t+S/4UeTN/z3b8l/wqzRQBW8mb/nu3
+ 5L/hTCrhxGZ33MMj5V7f8BqoLWf7V5jA58zduGPu+mc56dsUkNvMssbGMqwDB3yDknvj
+ NAF/yZv+e7fkv+FHkzf892/Jf8KyYomd3jiAWQRFSQ275s9c9s/nUq2sqxyBY2G4KNvy
+ jODyepH59aANHyZv+e7fkv8AhR5M3/PdvyX/AApllE8UbKy7ctkDgdh2BIH4VcoAreTN
+ /wA92/Jf8Kkhi8pNuSxJJJPqTntUtQXLskJ2feb5V+p4FADbTmIyf32ZvwJ4/SrNNRFj
+ RY16KAB+FOoAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
+ oooAKKKKACiiigAooooAKKKKAP/V6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
+ oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACqsv7mUXH8J
+ +V/6H8P61apGUMCrDIPBFAC0VUiYwMLeQ8H7jHuPQ+4/WrdABUBtrZiSYkJP+yKnooAO
+ nAooooAQADoKWiigAooooAKqr+/uN/8ABFkD3bufw6fnSzSMzfZ4T856n+6PX6+lToix
+ oEQYA4FADqKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigA
+ ooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoooo
+ AKKKKACiiigAooooAKKKKACiiigD/9bpKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAGSR
+ pKhRxkGq4le3+W4OU7Sf/Fen16VbooAAQRkUVV+zmPm2bZ/snlfy7fhS+dKnE0R+qfMP
+ y6/pQBZoquLu26GQKfRvlP64p/nwYz5i/mKAJaKrm7tgceYpPoDk/kKTz3f/AFMTH3b5
+ R+vP6UAWaqmZpSUtuexfsPp6mjyHl/4+WyP7i8L+Pc/y9qsgBRgDAFAEcUSQrtTucknq
+ T6mpax7qMmeRkU7vlxhCckf7Xb61LvmF2Dhwu/BGGIxjg+n5Vr7PS9xXNOisuIzmcn5z
+ 97ruA9sg8flUcMc037ucthlIcEHGfx449qPZ92FzYorKCTmJ5lTbJhUGBzgdSP6fSm5l
+ EL/NJ1G3AbI9evJH14o9n5hc16Kz5YswoyNIQHBPXdjvweaZOZW8vZvEeDnhs57ZxzSU
+ L9QuadFZEn2jamDISF+fAIyMjp/tVduMmFdhYcjs2ce+OaHC1tQuWqajhxlexI/I4rP8
+ yYRkFX3MFwOTj15pEDqxC+YH80467dpbn26fjR7MLmi7iNS7dBTqzcM0TBt5kIO4HOOv
+ bt9MUmZjOSN6g7gepx6Hnj6Yo9mFzTorIJm8v+P5Sf7/AM3A/EfjkVrDkAnilKNhi0UU
+ VABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABR
+ RRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAH/1+kooooAKKKKACiiigAo
+ oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
+ KKKKACiiigAooooAKKKKACiijIHWgAIB4NR+VF12L+VOLqBk96TflcqM0roV0OAAGAMU
+ tMy5B4waAH53Gi4XH0UxVIOSxNAjAOcmi7C7H0VH5a5zSmNScmjUNR9FMKAnOTQUOAAS
+ MUXYXY+imYcDAPNGXC5Iyfai4XH0UwOCCSMYpwYHoaLhcWiiimMKKKKACiiigAooooAK
+ KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA
+ CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP//Q6SiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igAooooAKKKKACiml1Bx3pp8wn0FK4rjyQOpprOQcAZNGxc5Ip9GoajCHPQ4FBQHG7nF
+ PoosFhAAOBS0UUxhRRRQAUUUUAFFFFABRRRQAUUUUAHWm7F5xxmnUUWCwwKy98ihXydp
+ GDT6KVuwrdg69KKYECnK/lQrknawwaL9wv3H0UUUxhRRRQAUUUUAFFFFABRRRQAUUUUA
+ FFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFF
+ ABRRRQAUUUUAFFFFABRRRQAUUUUAf//R6SiiigAooooAKKKKACiiigAooooAKKKKACii
+ igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooJA61GS5bA4A70mx
+ Nji6g4PWm4ctycAU8KoOQOaWi3cLdxAoByBS0UUxhRRRQAUUUUAFFFFABRRRQAUUUUAF
+ FFFABRRRQAUUUUAFFFFABRRRQAUUUUARhShyDx6U5XDfWnU0r1I4PrStbYVrbDqKYpYc
+ P270+hMEwooopjCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigA
+ ooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/0ukooooA
+ KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAprMFHNDNtFIFzhmHNJvohN9EIU3HcenpUlFFCQJBRRRTGFFFFABRRRQAUUUUA
+ FFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFR7nLELjA9aP3v+z+tAElFR/vf9n9aQGRhk
+ FSPxoAloqP8Ae/7P60fvemVoAkoqP97/ALP60fvf9n9aAHkBhg0zPljk5FH73/Z/WgiU
+ 8Hb+tJoTRJ15FFQEyRjtipEYtnPY44+maEwTH0UUUxhRRRQAUUUUAFFFFABRRRQAUUUU
+ AFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFF
+ FABRRRQAUUUUAf/T6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igAooooAKKKKACiiigAooooAKQnA45pajCkvuPQdKTExUDYy3en0UUIEgooopjCiiigA
+ ooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCNPvv9R/IVHmQ8NkbepA6
+ /hUifff6j+Qp+5eOevSgCKEnZg5z3zURkk2rkN05wOTVuigCCYvgBAec9KYC4ycHJUHp
+ 6VaBBGRR05NAFVmmIPGMc8e/QUK0ij5t2N31OMVapjpuwQcEcigCuZJMHOR83brjH0q0
+ DkA/zpqqEHJ5J5PvT6ACoVLB2wMjOP0FTVGn3n/3v6Ck0JokoqMDyyeflqShMEwooopj
+ CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiii
+ gAooooAKKKKACiiigAooooAKKKKACiiigD//1OkooooAKKKKACiiigAooooAKKKhknii
+ ba7YOM460ATUVW+12/8Ae/Q/4Ufa7f8Avfof8KALNFVvtdv/AHv0P+FH2u3/AL36H/Cg
+ CzRVb7Xb/wB79D/hR9rt/wC9+h/woAs0VW+12/8Ae/Q/4Ufa7f8Avfof8KALNFVvtdv/
+ AHv0P+FH2u3/AL36H/CgCzRVb7Xb/wB79D/hR9rt/wC9+h/woAs0VW+12/8Ae/Q/4Ufa
+ 7f8Avfof8KALNFVvtdv/AHv0P+FH2u3/AL36H/CgCzRVb7Xb/wB79D/hR9rt/wC9+h/w
+ oAmcFvlH408DAwKppcwAks3J9j/hT/tdv/e/Q/4Ul3Eu5Zoqt9rt/wC9+h/wo+2Ww5LY
+ HuDTGWaKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACo2JY7E/E
+ +n/16VmOdidT+lOVQowKAI41Cl1HTP8AQVD5cgUKMjDdSe3PIqUOiu4ZgOR1PsKd5sX9
+ 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
+ 8KOaPYCD7TO0DTCPACkjJ7j+lPe5aOESSJgkgAZ65qWOCONDGoO09iSf5mmi1hClMEg4
+ 6kk8dMHPFK8ewEP2w+UZSnCthueg9RxzUyTO1v55TnGQoOSR2/Ol+zRYAIJw27lj19+e
+ ackMaRmJQQpzxk96G49EBHFceYVGB8xPQ56fgKhSaV5i0aZyinBOMct7VY+zRYxz1znJ
+ znGOuc9KT7JBxgEYG3gkcenWneIDY7hpiDEmVwMknB556VAt0YYY8jd8oJ55/LB/pVv7
+ PFuDAYxgcEgcdOBTTawMMEHGAMZPQdM80Jx7AR/a2zINnKZ4zycHGcY6d+M1Yhk82MPx
+ z6HIpn2eIksQcn3PGTnjnj8KkSNY12p06+vWpk420GPoooqACiiigAooooAKKKKACiii
+ gAooooAKKKKACiiigAooooA//9XpKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igAooooAKKKKACiiigAooooAKKKKACiiigApjg8MvUU+ik0JoBRUeCrEjoetSUIEFFFF
+ MYUUUUAFRTwrcQtC/RhipaKAMvTJmKNZzf6yA7fqOxrUrI1CJ4ZF1G3HzR/fHqtacMyT
+ xLLGcqwzQBJRRRQAUUUUAFFFFABRRRQAUUUUAFFFQXFxFaxGWU4A/Mn0FABcXEVrEZZT
+ gD8yfQVnW1vLeSi+vRgD/Vp6D1NJb28t7KL29GFH+rj7AeprZoAKKKKACiigkAZPAoAK
+ rT3KxfKOW9Krz3ZPyxcD1qKG2aX5m4X+dQ5dEbRp21mRgS3L+p/QVpQ26QjPVvWpkRY1
+ 2oMCnU1Gwp1L6LYKKKKoyCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igD/1ukooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igAooooAKKKKACiiigAIBGDUY/d8MfpUlIQGGDSaE0LRUefLwD09ak680JgmFFFFMYUU
+ UUABAIwawxnSrnaf+PaY8f7LVuVFPDHcRNDKMq1AEtFY9lNJbS/2ddHkf6tvUelbFABR
+ RVdrmPJWPMjDsoz+Z6D8TQBYoqtuu2+6ioP9o5P5D/GjZdnrKo+if/ZUAWaKrbLsdJEP
+ 1U//ABVHmXKffjDD/YPP5HH86ALNFQJcRO2zO1v7rDB/WquqXJtrRihw7fKtAFq4uIrW
+ IyynAH5k+grNt7eW9lF7ejCj/Vx9gPU1U0/dqM/nXeW8sfKMfLn/ABrpKACiiigAooqp
+ PdLH8qct/Kk3Yai3oieSVIly5/CsqWaSdto6dgKRUluHz1PcmtSGBIRxyfWo1kb+7D1K
+ 8FoF+aXk+lXqKzEhWaaUMSMHt9ae2iM/iu2zTorO+e1lVd25G9amUxrcSMN24DJ9KfMD
+ gW6KqpdxyMFUHJoa7iBIAJA6kDijmQuSXYtUVE08aRiQng9Kh+2RkHAbI9qbkhKDfQt0
+ VStrkyDbJkt69qebyIHgEj1xxS5la43Td7FqkLKpAYgZ6VFJPHGgcnIPTHeqUkyzSxbQ
+ Rhuc/hQ5JBGDZp0UVVa7iVivJx1IptpbkqLexaoqutzGyNIM4WkS6jkOFB4Gc0cyHyPs
+ WaKqi8jyMhgD3I4p0lzHE2xs5xmlzIOR7WLFIrK33SD9KgiuY5W2jIPoapwXCQhgwJye
+ 1JzRSpvU1KKajrIodehp1WZhRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFF
+ FFABRRRQAUUUUAFFFFABRRRQAUUUUAf/1+kooooAKKKKACiiigAooooAKKKKACiiigAo
+ oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAOvBqNg4O5fyqSik0
+ JoTcM7e9LTWRW600l1PTIov3C/ckopMgnFLTGFFFFAFK+tBdxYB2yLyjehqC11APGUmB
+ 89DtKDqT6ir00vlAADc7HCr6n/D1rJu7ea1I1GM7pF/1g7FfYegoA0vJkm5uTx/cXp+J
+ 7/yqyqqoCqAAOgFMhlSeJZYzlWGRUlABRRRQAUUUUAMeNJV2yKGHvWbcWO51d8zRp/yz
+ J5H0Pf6GtWigCKFomjBhxtHGBxj2xUtVpYnVvPg+/wDxL2Yf4+hqaORZUDp0P5g+hoAf
+ SEhRljgCo5ZkiGW69hWXJLJcNj8gKlysaQpuWpNPdlvli4HrTYLVpPmfhf1NWILQJ80n
+ J9Owq7SUb6st1FHSA1VVBtUYFOooqzAKy0nSGaUsCcnt9a1KKlq5UZWvczxvupVbbtRe
+ eaP+Xmb/AHP8K0KKXKV7TyKdoubbA4JzVFf3atG7Mp/ujvW1RQ4bDVTVmZJGUiicAlVO
+ SD71ajuI5mKoDnHWrNFNRtsJzutTMtmBia36Oc/yqAEKhjdmB/u4rawOtFTyFe112M2R
+ DF5UhBKr1zTZJlmmjKA4BHP41qUU+QSqd0FZkMotg0cinOe3etOqZjuwSFcEH1ol3QoN
+ aplWP/j3m4xzVtSyWgaMc7algh8lNuck8k1NRGI5TTZiSPvjGXZj3HYVZmcR3SuwyAta
+ VVzExuBNxgDFTyMpVEysGFxcq8YOF6mi3A8mX8f5Vo0VXL1Ic+hVs/8AUD6mrVFFUlZW
+ Ik7u4UUUUxBRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUU
+ AFFFFABRRRQB/9DpKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAYUUnPQ0hZ1PTIqSilYVhNyjg
+ mhmCqWY4AGSaY8YY5HFV5QXZLYnIblv91e34nAou7hd3HwKXJuZBhm+6D2Xt+J6mrJAI
+ welFFMZi2ubC9ayb/VyfNH7eorarM1WEyW/nR8PCd6n6dau28wuIEmX+IZoAmooooAKK
+ KKACiiigArMmnEExaE53feHbPY/41JeSSqdg4U9/WoobQyDdLwvp3NQ29kbRgkuaREkc
+ tw2fzJrUihSEYXr3NR2pPleW33oyVP4d/wARzVmmo2JnUctAoooqjMKKKKACiiigAooo
+ oAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKK
+ KKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigD//R6SiiigAo
+ oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
+ KKKKACiiigAooooAKKKKACiiigAqtF888snphB+Ayf1NWarWvMbN6u5/8eNAFmiqs675
+ ooySFO4nBI6D2xS/ZIvWT/v4/wDjQBYIBBB5BrJ0klEltT/yxcgfQ1e+yResn/fx/wDG
+ su3gQancRZbGFPDMD0HU5yevegDdoqt9ki9ZP+/j/wCNH2SL1k/7+P8A40AWaKrfZIvW
+ T/v4/wDjR9ki9ZP+/j/40AWaKrfZIvWT/v4/+NH2SL1k/wC/j/40AWCobGRnFLVb7JF6
+ yf8Afx/8aYIxDcoELYZWyCzN0x6k0APHyXbDtImfxU4P8xVmq0vFxC3qWX8xn+lWaACi
+ iigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigA
+ ooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoooo
+ AKKKKAP/0ukooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKrWn+px6M4/JjVmq1v8AK8sf
+ o+R9GGf55oAJf+PmH/gX8qs1FLCJSpyVK9CPeo/s5/56yfmP8KALNVktUS6e6BO5wAR2
+ 4o+zn/nrJ+Y/wo+zn/nrJ+Y/woAs0VTeNIhukndR6lgP6UyURxJvad+RkDcOfpQBfoqi
+ VjVQz3DLuGRlgP6UpSMMENw249BuGT+lAF2iqWyMv5QuG3/3dwz+WKk+zn/nrJ+Y/wAK
+ ALNVpP8Aj6i/3X/pR9nP/PWT8x/hSpbhJBIXZiAQNx9f/wBVACTczQD/AGif/HT/AI1Z
+ qsfmu1H9xCT/AMCIA/kas0AFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUU
+ UUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAF
+ FFFABRRRQAUUUUAFFFFABRRRQAUUUUAf/9PpKKKKACiiigAooooAKKKKACiiigAooooA
+ KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACqz/u7lJO0g2H6jkf1qzUc0YljMZOM9D6EdD+BoAkoqGCUyplhhlOGHoRU1ABUbyxRY
+ 8x1XPTJAqSigDPnT7UyS27q3l5BAbHX3GahNjKqbEVDuTZ8xPy8k5HHPX2rWooAxbqGR
+ VC4VmdVXGCxBX0OOn1xU0llI0zsMMrsG5YjGMdgOenqK1KKAM6O2mW48w7QoZm4JPXPY
+ jg+uDWjRRQAUUVWuGLYt0PzSdT6L3P8AQe9ABbfPvn/56Hj/AHRwPz6/jVmkUBQFUYA4
+ FLQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQA
+ UUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUU
+ AFFFFABRRRQB/9TpKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCtKjI/2iIZOMMo
+ /iH+IqaORJUEkZyp6Gn1WeJ42MtvjJ5ZD0PuPQ0AWaKiimSXIXhh1U8EfhUtABRRRQAU
+ UUUAFFFQSTqjeWg3yf3R/U9hQA6WVYVyeSeAB1J9BTYYmXMknMj9fb0A9hRFCQ3myndI
+ ePYD0FT0AFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQA
+ UUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUU
+ AFFFFABRRRQAUUUUAFFFFAH/1ekooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igCKSGOXBYcjoRwR9DUWLqLoRKPf5W/McH8hVqigCt9pC/61HT/gOf1XNH2y17yKPqcf
+ zqzRQBW+2W3Zw305/lR9oLf6qN29yNo/8ewf0qzRQBV8u4l/1rhB/dTr/wB9H+gFSqkc
+ CHYMAcnHJ/xNS01wShC9SOM0ICOO4ik+6ccbuQRx6804SxFDIHUqOpyMfnVCOznRWxtQ
+ mPZwS2T68jigWs4VxhfmKkfMxIx74rVwj0Yi/wCdDs8zeu31yMfnSefFuCA5LAsMAkED
+ 3FUjaTGNckblctjPqPXHX3xTvskghAjIRwxOck/e68/r9aOWPcC0LiEorlgobpu4z+dO
+ aaJCQ7qCOuSBVOa0ZnBjwV2bNpJGB+Rp/kSCWNtiMqLt5Jz256H+dHLHuBZE0TOYww3D
+ tS+bFuKbhuHUZ5qv5LrOZI1QhsZJ4Ix1xxUCWciSA8MFYsCWPfPbH9aXLHuBeWaJiArq
+ SeRgjmlMkYbYWAbGcZ5xVO3t5opTIwXDZyAT8vP8PHT196dJbyPMWXAVupz14x0x1980
+ csb2uBPLKI13Ag8r+RIGacJoihkDqVHU5GKpvbzyKQwT7qgDJIODnninNBK7+cQobK4X
+ PB256nHv6UcsbbgT+em/qNm3duzx1xT/ADoQocuu09DkYNV5IZn+YbVbGMA++euPTvio
+ TazbDjG7cxB3HjIHtz78U+WPcC+JIyxQMCw6jPNPqpFDKkxc4CnOec5J9scfnVuokkth
+ hRRRUgFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUU
+ UAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQB//W6SiiigAooooAKKKKACii
+ igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
+ oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
+ KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/X
+ 6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
+ oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
+ KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKAP/Q6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
+ oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
+ KKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/R6SiiigAooooAKKKKACiiigAooooA
+ KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
+ ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
+ igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
+ oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/Z
+
+ DKDChangeTimeStamp
+ 2026-10-12 02:31:53 +0600
+ DKDCreateTimeStamp
+ 2020-09-22 04:51:46 +0600
+ DKDDisplayGraphicDetails
+
+ AngleFormatDisplayDetails
+
+ AngleDirection
+ Right
+ AngleForm
+ degrees
+ AngleRotation
+ Counter Clockwise
+ PrecisionAngles
+ 1
+
+ AnglesDisplaySpec
+
+ FormDisplaySpec
+ Decimal
+ PrecisionDisplaySpec
+ 2
+ TextAlignDisplaySpec
+ Left
+ UnitsDisplaySpec
+ Punctuation
+
+ AreaForm
+ Natural
+ HelpTipDisplaySpec
+
+ FormDisplaySpec
+ Decimal
+ PrecisionDisplaySpec
+ 3
+ TextAlignDisplaySpec
+ Left
+ UnitsDisplaySpec
+ Abbreviate
+
+ InspectingSpecIndex
+ 0
+ LengthsDisplaySpec
+
+ FormDisplaySpec
+ Decimal
+ PrecisionDisplaySpec
+ 2
+ TextAlignDisplaySpec
+ Left
+ UnitsDisplaySpec
+ Nothing
+
+ PercentDisplaySpec
+
+ FormDisplaySpec
+ Decimal
+ PrecisionDisplaySpec
+ 1
+ TextAlignDisplaySpec
+ Left
+ UnitsDisplaySpec
+ Punctuation
+
+ PercentFormatDisplayDetails
+
+ PercentForm
+ Percent
+ PrecisionPercents
+ 1
+
+
+ DKDDocumentRuler
+
+ AutoLightDarkModeulerStyle
+ YES
+ RulerBackgroundRGB
+
+ Catalog
+ System
+ Catalog-Color
+ windowBackgroundColor
+
+ RulerBorderLineWidth
+ 1
+ RulerBorderRGB
+
+ Catalog
+ System
+ Catalog-Color
+ systemGrayColor
+
+ RulerFontIOS
+
+ Family
+ .AppleSystemUIFont
+ Name
+ .AppleSystemUIFont
+ Size
+ 10
+
+ RulerHasBackgroundColor
+ YES
+ RulerHasBorder
+ YES
+ RulerHeightHorizontalRuler
+ 20
+ RulerTextRGB
+
+ Catalog
+ System
+ Catalog-Color
+ systemGrayColor
+
+ RulerTickPattern
+
+ TickPatternStyle
+ Quarters
+
+ RulerWidthVerticalRuler
+ 18
+
+ DKDExportDoc
+
+ BMPExporBackground
+ No (White) Background
+ BMPSpecification
+
+ ColorDepthWIS
+ 256 Colors
+ ColorListNameWIS
+ 256 Best
+ HeightWIS
+ 64
+ WidthWIS
+ 64
+
+ CSVStringEncoding
+ Unicode (UTF8)
+ DXFExportLayers
+ All
+ DXFExportRevision
+ AutoCADLT 2010
+ ExporBackground
+ No (Black) Background
+ ExportColorTable
+ 256 Best
+ ExportCompresion
+ 1
+ ExportContent
+ Just Graphics
+ ExportExpand
+ 3.944
+ ExportFileExtension
+ png
+ ExportImageAntialias
+ YES
+ ExportImageInterpolation
+ None
+ ExportTransparentColor
+ Automatic
+ GIFExporBackground
+ White Background
+ GIFFDither
+ NO
+ HideExtension
+ NO
+ ICOColorTable
+ 256 Best
+ JPGColorSpace
+ sRGB_ColorSpace
+ JPGExporBackground
+ White Background
+ PDFExporBackground
+ No (Black) Background
+ PDFPagination
+ Single Page
+ PDFXMirror
+ NO
+ PDFYMirror
+ NO
+ PNGAlpha
+ YES
+ PNGColorSpace
+ sRGB_ColorSpace
+ PNGExporBackground
+ No (Black) Background
+ PNGInterlace
+ NO
+ SVGCompress
+ NO
+ SVGDOMIds
+ YES
+ SVGEmbedImages
+ YES
+ SVGFont
+ SVG
+ SVGGlyphs
+ System Font
+ SVGOverwriteImages
+ NO
+ SVGProfile
+ SVG 1.1
+ SVGTidyFormatting
+ YES
+ TIFExporBackground
+ No (Black) Background
+ TIFFColorSpace
+ sRGB IEC61966-2.1
+
+ DKDGrids
+
+ DynamicSnapGrid
+ YES
+ GuidesLayer
+ NO
+ MajorGrid
+
+ GridAboveGraphics
+ NO
+ GridRGB
+
+ BluePlus
+ 1
+ ColorSpacePlus
+ DKDP3ColorSpace
+ GreenPlus
+ 0.713725
+ OpacityPlus
+ 0.6
+ RedPlus
+ 0.54902
+
+ GridSpacingX
+ 72
+ GridSpacingY
+ 72
+ LinkGridToRulers
+ NO
+ PrintLineWidth
+ 1
+ PrintsGrid
+ NO
+ ShowsGrid
+ NO
+ SnapsToGrid
+ NO
+
+ MinorGrid
+
+ GridAboveGraphics
+ NO
+ GridRGB
+
+ BluePlus
+ 0.87451
+ ColorSpacePlus
+ DKDP3ColorSpace
+ GreenPlus
+ 0.854902
+ OpacityPlus
+ 1
+ RedPlus
+ 0.745098
+
+ GridSpacingX
+ 18
+ GridSpacingY
+ 18
+ LinkGridToRulers
+ NO
+ PrintLineWidth
+ 0.5
+ PrintsGrid
+ NO
+ ShowsGrid
+ YES
+ SnapsToGrid
+ NO
+
+ SnapDrawing
+ NO
+ SnapEnds
+ NO
+ SnapGuidelines
+ NO
+ SnapRadiusGrid
+ 3
+ SnapSound
+ None
+ SoftSnap
+ YES
+
+ DKDHideExtension
+ YES
+ DKDLayersList
+
+
+ CloakLayerGuidelines
+ NO
+ CloakLayerVertices
+ NO
+ FullLayerScale
+
+ ArchivePrecision
+ 12
+ ScaleOriginX
+ 0
+ ScaleOriginY
+ 0
+ ScalePlusDown
+ YES
+ ScalePlusToRight
+ YES
+ ScaleScale
+ 1
+ ScaleUnits
+ Centimeters
+
+ GraphicsList
+
+
+ Bounds
+ {{294.224122401, 275.716405174}, {108.290742591, 108.290742591}}
+ Class
+ DKDCircle
+ DKDLockInfo
+ 10
+ GraphicID
+ C0B95773
+ GraphicStyle
+ 8
+
+
+ Bounds
+ {{503.514284115, 126.757499453}, {108.290742591, 108.290742591}}
+ Class
+ DKDCircle
+ DKDLockInfo
+ 10
+ GraphicID
+ 6F7E8773
+ GraphicStyle
+ 8
+
+
+ Bounds
+ {{328.835052797, 128.125047075}, {78.4881890125, 78.4881890125}}
+ Class
+ DKDSquare
+ GraphicID
+ 17CBE773
+ GraphicStyle
+ 8
+
+
+ Class
+ DKDLine
+ GraphicID
+ 73CA6873
+ GraphicStyle
+ 24
+ SVGPath
+ M387.399317029,309.662716377 L529.441939138,204.802059204
+
+
+ Bounds
+ {{305.98064227, 322.038627768}, {87.782600853, 16.648764451}}
+ Class
+ DKDRectangle
+ GraphicID
+ 614BBC73
+ GraphicStyle
+ 8
+
+
+ Class
+ DKDContinuousBezier
+ DkBezArrow
+ 10
+ GraphicID
+ C2545D73
+ GraphicStyle
+ 40
+ SVGPath
+ M328.408013566,330.573918646 C328.408013566,330.573918646 328.408013566,330.573918646 328.408013566,330.573918646 C330.201032664,294.273031091 287.069985825,268.786411738 281.183724024,239.232245681 C276.209392441,214.256764372 278.407101059,179.831516338 325.442174032,178.964447435
+
+
+ AttributedText
+
+ String
+ _edges
+ TextAttribute
+ 0
+
+ Bounds
+ {{324.236569375, 338.377538768}, {78.3773221901, 21.0231661209}}
+ Class
+ DKDTextArea
+ GraphicID
+ 35D9CF73
+ GraphicStyle
+ 10
+
+
+ Class
+ DKDContinuousBezier
+ DkBezArrow
+ 26
+ GraphicID
+ 2BF2D183
+ GraphicStyle
+ 56
+ SVGPath
+ M389.018941427,152.095726702 C389.018941427,152.095726702 389.018941428,152.095726702 389.018941428,152.095726702 C410.302813906,152.053209509 440.736837683,163.117618759 446.549458254,183.026391843 C455.368197175,213.231403497 397.85483445,259.798877024 376.502004957,283.853746525
+
+
+ Class
+ DKDContinuousBezier
+ DkBezArrow
+ 26
+ GraphicID
+ AC19D283
+ GraphicStyle
+ 56
+ SVGPath
+ M388.651791845,172.116425773 C388.651791845,172.116425773 388.651791845,172.116425773 388.651791845,172.116425773 C432.427131192,172.591985962 437.539749991,148.859460237 462.719663264,143.758325424 C478.393662924,140.582969557 494.172144152,141.591955073 511.079252224,151.463000746
+
+
+ AttributedText
+
+ String
+ v1
+ TextAttribute
+ 0
+
+ Bounds
+ {{358.242750341, 142.935407683}, {31.0306494531, 21.0231661209}}
+ Class
+ DKDTextArea
+ GraphicID
+ 38F37683
+ GraphicStyle
+ 8
+
+
+ AttributedText
+
+ String
+ v2
+
+ TextAttribute
+ 0
+
+ Bounds
+ {{358.236818933, 163.775211565}, {30.9110329578, 22.1917445833}}
+ Class
+ DKDTextArea
+ GraphicID
+ 19EDA683
+ GraphicStyle
+ 8
+
+
+ AttributedText
+
+ String
+ BaseVertex subclass
+ TextAttributes
+
+ {0, 10}
+ 16
+ {10, 9}
+ 32
+
+
+ Bounds
+ {{586.619482542, 221.377689725}, {135.410183231, 32.1481976616}}
+ Class
+ DKDTextArea
+ GraphicID
+ 09BB7C83
+ GraphicStyle
+ 10
+
+
+ AttributedText
+
+ String
+ Edge subclass
+ TextAttributes
+
+ {0, 4}
+ 16
+ {4, 9}
+ 32
+
+
+ Bounds
+ {{329.991616456, 208.243955856}, {90.1938101669, 21.4163415091}}
+ Class
+ DKDTextArea
+ GraphicID
+ 18ED7C83
+ GraphicStyle
+ 10
+
+
+ Bounds
+ {{313.182629892, 635.149616291}, {108.290742591, 108.290742591}}
+ Class
+ DKDCircle
+ DKDLockInfo
+ 10
+ GraphicID
+ 5943FD83
+ GraphicStyle
+ 8
+
+
+ Bounds
+ {{522.472791607, 486.19071057}, {108.290742591, 108.290742591}}
+ Class
+ DKDCircle
+ DKDLockInfo
+ 10
+ GraphicID
+ 6943FD83
+ GraphicStyle
+ 8
+
+
+ Bounds
+ {{347.793560289, 487.558258192}, {78.4881890125, 78.4881890125}}
+ Class
+ DKDSquare
+ GraphicID
+ 7943FD83
+ GraphicStyle
+ 8
+
+
+ Class
+ DKDLine
+ DkBezArrow
+ 42
+ GraphicID
+ 8943FD83
+ GraphicStyle
+ 24
+ SVGPath
+ M406.357824521,669.095927494 L548.400446629,564.235270321
+
+
+ Bounds
+ {{324.939149762, 681.471838886}, {87.782600853, 16.648764451}}
+ Class
+ DKDRectangle
+ GraphicID
+ 9943FD83
+ GraphicStyle
+ 8
+
+
+ Class
+ DKDContinuousBezier
+ DkBezArrow
+ 10
+ GraphicID
+ A943FD83
+ GraphicStyle
+ 40
+ SVGPath
+ M347.366521058,690.007129763 C347.366521058,690.007129763 347.366521058,690.007129763 347.366521058,690.007129763 C349.159540156,653.706242208 306.028493317,628.219622855 300.142231515,598.665456798 C295.167899934,573.689975489 307.044296477,540.532783177 344.400681524,538.397658552
+
+
+ AttributedText
+
+ String
+ _edges
+ TextAttribute
+ 0
+
+ Bounds
+ {{343.195076867, 697.810749885}, {78.3773221901, 21.0231661209}}
+ Class
+ DKDTextArea
+ GraphicID
+ B943FD83
+ GraphicStyle
+ 10
+
+
+ Class
+ DKDContinuousBezier
+ DkBezArrow
+ 26
+ GraphicID
+ C943FD83
+ GraphicStyle
+ 56
+ SVGPath
+ M407.977448919,511.528937819 C407.977448919,511.528937819 407.977448919,511.528937819 407.977448919,511.528937819 C429.261321398,511.486420626 459.695345175,522.550829876 465.507965746,542.45960296 C474.326704667,572.664614614 416.813341941,619.232088141 395.460512449,643.286957642
+
+
+ Class
+ DKDContinuousBezier
+ DkBezArrow
+ 26
+ GraphicID
+ D943FD83
+ GraphicStyle
+ 56
+ SVGPath
+ M407.610299337,531.54963689 C407.610299337,531.54963689 407.610299337,531.54963689 407.610299337,531.54963689 C451.385638684,532.025197079 456.498257482,508.292671354 481.678170755,503.191536541 C497.352170416,500.016180674 513.130651644,501.02516619 530.037759716,510.896211863
+
+
+ AttributedText
+
+ String
+ v1
+ TextAttribute
+ 0
+
+ Bounds
+ {{377.201257832, 502.368618799}, {31.0306494531, 21.0231661209}}
+ Class
+ DKDTextArea
+ GraphicID
+ E943FD83
+ GraphicStyle
+ 8
+
+
+ AttributedText
+
+ String
+ v2
+
+ TextAttribute
+ 0
+
+ Bounds
+ {{377.195326424, 523.208422682}, {30.9996031922, 21.0231661209}}
+ Class
+ DKDTextArea
+ GraphicID
+ F943FD83
+ GraphicStyle
+ 8
+
+
+ AttributedText
+
+ String
+ Edge subclass
+ TextAttributes
+
+ {0, 4}
+ 16
+ {4, 9}
+ 32
+
+
+ Bounds
+ {{348.950123948, 567.677166973}, {90.1938101669, 21.4163415091}}
+ Class
+ DKDTextArea
+ GraphicID
+ 2A43FD83
+ GraphicStyle
+ 10
+
+
+ Bounds
+ {{515.832308348, 171.943151603}, {87.782600853, 16.648764451}}
+ Class
+ DKDRectangle
+ GraphicID
+ 43C31293
+ GraphicStyle
+ 8
+
+
+ AttributedText
+
+ String
+ _edges
+ TextAttribute
+ 0
+
+ Bounds
+ {{534.088235453, 188.282062602}, {78.3773221901, 21.0231661209}}
+ Class
+ DKDTextArea
+ GraphicID
+ 53C31293
+ GraphicStyle
+ 10
+
+
+ Bounds
+ {{534.932171445, 530.358084862}, {87.782600853, 16.648764451}}
+ Class
+ DKDRectangle
+ GraphicID
+ 895D5293
+ GraphicStyle
+ 8
+
+
+ AttributedText
+
+ String
+ _edges
+ TextAttribute
+ 0
+
+ Bounds
+ {{553.18809855, 546.696995861}, {78.3773221901, 21.0231661209}}
+ Class
+ DKDTextArea
+ GraphicID
+ 995D5293
+ GraphicStyle
+ 10
+
+
+ Class
+ DKDBezier
+ DkBezArrow
+ 2
+ GraphicID
+ AA5AC793
+ GraphicStyle
+ 56
+ SVGPath
+ M564.492647498,180.026681355 C564.492647498,180.026681355 564.492647498,180.026681355 564.492647498,180.026681355 C560.983309031,74.6526353337 486.944971131,55.5961066657 424.350870745,56.9055010207 C246.769676444,66.1107318805 267.032048519,152.262249804 327.980615122,151.478502838
+
+
+ AttributedText
+
+ String
+ Undirected graph
+ TextAttribute
+ 48
+
+ Bounds
+ {{450.645030196, 262.075333739}, {202.348893933, 34.1385596992}}
+ Class
+ DKDTextArea
+ GraphicID
+ 14DEC993
+ GraphicStyle
+ 10
+
+
+ AttributedText
+
+ String
+ Directed graph
+ TextAttribute
+ 48
+
+ Bounds
+ {{466.989245863, 625.572791511}, {175.234506692, 31.2274995402}}
+ Class
+ DKDTextArea
+ GraphicID
+ 55CF0C93
+ GraphicStyle
+ 10
+
+
+ AttributedText
+
+ String
+ v1 is always the start vertex
+ TextAttribute
+ 64
+
+ Bounds
+ {{434.664097974, 443.914155611}, {87.7526987382, 35.5524288103}}
+ Class
+ DKDTextArea
+ GraphicID
+ 0DE69F93
+ GraphicStyle
+ 72
+
+
+ Class
+ DKDLine
+ GraphicID
+ 810832A3
+ GraphicStyle
+ 72
+ SVGPath
+ M433.580362928,463.945782216 L398.62784885,502.411477667
+
+
+ AttributedText
+
+ String
+ order doesn't matter
+ TextAttribute
+ 64
+
+ Bounds
+ {{413.920132976, 87.3386642252}, {85.897378884, 35.5524288103}}
+ Class
+ DKDTextArea
+ GraphicID
+ 172903A3
+ GraphicStyle
+ 72
+
+
+ Class
+ DKDLine
+ GraphicID
+ 5E2CF3A3
+ GraphicStyle
+ 72
+ SVGPath
+ M379.904216486,143.380517666 L413.065903411,105.851078658
+
+
+ AttributedText
+
+ String
+ list of Edges
+ TextAttribute
+ 64
+
+ Bounds
+ {{433.509267317, 316.225318777}, {85.897378884, 18.9174921865}}
+ Class
+ DKDTextArea
+ GraphicID
+ 8BCA09A3
+ GraphicStyle
+ 72
+
+
+ Class
+ DKDLine
+ GraphicID
+ 7462B9A3
+ GraphicStyle
+ 72
+ SVGPath
+ M393.192917989,331.806383095 L432.633093519,326.734821747
+
+
+ AttributedText
+
+ String
+ BaseVertex subclass
+ TextAttributes
+
+ {0, 10}
+ 16
+ {10, 9}
+ 32
+
+
+ Bounds
+ {{393.505995305, 736.467185297}, {135.410183231, 32.1481976616}}
+ Class
+ DKDTextArea
+ GraphicID
+ 4D9685B1
+ GraphicStyle
+ 10
+
+
+ AttributedText
+
+ String
+ BaseVertex subclass
+ TextAttributes
+
+ {0, 10}
+ 16
+ {10, 9}
+ 32
+
+
+ Bounds
+ {{590.256284561, 589.217001103}, {135.410183231, 32.1481976616}}
+ Class
+ DKDTextArea
+ GraphicID
+ 766E85B1
+ GraphicStyle
+ 10
+
+
+ AttributedText
+
+ String
+ BaseVertex subclass
+ TextAttributes
+
+ {0, 10}
+ 16
+ {10, 9}
+ 32
+
+
+ Bounds
+ {{380.443304193, 370.406352954}, {135.410183231, 32.1481976616}}
+ Class
+ DKDTextArea
+ GraphicID
+ E2F295B1
+ GraphicStyle
+ 10
+
+
+ Bounds
+ {{56.1300036422, 117.007832584}, {179.748202765, 138.79904252}}
+ Class
+ DKDGroup
+ GraphicID
+ A1C73EB1
+ GroupGraphics
+
+
+ AttributedText
+
+ String
+ _BaseGraph class
+ TextAttributes
+
+ {0, 10}
+ 16
+ {10, 6}
+ 32
+
+
+ Bounds
+ {{68.0289994371, 223.658677443}, {121.597735034, 32.1481976616}}
+ Class
+ DKDTextArea
+ GraphicID
+ D962B6B1
+ GraphicStyle
+ 10
+
+
+ Bounds
+ {{139.483420339, 132.525658238}, {87.782600853, 16.648764451}}
+ Class
+ DKDRectangle
+ GraphicID
+ 818AC7B1
+ GraphicStyle
+ 8
+
+
+ AttributedText
+
+ String
+ _edgelist
+ TextAttribute
+ 80
+
+ Bounds
+ {{57.2009356021, 165.133742084}, {78.3773221901, 21.0231661209}}
+ Class
+ DKDTextArea
+ GraphicID
+ E917E8B1
+ GraphicStyle
+ 10
+
+
+ Bounds
+ {{56.1300036422, 117.007832584}, {179.748202765, 102.160261623}}
+ Class
+ DKDRectangle
+ GraphicID
+ 9CCE8AB1
+ GraphicStyle
+ 88
+
+
+ AttributedText
+
+ String
+ _vertexlist
+ TextAttribute
+ 80
+
+ Bounds
+ {{57.1450032585, 132.577324973}, {93.7524652752, 28.0906581509}}
+ Class
+ DKDTextArea
+ GraphicID
+ C73E6BB1
+ GraphicStyle
+ 10
+
+
+ Bounds
+ {{139.273834123, 161.851595515}, {87.782600853, 16.648764451}}
+ Class
+ DKDRectangle
+ GraphicID
+ C8CA8BB1
+ GraphicStyle
+ 8
+
+
+
+
+ Class
+ DKDContinuousBezier
+ DkBezArrow
+ 2
+ DkBezDashPattern
+ 0
+ GraphicID
+ 2710EBC1
+ GraphicStyle
+ 104
+ SVGPath
+ M174.853229387,140.494743983 C174.853229387,140.494743983 174.853229387,140.494743983 174.853229387,140.494743983 C174.382483601,180.130470999 204.086118499,228.922086149 221.524983524,253.571835166 C235.199996386,272.901397863 244.886172162,282.39656773 296.315396389,306.197927546
+
+
+ Class
+ DKDContinuousBezier
+ DkBezArrow
+ 2
+ DkBezDashPattern
+ 16
+ GraphicID
+ 2D4A7EC1
+ GraphicStyle
+ 104
+ SVGPath
+ M198.142929913,140.010933352 C198.142929913,140.010933352 199.713613947,134.251373061 199.713613947,134.251373061 C214.154610677,58.3618300063 319.60245667,28.7107386875 381.864182818,31.579042149 C463.451820359,35.3376610895 507.141790253,89.8477588426 538.37650548,129.225778752
+
+
+ Class
+ DKDContinuousBezier
+ DkBezArrow
+ 2
+ DkBezDashPattern
+ 32
+ GraphicID
+ F9215BD1
+ GraphicStyle
+ 120
+ SVGPath
+ M210.844983401,170.766790232 C210.844983401,170.766790232 210.844983401,170.766790232 210.844983401,170.766790232 C213.752183867,199.117485484 250.788478524,197.804023056 258.597192548,193.417321791 C266.581638868,188.931899395 266.646650811,163.673519796 326.03417007,166.857994658
+
+
+ Bounds
+ {{75.6929880143, 478.94959588}, {179.748202765, 138.799042521}}
+ Class
+ DKDGroup
+ GraphicID
+ 835D7ED1
+ GraphicTransform
+
+ coefficientM11
+ 1
+ coefficientM12
+ 0
+ coefficientM21
+ 0
+ coefficientM22
+ 1
+ coefficientTX
+ 0
+ coefficientTY
+ 0
+
+ GroupGraphics
+
+
+ AttributedText
+
+ String
+ _BaseGraph class
+ TextAttributes
+
+ {0, 10}
+ 16
+ {10, 6}
+ 32
+
+
+ Bounds
+ {{87.5919838092, 585.600440739}, {121.597735034, 32.1481976616}}
+ Class
+ DKDTextArea
+ GraphicID
+ 235D7ED1
+ GraphicStyle
+ 10
+
+
+ Bounds
+ {{159.046404711, 494.467421534}, {87.782600853, 16.648764451}}
+ Class
+ DKDRectangle
+ GraphicID
+ 335D7ED1
+ GraphicStyle
+ 8
+
+
+ AttributedText
+
+ String
+ _edgelist
+ TextAttribute
+ 80
+
+ Bounds
+ {{76.7639199742, 527.07550538}, {78.3773221901, 21.0231661209}}
+ Class
+ DKDTextArea
+ GraphicID
+ 435D7ED1
+ GraphicStyle
+ 10
+
+
+ Bounds
+ {{75.6929880143, 478.94959588}, {179.748202765, 102.160261623}}
+ Class
+ DKDRectangle
+ GraphicID
+ 535D7ED1
+ GraphicStyle
+ 88
+
+
+ AttributedText
+
+ String
+ _vertexlist
+ TextAttribute
+ 80
+
+ Bounds
+ {{76.7079876306, 494.519088269}, {93.7524652752, 28.0906581509}}
+ Class
+ DKDTextArea
+ GraphicID
+ 635D7ED1
+ GraphicStyle
+ 10
+
+
+ Bounds
+ {{158.836818495, 523.793358811}, {87.782600853, 16.648764451}}
+ Class
+ DKDRectangle
+ GraphicID
+ 735D7ED1
+ GraphicStyle
+ 8
+
+
+
+
+ Class
+ DKDContinuousBezier
+ DkBezArrow
+ 2
+ DkBezDashPattern
+ 48
+ GraphicID
+ 935D7ED1
+ GraphicStyle
+ 104
+ SVGPath
+ M194.416213759,502.436507279 C194.416213759,502.436507279 194.416213759,502.436507279 194.416213759,502.436507279 C193.945467973,542.072234295 223.649102871,590.863849445 241.087967896,615.513598462 C254.762980758,634.843161159 264.449156534,644.338331026 315.878380761,668.139690842
+
+
+ Class
+ DKDContinuousBezier
+ DkBezArrow
+ 2
+ DkBezDashPattern
+ 64
+ GraphicID
+ A35D7ED1
+ GraphicStyle
+ 104
+ SVGPath
+ M217.705914285,501.952696648 C217.705914285,501.952696648 219.276598319,496.193136357 219.276598319,496.193136357 C233.717595049,420.303593302 339.165441042,390.652501983 401.42716719,393.520805445 C483.014804731,397.279424385 526.704774625,451.789522138 557.939489852,491.167542048
+
+
+ Class
+ DKDContinuousBezier
+ DkBezArrow
+ 2
+ DkBezDashPattern
+ 80
+ GraphicID
+ B35D7ED1
+ GraphicStyle
+ 120
+ SVGPath
+ M230.407967773,532.708553528 C230.407967773,532.708553528 230.407967773,532.708553528 230.407967773,532.708553528 C233.315168239,561.05924878 270.351462896,559.745786352 278.16017692,555.359085087 C286.14462324,550.873662691 286.209635183,525.615283092 345.597154442,528.799757954
+
+
+ HideDimensions
+ NO
+ LayerColorMod
+
+ DKDOnColorMod
+ NO
+ DKDOpacityColorMod
+ 0.5
+ DKDOutlineColorMod
+ NO
+ DKDTintColorColorMod
+
+ ColorSpace
+ NSCalibratedWhiteColorSpace
+ Opacity
+ 1
+ White
+ 0.5
+
+ DKDTintFractionColorMod
+ 0.5
+
+ LayerLock
+ NO
+ LayerName
+ Paper
+ LayerState
+ Active
+ OutlineLayer
+ NO
+
+
+ DKDPagesSpec
+
+ BackgroundDisplay
+ Background
+ CanvasBorder
+
+ BluePlus
+ 0.533333
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0.533333
+ OpacityPlus
+ 1
+ RedPlus
+ 0.54902
+
+ CanvasColor
+
+ Catalog
+ System
+ Catalog-Color
+ windowBackgroundColor
+
+ CanvasMargin
+ 0
+ DetailsDrawerWidth
+ 260
+ DisplayAttributesBar
+ YES
+ DisplayRulers
+ NO
+ FullScreen
+ NO
+ FullScreenCanvasMargin
+ 141.73228
+ LayersDrawerWidth
+ 266
+ NonFullScreenCanvasMargin
+ 0
+ NumberAcrossFirst
+ YES
+ PagesAcross
+ 1
+ PagesDown
+ 1
+ PagesSpecBackgroundRGB
+
+ ColorSpace
+ NSCalibratedWhiteColorSpace
+ Opacity
+ 1
+ White
+ 1
+
+ PagesSpecPrintBackground
+ NO
+ ShowPageBreaks
+ NO
+ SizeChecker
+ 8
+ aCheckerColor
+
+ BluePlus
+ 0.941176
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0.941176
+ OpacityPlus
+ 1
+ RedPlus
+ 0.941176
+
+ bCheckerColor
+
+ BluePlus
+ 0.784314
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ GreenPlus
+ 0.784314
+ OpacityPlus
+ 1
+ RedPlus
+ 0.784314
+
+
+ DKDPrintInfo
+
+ BottomMargin
+ 18
+ Copies
+ 1
+ FallBackPaperSizeHeight
+ 841.889770508
+ FallBackPaperSizeWidth
+ 886.393700787
+ FirstPage
+ 1
+ HorizontalPagination
+ 2
+ HorizontallyCentered
+ YES
+ LastPage
+ -1
+ LeftMargin
+ 18
+ MustCollate
+ YES
+ Orientation
+ 1
+ PaperName
+ Custom
+ PaperSizeHeight
+ 841.889770508
+ PaperSizeWidth
+ 886.393700787
+ PreviewPageNumber
+ 1
+ PrintAllPages
+ YES
+ PrintJobDisposition
+ NSPrintSpoolJob
+ PrintSavePath
+
+ PrintScalingFactor
+ 1
+ PrinterName
+ Brother MFC-L8690CDW series
+ ReversePageOrder
+ NO
+ RightMargin
+ 18
+ TopMargin
+ 18
+ VerticalPagination
+ 0
+ VerticallyCentered
+ YES
+ XPrintMirror
+ NO
+ YPrintMirror
+ NO
+
+ DKDSaveTimeStamp
+ 2026-10-12 02:33:47 +0600
+ DKDTablet
+
+ BrushDynamic
+ NO
+ BrushFit
+ 6
+ PenMax
+ 25
+ PenMin
+ 0.5
+ PenPressureFactor
+ 0.5
+ PencilDynamic
+ NO
+ PencilFit
+ 7
+
+ DKDTimeFormat
+
+ Field 0 Include
+ Weekday
+ Field 0 Type
+ Long
+ Field 1 Include
+ Month
+ Field 1 Type
+ Short
+ Field 2 Include
+ Day
+ Field 2 Type
+ Number
+ Field 3 Include
+ Year
+ Field 3 Type
+ Long
+ Include GMT
+ NO
+ Include Title
+ YES
+ IncludeDate
+ YES
+ IncludeTime
+ YES
+ Seperator 0
+ -
+ Seperator 1
+ .
+ Seperator 2
+ ,
+ Seperator 3
+
+ Time Seperator
+ :
+ TimeAfterDate
+ YES
+ Twelve Hour Clock
+ YES
+ Used Once
+ YES
+
+ DKDToolbarSelectedButtonPairs
+
+ ColorTextToolbarItemIdentifier_0
+
+ HSB_10FFFF
+
+ ColorFillToolbarItemIdentifier_0
+
+ HSB_0000D0
+
+ ColorStrokeToolbarItemIdentifier_0
+
+ HSB_000020
+
+ GradientToolbarItemIdentifier_0
+
+
+ EndGradientColor
+
+ Blue
+ 0.999991
+ BluePlus
+ 1
+ ColorSpace
+ NSCalibratedRGBColorSpace
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ Green
+ 0.999974
+ GreenPlus
+ 1
+ Opacity
+ 1
+ OpacityPlus
+ 1
+ Red
+ 0.999999
+ RedPlus
+ 0.999996
+
+ GradientFillClass
+ DKDHorizontalGradientFill
+ StartGradientColor
+
+ Blue
+ 0
+ BluePlus
+ 0
+ ColorSpace
+ NSCalibratedRGBColorSpace
+ ColorSpacePlus
+ DKDsRgbColorSpace
+ Green
+ 0
+ GreenPlus
+ 0
+ Opacity
+ 1
+ OpacityPlus
+ 1
+ Red
+ 0
+ RedPlus
+ 0
+
+
+
+
+ DKDWindowState
+
+ CursorMode
+ Nothing
+ DocCenter
+ {391.792986229, 378.287529766}
+ DocumentFileName
+ /Users/pic/Library/CloudStorage/Dropbox/code/pgraph-python/docs/source/datastructures.ezdraw
+ DrawersOnMainView
+ YES
+ GDetailsLayersDrawerEdgePreference
+ Auto
+ GraphicDetailsOpen
+ NO
+ LayerActiveAbove
+ NO
+ LayerOpen
+ NO
+ LayerSelect
+ Active Only
+ LayersDrawerEdgePreference
+ Auto
+ OutlineDrawing
+ NO
+ WindowLocation
+ 2317 -83 1142 1238 0 0 3840 1590
+ ZoomPercent
+ 160.180664
+
+ GroupEdit
+ Fixed
+ NumberColorsToListInContextMenu
+ 12
+ NumberPairColorsToListInContextMenu
+ 6
+
+
diff --git a/docs/figs/datastructures.svg b/docs/figs/datastructures.svg
new file mode 100644
index 00000000..bfbf875e
--- /dev/null
+++ b/docs/figs/datastructures.svg
@@ -0,0 +1,6082 @@
+
+
+
+
diff --git a/docs/source/PGraph.rst b/docs/source/PGraph.rst
deleted file mode 100644
index 23c88ad6..00000000
--- a/docs/source/PGraph.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-PGraph module
-=============
-
-.. automodule:: pgraph.PGraph
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/docs/source/analysis.rst b/docs/source/analysis.rst
new file mode 100644
index 00000000..8b7e2555
--- /dev/null
+++ b/docs/source/analysis.rst
@@ -0,0 +1,67 @@
+Graph analysis
+===============
+
+Querying structure -- counts, adjacent vertices, connectivity, distance -- for directed and
+undirected graphs.
+See :doc:`planning` for
+finding paths between vertices, and :doc:`representations` for matrix/dot forms of the
+whole graph.
+
+Graph
+-----
+
+.. autosummary::
+ :nosignatures:
+
+ ~pgraph.PGraph.BaseGraph.n
+ ~pgraph.PGraph.BaseGraph.ne
+ ~pgraph.PGraph.BaseGraph.nc
+ ~pgraph.PGraph.BaseGraph.edges
+ ~pgraph.PGraph.BaseGraph.average_degree
+ ~pgraph.PGraph.BaseGraph.iscyclic
+ ~pgraph.PGraph.BaseGraph.connectivity
+ ~pgraph.PGraph.BaseGraph.component
+ ~pgraph.PGraph.BaseGraph.samecomponent
+ ~pgraph.PGraph.BaseGraph.closest
+
+Vertex
+------
+
+.. autosummary::
+ :nosignatures:
+
+ ~pgraph.PGraph.BaseVertex.edges
+ ~pgraph.PGraph.BaseVertex.adjacent
+ ~pgraph.PGraph.BaseVertex.isadjacent
+ ~pgraph.PGraph.BaseVertex.incidences
+ ~pgraph.PGraph.BaseVertex.degree
+ ~pgraph.PGraph.BaseVertex.heuristic_distance
+ ~pgraph.PGraph.BaseVertex.distance
+ ~pgraph.PGraph.BaseVertex.x
+ ~pgraph.PGraph.BaseVertex.y
+ ~pgraph.PGraph.BaseVertex.z
+
+Details
+-------
+
+.. autoproperty:: pgraph.PGraph.BaseGraph.n
+.. autoproperty:: pgraph.PGraph.BaseGraph.ne
+.. autoproperty:: pgraph.PGraph.BaseGraph.nc
+.. automethod:: pgraph.PGraph.BaseGraph.edges
+.. automethod:: pgraph.PGraph.BaseGraph.average_degree
+.. automethod:: pgraph.PGraph.BaseGraph.iscyclic
+.. automethod:: pgraph.PGraph.BaseGraph.connectivity
+.. automethod:: pgraph.PGraph.BaseGraph.component
+.. automethod:: pgraph.PGraph.BaseGraph.samecomponent
+.. automethod:: pgraph.PGraph.BaseGraph.closest
+
+.. automethod:: pgraph.PGraph.BaseVertex.edges
+.. automethod:: pgraph.PGraph.BaseVertex.adjacent
+.. automethod:: pgraph.PGraph.BaseVertex.isadjacent
+.. automethod:: pgraph.PGraph.BaseVertex.incidences
+.. autoproperty:: pgraph.PGraph.BaseVertex.degree
+.. automethod:: pgraph.PGraph.BaseVertex.heuristic_distance
+.. automethod:: pgraph.PGraph.BaseVertex.distance
+.. autoproperty:: pgraph.PGraph.BaseVertex.x
+.. autoproperty:: pgraph.PGraph.BaseVertex.y
+.. autoproperty:: pgraph.PGraph.BaseVertex.z
diff --git a/docs/source/api.rst b/docs/source/api.rst
new file mode 100644
index 00000000..875c5819
--- /dev/null
+++ b/docs/source/api.rst
@@ -0,0 +1,9 @@
+API details
+============
+
+.. toctree::
+ :maxdepth: 2
+
+ common
+ edges_vertices
+ policy
diff --git a/docs/source/common.rst b/docs/source/common.rst
new file mode 100644
index 00000000..c60277d1
--- /dev/null
+++ b/docs/source/common.rst
@@ -0,0 +1,45 @@
+Common methods
+===============
+
+The package supports both directed (prefix ``D``) and undirected graphs (prefix ``U``), and the classes for these
+share a common interface.
+
+The graph classes represent a single graph, either directed or undirected, and they share :class:`BaseGraph`:
+
+.. inheritance-diagram:: pgraph.PGraph.UGraph pgraph.PGraph.DGraph
+ :parts: 1
+ :private-bases:
+ :top-classes: pgraph.PGraph.BaseGraph
+
+The vertices in a directed graph (``DGraph``) inherit from :class:`DVertex` and the
+vertices in an undirected graph (``UGraph``) inherit from :class:`UVertex`.
+
+.. inheritance-diagram:: pgraph.PGraph.UVertex pgraph.PGraph.DVertex
+ :parts: 1
+
+The vertex classes share
+almost their entire interface, defined once on their common base classes
+(:class:`BaseGraph`, :class:`BaseVertex`). This section documents that
+shared interface by task rather than by class; see :doc:`construction` for
+the :class:`DGraph` and :class:`UGraph` classes and :doc:`edges_vertices` for
+what's specific to directed vs. undirected vertices.
+
+Edges are represented by the :class:`Edge` class, which is used by both directed and undirected graphs.
+
+.. inheritance-diagram:: pgraph.PGraph.Edge
+ :parts: 1
+
+
+
+The following sections describe the common methods.
+
+.. toctree::
+ :maxdepth: 2
+
+ construction
+ modification
+ analysis
+ representations
+ visualization
+ export
+ planning
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 1e340a48..0f1d1680 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -18,7 +18,7 @@
# -- Project information -----------------------------------------------------
-project = "Simple graph functionality for Python"
+project = "Graphs for Python"
copyright = "2020-present, Peter Corke"
author = "Peter Corke"
@@ -60,8 +60,12 @@
html_theme_options = {
"logo_only": False,
- "display_version": True,
"prev_next_buttons_location": "both",
+ # show the sub-headings of every page in the sidebar, not just the current one
+ "collapse_navigation": False,
+ # Introduction / API details -> page -> sub-heading; individual methods
+ # are reached from the page, not listed in the sidebar
+ "navigation_depth": 3,
"analytics_id": "G-11Q6WJM565",
}
diff --git a/docs/source/construction.rst b/docs/source/construction.rst
new file mode 100644
index 00000000..290cbdf8
--- /dev/null
+++ b/docs/source/construction.rst
@@ -0,0 +1,39 @@
+Construction and basic usage
+=============================
+
+There are a number of ways to build a :class:`DGraph`/:class:`UGraph` (a plain constructor, or from
+a dictionary/adjacency matrix).
+
+See :doc:`policy` for the rules around constructing vertices/edges
+standalone, independent of a graph.
+
+.. autosummary::
+ :nosignatures:
+
+ ~pgraph.PGraph.DGraph
+ ~pgraph.PGraph.UGraph
+ ~pgraph.PGraph.BaseGraph.Dict
+ ~pgraph.PGraph.BaseGraph.Adjacency
+
+
+.. autoclass:: pgraph.PGraph.DGraph
+ :show-inheritance:
+
+.. autoclass:: pgraph.PGraph.UGraph
+ :show-inheritance:
+
+.. autoclass:: pgraph.PGraph.BaseGraph.Adjacency
+ :show-inheritance:
+
+.. autoclass:: pgraph.PGraph.BaseGraph.Dict
+ :show-inheritance:
+
+
+Inherited methods for all graph types
+--------------------------------------
+
+.. autoclass:: pgraph.PGraph.BaseGraph
+ :members: copy, vertex_copy, metric, heuristic, show, vertex_class, edge_class
+ :special-members: __init__, __str__, __repr__, __getitem__, __iter__, __contains__
+
+
diff --git a/docs/source/datastructures.ezdraw b/docs/source/datastructures.ezdraw
deleted file mode 100644
index c25ab384..00000000
--- a/docs/source/datastructures.ezdraw
+++ /dev/null
@@ -1,2353 +0,0 @@
-
-
-
-
- AAAA_CurrentOSXVersion
- macOS Catalina: 1677.104000
- AAAA_DKDDocumentVersion
- 9.0.0 : Mobile Friendly
- AAAA_EazyDrawVersion
- 9.7.1
- AAAB_Build
- 9088
- AAAB_Distribution
- Free Market
- ArchiveMatchStore
-
- Archive_Stores
-
-
- Class_Store
- DKDLock
- Match_Hashes
-
-
- BinIndex
- 10
- BinMatches
-
-
- CenterLock
- YES
-
-
- CenterLock
- YES
-
-
-
-
- BinIndex
- 14
- BinMatches
-
-
-
-
-
- NHashBins
- 16
-
-
- Class_Store
- DKDGraphicStyle
- Match_Hashes
-
-
- BinIndex
- 8
- BinMatches
-
-
- DrawsFill
- NO
- DrawsLine
- YES
- LineCapStyle
- Square
- LineJoinStyle
- Miter
- LineRGB
-
- Blue
- 0
- BluePlus
- 0
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0
- GreenPlus
- 0
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0
- RedPlus
- 0
-
- LineWidth
- 1
- MiterLimit
- 10
- StrokePosition
- Front
- WindingRule
- Non-Zero
-
-
- DrawsFill
- NO
- DrawsLine
- YES
- LineCapStyle
- Square
- LineJoinStyle
- Miter
- LineRGB
-
- Blue
- 0.027434
- BluePlus
- 0
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0.007121
- GreenPlus
- 0.149131
- Opacity
- 0.796019
- OpacityPlus
- 0.796019
- Red
- 0.986246
- RedPlus
- 1
-
- LineWidth
- 6.34521484375
- MiterLimit
- 10
- StrokePosition
- Front
- WindingRule
- Non-Zero
-
-
- DrawsFill
- NO
- DrawsLine
- YES
- LineCapStyle
- Square
- LineJoinStyle
- Miter
- LineRGB
-
- Blue
- 0
- BluePlus
- 0
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0
- GreenPlus
- 0
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0
- RedPlus
- 0
-
- LineWidth
- 2.53369140625
- MiterLimit
- 10
- StrokePosition
- Front
- WindingRule
- Non-Zero
-
-
- DrawsFill
- NO
- DrawsLine
- YES
- LineCapStyle
- Square
- LineJoinStyle
- Miter
- LineRGB
-
- Blue
- 0
- BluePlus
- 0
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0
- GreenPlus
- 0
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0
- RedPlus
- 0
-
- LineWidth
- 2.5
- MiterLimit
- 10
- StrokePosition
- Front
- WindingRule
- Non-Zero
-
-
- DrawsFill
- NO
- DrawsLine
- YES
- LineCapStyle
- Square
- LineJoinStyle
- Miter
- LineRGB
-
- Blue
- 0.498039
- BluePlus
- 0.570465
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0.498039
- GreenPlus
- 0.570472
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0.498039
- RedPlus
- 0.570459
-
- LineWidth
- 1
- MiterLimit
- 10
- StrokePosition
- Front
- WindingRule
- Non-Zero
-
-
-
-
- BinIndex
- 10
- BinMatches
-
-
- DrawsFill
- NO
- DrawsLine
- NO
- LineCapStyle
- Square
- LineJoinStyle
- Miter
- LineWidth
- 1
- MiterLimit
- 10
- StrokePosition
- Front
- WindingRule
- Non-Zero
-
-
-
-
- NHashBins
- 16
-
-
- Class_Store
- DKDParagraph
- Match_Hashes
-
-
- BinIndex
- 0
- BinMatches
-
-
- FirstLineHeadIndent
- 0
- HeadIndent
- 0
- LineFragmentPadding
- 5
- LineSpacing
- 0
- ParagraphSpacing
- 0
- ParagraphSpacingBefore
- 0
- TailIndent
- 0
- TextAlignment
- Left
-
-
-
-
- NHashBins
- 16
-
-
- Class_Store
- DKDFont
- Match_Hashes
-
-
- BinIndex
- 0
- BinMatches
-
-
- Family
- Avenir
- Name
- Avenir-Book
- Size
- 12
-
-
- Family
- Courier
- Name
- Courier
- Size
- 12
- Traits
- 400
-
-
- Family
- Avenir
- Name
- Avenir-Heavy
- Size
- 22
- Traits
- 2
-
-
- Family
- Bradley Hand
- Name
- BradleyHandITCTT-Bold
- Size
- 12
- Traits
- 22
-
-
-
-
- NHashBins
- 16
-
-
- Class_Store
- DKDTextAttributes
- Match_Hashes
-
-
- BinIndex
- 0
- BinMatches
-
-
- Font
- 0
- ForeColor
-
- Blue
- 0.998189
- BluePlus
- 1
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0
- GreenPlus
- 0
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0
- RedPlus
- 0
-
- Paragraph
- 0
-
-
- Font
- 16
- ForeColor
-
- ColorSpace
- NSCalibratedWhiteColorSpace
- Opacity
- 1
- White
- 0
-
- Paragraph
- 0
-
-
- Font
- 16
- ForeColor
-
- Blue
- 0.998189
- BluePlus
- 1
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0
- GreenPlus
- 0
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0
- RedPlus
- 0
-
- Paragraph
- 0
-
-
- Font
- 32
- ForeColor
-
- Blue
- 0.02921
- BluePlus
- 0
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0.238126
- GreenPlus
- 0.333
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0.987339
- RedPlus
- 1
-
- Paragraph
- 0
-
-
- Font
- 48
- ForeColor
-
- Blue
- 0.498039
- BluePlus
- 0.570465
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0.498039
- GreenPlus
- 0.570472
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0.498039
- RedPlus
- 0.570459
-
- Paragraph
- 0
-
-
-
-
- NHashBins
- 16
-
-
- Class_Store
- DKDArrow
- Match_Hashes
-
-
- BinIndex
- 2
- BinMatches
-
-
- ArrowAngle
- 160
- ArrowArchiveVersion
- 9
- ArrowBackEnd
- YES
- ArrowForEachSegment
- NO
- ArrowForm
- solid
- ArrowFrontEnd
- NO
- ArrowLineWidthFraction
- 0.25
- ArrowOffset
- 0
- ArrowSize
- 8
- ReferenceArrow
- Relief
- UseCurveFillAndStroke
- YES
-
-
-
-
- BinIndex
- 10
- BinMatches
-
-
- ArrowAngle
- 159.730010986
- ArrowArchiveVersion
- 9
- ArrowBackEnd
- YES
- ArrowForEachSegment
- NO
- ArrowForm
- solid
- ArrowFrontEnd
- NO
- ArrowLineWidthFraction
- 0.25
- ArrowOffset
- 0
- ArrowSize
- 10.7576407035
- ReferenceArrow
- Relief
- UseCurveFillAndStroke
- YES
-
-
- ArrowAngle
- 160
- ArrowArchiveVersion
- 9
- ArrowBackEnd
- YES
- ArrowForEachSegment
- NO
- ArrowForm
- solid
- ArrowFrontEnd
- NO
- ArrowLineWidthFraction
- 0.25
- ArrowOffset
- 0
- ArrowSize
- 10.6271449412
- ReferenceArrow
- Relief
- UseCurveFillAndStroke
- YES
-
-
- ArrowAngle
- 160
- ArrowArchiveVersion
- 9
- ArrowBackEnd
- YES
- ArrowForEachSegment
- NO
- ArrowForm
- solid
- ArrowFrontEnd
- NO
- ArrowLineWidthFraction
- 0.25
- ArrowOffset
- 0
- ArrowSize
- 37.5449518519
- ReferenceArrow
- Relief
- UseCurveFillAndStroke
- YES
-
-
-
-
- NHashBins
- 16
-
-
-
- BBB_DKDQuicklookData
-
- /9j/4AAQSkZJRgABAQAASABIAAD/4QCMRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEA
- AAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAA
- AAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAi+gAwAEAAAA
- AQAAAyYAAAAA/+0AOFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAAOEJJTQQlAAAAAAAQ
- 1B2M2Y8AsgTpgAmY7PhCfv/AABEIAyYCLwMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAA
- AAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYT
- UWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJ
- SlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmq
- srO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAf
- AQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncA
- AQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkq
- NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SV
- lpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery
- 8/T19vf4+fr/2wBDABwcHBwcHDAcHDBEMDAwRFxEREREXHRcXFxcXHSMdHR0dHR0jIyM
- jIyMjIyoqKioqKjExMTExNzc3Nzc3Nzc3Nz/2wBDASIkJDg0OGA0NGDmnICc5ubm5ubm
- 5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ub/3QAEACP/
- 2gAMAwEAAhEDEQA/AOkooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
- oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
- KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
- AP/Q6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
- ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
- igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA/9HpKKKKACii
- igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
- oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
- KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigD/0ukooooAKKKKACiiigAooooA
- KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoqMzRL951
- H1IqM3doOsyf99CgCxRVf7Zaf89o/wDvoUourY9JUP8AwIUAT0UwSRt91gfxp9ABRRRQ
- AUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUU
- UAFFFFABRRRQAUUUUAf/0+kooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
- igAoopCQoyTgCgBaKzZdVtIzsQmVvRBmofP1S4/1MSwr6uefy/8ArUAbFQSXVtD/AK2R
- VPoTz+VZ/wDZs83/AB93Lt7L8o/z+FWI9LsYukYJ/wBrn+dAELaxZg7Y90h/2R/jim/b
- 7yT/AFFo31Y4rVVEQYQBR7cU6gDIzrMnaKP8z/jR9k1OT/WXW3/dX/8AVWvRQBkf2W7f
- 625lb8cf40v9jWh++Xf6tWtRQBmDSNPH/LPP1J/xqUaZYD/lkv61eooAo/2bY/8APJaQ
- 6XYHrEPzP+NX6KAMw6Pp56RkfQn/ABqP+x4V/wBVJIn0ateigDI+wX0fMN2x9nGaN2sx
- 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
- vo3/AHyf8KPNX0b/AL5P+FSUUARF0YYIb/vk/wCFL5q+jf8AfJ/wqSigCPzV9G/75P8A
- hTWMb9Q34BhU1FAEYkQDADf98n/CjzV9G/75P+FSUUAR+avo3/fJ/wAKRDudmAOMDqMe
- vrUtFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFF
- FABRRRQB/9XpKKKKACiiigAooooAKKKKACiiigAooooAKKKKACq0/wC7eOfsp2t9G/8A
- r4qzTXRZEKOMhhg/jQA6iq9u7YMMhy8fB9x2P4/zqxQAUx5I4xmRgo9zin0UAUJ1W72G
- 3kVjG27Ab2x1GcVGtpKgRlVGILZViSPm75x1/CtOigDFkt5ILdAwUkKyYwWHPPGBTjYy
- svYhkVSCxGMD2Bz+lbFFAGc9tM1x5i7Qu5TnJ5xjqpBGfQ5rRoooAKKKgnkZFCx/fc4X
- 6+v4daAGxfvJ5Juy/Iv4df14/CrNMijWKNY16KMU+gAooooAKKKKACiiigAooooAKKKK
- ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
- igAooooAKKKKAP/W6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooArzRsSJov
- vr+o7g1JFKkyb1+hB6gjsakqvJC2/wA6EhX756MPQ/40AWKKgjnVz5bDY46qev4eoqeg
- AooooAKKKKACiioZZ0jO37znoo6n/PrQA+SRIkLucAf5xUUKOWM8ww7DAH90en19aSOJ
- 2cTT4LD7qjov+J96s0AFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAF
- FFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAf/9fp
- KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAjkijlXbIM+nt9DUOy4i/
- 1bCQej9f++h/UVaooArfaCv+tjdfoNw/8dzR9stu7gfXj+dWaKAK32y27SA/Tn+VH2nd
- /qo3b8No/wDHsVZooAq7bmX77CMei8n8z/hTWUWzJ5eArNhyck57ZOfwq5TJI0lQxyDK
- nqKcXrqBQ+2uqruAZmBbuPl7evJqc3MhKCOPPmLuGTjGMdePepXgikwSCCBgEEg49OKQ
- 20RZW+YFRgYYjj8605odhDPOm+0eVs42g9fWoxegzeWFyu7bnvn6Y6fjViSCOVgzg5Ax
- wSOPfFH2eLf5gBBznqcZ9cdKSceqAhjuXecwFACv3ueg7HpzmpGnKziErgHuTjP045/O
- hbWFGDKDlSSDk9T1709oY2cO2cj3OOPbpQ3G+wFWa43W+QMF4y/XpjH+NSNcvGdsiYYg
- bQDnOSB6DHJFP+ywc5UnIK9T0PUDmlFtDgggnIxySePbPSneAETSOsoaQBcI5xnjgr3w
- KZ9tO0nZyDg8nHTOc4/pVj7PERggnII5JJ5xn+VJ9miwR83PJO45PbrmhOHVAItxum8r
- AA7EnrxnjjkfjVmoRBErBwDlegycDjHTp0qaolboMKKKKkAooooAKKKKACiiigAooooA
- KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigD/0OkooooA
- KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
- ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
- igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/R6SiiigAooooAKKKKACii
- igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
- oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
- KKKKACiiigAooooAKKKKACiiigAooooA/9LpKKKKACiiigAooooAKKKiZQ0gB6YP9KAJ
- aKiKRAEnoKRVhYkLzjrQBNRUGyMZLYAHvS7Idu/t1zQBNRVf9ycY5Bzz9KeUiAz2+tAE
- tFQDyCSPTrTikQ69uetAEtFQEQhDJ1A96MQ5x7A5z60AT0VFsi3bO/XFIyKpUrxzQBNR
- RVa7JEBwSMlRwcHlgOooAs0VW+yResn/AH8f/Gj7JF6yf9/H/wAaALNFVvskXrJ/38f/
- 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
- a/QUSJ5kbJ03Aj86gUXaqFHl8DHegC1VDULaS6iRI8ZVwxz6DNTf6Z/0z/Wj/TP+mf60
- AWaKrf6Z/wBM/wBaP9M/6Z/rQBZoqoHuWJCmIkcHBPFO/wBM/wCmf60AWaKrf6Z/0z/W
- j/TP+mf60AWagu/+PWX/AHG/lTf9M/6Z/rTJUu5Y2jPlgMCM896ALP8Ayz59Kjtf+PaL
- P9xf5UlyTHbOR1CkD644qZFCIEHYYoAdRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQ
- AUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQB//Q
- 6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKr3QPlb15MZDj8Ov5irFFACA
- hgGHIPNLVW3/AHTNbH+Hlf8AdP8Ah0q1QAUUUhAYFT39OKAIrjzfIfyPv7Tt+tZiG5Ec
- mwuRheCGz1+bG7vj0rTWBFYMC3Hq7H9CamoAxk8wCYxCXBZTkghivfGf/wBdMBnKHaZN
- nmENksWAA4Hy8/lW2yq6lWGQeopEjSJdkahQOwoAyXNx5MSlnJ+bJww78Z28g+metacG
- 7yU3gg7RnPJzjvUtFABRRRQBWuPneOEfxNuP0Xn+eKs1Vt/3jNcno3C/7o/x6/lVqgAo
- oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
- KKKKACiiigAooooAKKKKACiiigAooooA/9HpKKKKACiiigAooooAKKKKACiiigAooooA
- KKKKACiiigAooooAgnjZwHj4kTlf6g+xp8UqypuXg9CD1B9DUlVpImD+fBw/Qg9GA7H+
- hoAs0VFFMsuQMhh1U9RUtABRRRQAUUUUAFFFFABVSU/aHNun3R/rD/7L+Pf2oaVpyY7c
- 4HRn7D2Hqf0FWI40iQIgwBQA8AAYFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRR
- RQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQB/
- /9LpKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAIpYUlwTkMOj
- Dgj8ai3XMX3181fVeG/EHj8vyq1RQBAt1Ax27gG/utwfyNT01kVxtcBh6HmoPsdt/CgX
- /d4/lQBZprukY3OwUepOKg+yQf7R+rN/jTltrdDuWNQfXHP50AN+1K3ECmT3HT8zxUMy
- yeWZbrlV5KJ0x7k4z+lX6QgMCp5B4przAr+fHGShUqqAc8Y56AYpxuoAnmFsLnaSQeD7
- +n41B9iHk+UXydwbcR6cDP4UfZHERjVlBLBj8vHGD6+3rWlodxErXcKhSScMcdDTnuYY
- wCx6jPAJ49eKJInkRfmAdTnOOM/TP9agks2kYSMwLbdpyvHXsMj1pJQ6gTPdQISGboAe
- hPB4FSPKkYBcnnpgEn8hVWS0dypDgeWAE+XoeMnrzU08JmQLkAjuR/LkEUWjpqBJ5seC
- c9CAfqcY/nUMNyj/ACsfm3EdDjgnjPTNIbZzwH4JVjkZJK47574oW2cAIzgoG3Yxg9c4
- zn1otG24CvcoVHlHJ3KOhwQWAOD3p5uYQSCcbQScgjp1x6/hTFt3CLEXBVNuOOflIPPP
- tUf2NtxZmByGHK5zn15p2h3AnNxEACSec9jnjrkY4qeqBs3KBd4yCcHByM/3ecir9TJR
- 6DCiiioAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
- oooAKKKKACiiigD/0+kooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
- oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
- KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
- AP/U6SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
- ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
- igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA/9XpKKKKACii
- igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
- oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
- KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigD/1ukooooAKKKKACiiigAooooA
- KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
- ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
- igAooooAKKKKACiiigAooooAKKKKAP/X6SiiigAooooAKKKKACiiigAooooAKKKKACii
- igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
- oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
- KKKKACiiigAooooA/9DpKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA
- KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKK
- ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
- igD/0ekooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii
- igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo
- oooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/Z
-
- DKDChangeTimeStamp
- 2020-09-21 23:11:11 +0000
- DKDCreateTimeStamp
- 2020-09-21 22:51:46 +0000
- DKDDisplayGraphicDetails
-
- AngleFormatDisplayDetails
-
- AngleDirection
- Right
- AngleForm
- degrees
- AngleRotation
- Counter Clockwise
- PrecisionAngles
- 1
-
- AnglesDisplaySpec
-
- FormDisplaySpec
- Decimal
- PrecisionDisplaySpec
- 2
- TextAlignDisplaySpec
- Left
- UnitsDisplaySpec
- Punctuation
-
- AreaForm
- Natural
- HelpTipDisplaySpec
-
- FormDisplaySpec
- Decimal
- PrecisionDisplaySpec
- 3
- TextAlignDisplaySpec
- Left
- UnitsDisplaySpec
- Abbreviate
-
- InspectingSpecIndex
- 0
- LengthsDisplaySpec
-
- FormDisplaySpec
- Decimal
- PrecisionDisplaySpec
- 2
- TextAlignDisplaySpec
- Left
- UnitsDisplaySpec
- Nothing
-
- PercentDisplaySpec
-
- FormDisplaySpec
- Decimal
- PrecisionDisplaySpec
- 1
- TextAlignDisplaySpec
- Left
- UnitsDisplaySpec
- Punctuation
-
- PercentFormatDisplayDetails
-
- PercentForm
- Percent
- PrecisionPercents
- 1
-
-
- DKDGrids
-
- DynamicSnapGrid
- YES
- GuidesLayer
- NO
- MajorGrid
-
- GridAboveGraphics
- NO
- GridRGB
-
- Blue
- 1
- BluePlus
- 1
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDP3ColorSpace
- Green
- 0.651064
- GreenPlus
- 0.713725
- Opacity
- 0.6
- OpacityPlus
- 0.6
- Red
- 0.432559
- RedPlus
- 0.54902
-
- GridSpacingX
- 72
- GridSpacingY
- 72
- LinkGridToRulers
- NO
- PrintLineWidth
- 1
- PrintsGrid
- NO
- ShowsGrid
- NO
- SnapsToGrid
- NO
-
- MinorGrid
-
- GridAboveGraphics
- NO
- GridRGB
-
- Blue
- 0.848787
- BluePlus
- 0.87451
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDP3ColorSpace
- Green
- 0.828351
- GreenPlus
- 0.854902
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0.664186
- RedPlus
- 0.745098
-
- GridSpacingX
- 18
- GridSpacingY
- 18
- LinkGridToRulers
- NO
- PrintLineWidth
- 0.5
- PrintsGrid
- NO
- ShowsGrid
- YES
- SnapsToGrid
- NO
-
- SnapDrawing
- NO
- SnapEnds
- NO
- SnapGuidelines
- NO
- SnapRadiusGrid
- 3
- SnapSound
- None
- SoftSnap
- YES
-
- DKDHideExtension
- YES
- DKDLayersList
-
-
- CloakLayerGuidelines
- NO
- CloakLayerVertices
- NO
- FullLayerScale
-
- ArchivePrecision
- 12
- ScaleOriginX
- 0
- ScaleOriginY
- 0
- ScalePlusDown
- YES
- ScalePlusToRight
- YES
- ScaleScale
- 1
- ScaleUnits
- Centimeters
-
- GraphicsList
-
-
- AttributedText
-
- String
- Vertex subclass
- TextAttribute
- 0
-
- Bounds
- {{584.594428198, 92.5444270325}, {111.11092077, 21.4163415091}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 9852BB83
- GraphicStyle
- 10
-
-
- Bounds
- {{122.115430323, 283.075572388}, {108.290742591, 108.290742591}}
- Class
- DKDCircle
- DKDLockInfo
- 10
- GraphicID
- C0B95773
- GraphicStyle
- 8
-
-
- Bounds
- {{331.405592037, 134.116666667}, {108.290742591, 108.290742591}}
- Class
- DKDCircle
- DKDLockInfo
- 26
- GraphicID
- 6F7E8773
- GraphicStyle
- 8
-
-
- Bounds
- {{156.726360719, 135.484214289}, {78.4881890125, 78.4881890125}}
- Class
- DKDSquare
- DKDLockInfo
- 14
- GraphicID
- 17CBE773
- GraphicStyle
- 8
-
-
- Class
- DKDLine
- DKDLockInfo
- 14
- GraphicID
- 73CA6873
- GraphicStyle
- 24
- SVGPath
- M215.290624951,317.021883591 L357.33324706,212.161226418
-
-
- Bounds
- {{133.871950192, 329.397794982}, {87.782600853, 16.648764451}}
- Class
- DKDRectangle
- DKDLockInfo
- 14
- GraphicID
- 614BBC73
- GraphicStyle
- 8
-
-
- Class
- DKDContinuousBezier
- DKDLockInfo
- 14
- DkBezArrow
- 10
- GraphicID
- C2545D73
- GraphicStyle
- 40
- SVGPath
- M156.299321488,337.93308586 C156.299321488,337.93308586 156.299321488,337.93308586 156.299321488,337.93308586 C158.092340586,301.632198305 114.961293747,276.145578952 109.075031946,246.591412895 C104.100700363,221.615931586 106.298408981,187.190683552 153.333481954,186.323614649
-
-
- AttributedText
-
- String
- _edges
- TextAttribute
- 16
-
- Bounds
- {{152.127877297, 345.736705982}, {78.3773221901, 21.0231661209}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 35D9CF73
- GraphicStyle
- 10
-
-
- Class
- DKDContinuousBezier
- DKDLockInfo
- 14
- DkBezArrow
- 26
- GraphicID
- 2BF2D183
- GraphicStyle
- 56
- SVGPath
- M216.910249349,159.454893916 C216.910249349,159.454893916 216.91024935,159.454893916 216.91024935,159.454893916 C238.194121828,159.412376723 268.628145605,170.476785973 274.440766176,190.385559057 C283.259505097,220.590570711 225.746142372,267.158044238 204.393312879,291.212913739
-
-
- Class
- DKDContinuousBezier
- DKDLockInfo
- 14
- DkBezArrow
- 26
- GraphicID
- AC19D283
- GraphicStyle
- 56
- SVGPath
- M216.543099767,179.475592987 C216.543099767,179.475592987 216.543099767,179.475592987 216.543099767,179.475592987 C260.318439114,179.951153176 265.431057913,156.218627451 290.610971186,151.117492638 C306.284970846,147.942136771 322.063452074,148.951122287 338.970560146,158.82216796
-
-
- AttributedText
-
- String
- v1
- TextAttribute
- 16
-
- Bounds
- {{186.134058263, 150.294574897}, {31.0306494531, 21.0231661209}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 38F37683
- GraphicStyle
- 8
-
-
- AttributedText
-
- String
- v2
-
- TextAttribute
- 16
-
- Bounds
- {{186.128126855, 171.134378779}, {30.9110329578, 20.8018422269}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 19EDA683
- GraphicStyle
- 8
-
-
- AttributedText
-
- String
- Vertex subclass
- TextAttributes
-
- {0, 6}
- 32
- {6, 9}
- 0
-
-
- Bounds
- {{198.775981826, 381.234341154}, {111.11092077, 21.4163415091}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 5B25DB83
- GraphicStyle
- 10
-
-
- AttributedText
-
- String
- Vertex subclass
- TextAttributes
-
- {0, 6}
- 32
- {6, 9}
- 0
-
-
- Bounds
- {{414.510790464, 228.736856939}, {111.11092077, 21.4163415091}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 09BB7C83
- GraphicStyle
- 10
-
-
- AttributedText
-
- String
- Edge subclass
- TextAttributes
-
- {0, 4}
- 32
- {4, 9}
- 0
-
-
- Bounds
- {{157.882924378, 215.60312307}, {90.1938101669, 21.4163415091}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 18ED7C83
- GraphicStyle
- 10
-
-
- Bounds
- {{140.115430322, 589.075572388}, {108.290742591, 108.290742591}}
- Class
- DKDCircle
- DKDLockInfo
- 26
- GraphicID
- 5943FD83
- GraphicStyle
- 8
-
-
- Bounds
- {{349.405592037, 440.116666667}, {108.290742591, 108.290742591}}
- Class
- DKDCircle
- DKDLockInfo
- 26
- GraphicID
- 6943FD83
- GraphicStyle
- 8
-
-
- Bounds
- {{174.726360719, 441.484214289}, {78.4881890125, 78.4881890125}}
- Class
- DKDSquare
- DKDLockInfo
- 14
- GraphicID
- 7943FD83
- GraphicStyle
- 8
-
-
- Class
- DKDLine
- DKDLockInfo
- 14
- DkBezArrow
- 42
- GraphicID
- 8943FD83
- GraphicStyle
- 24
- SVGPath
- M233.290624951,623.021883591 L375.333247059,518.161226418
-
-
- Bounds
- {{151.871950192, 635.397794983}, {87.782600853, 16.648764451}}
- Class
- DKDRectangle
- DKDLockInfo
- 14
- GraphicID
- 9943FD83
- GraphicStyle
- 8
-
-
- Class
- DKDContinuousBezier
- DKDLockInfo
- 14
- DkBezArrow
- 10
- GraphicID
- A943FD83
- GraphicStyle
- 40
- SVGPath
- M174.299321488,643.93308586 C174.299321488,643.93308586 174.299321488,643.93308586 174.299321488,643.93308586 C176.092340586,607.632198305 132.961293747,582.145578952 127.075031945,552.591412895 C122.100700364,527.615931586 133.977096907,494.458739274 171.333481954,492.323614649
-
-
- AttributedText
-
- String
- _edges
- TextAttribute
- 16
-
- Bounds
- {{170.127877297, 651.736705982}, {78.3773221901, 21.0231661209}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- B943FD83
- GraphicStyle
- 10
-
-
- Class
- DKDContinuousBezier
- DKDLockInfo
- 14
- DkBezArrow
- 26
- GraphicID
- C943FD83
- GraphicStyle
- 56
- SVGPath
- M234.910249349,465.454893916 C234.910249349,465.454893916 234.910249349,465.454893916 234.910249349,465.454893916 C256.194121828,465.412376723 286.628145605,476.476785973 292.440766176,496.385559057 C301.259505097,526.590570711 243.746142371,573.158044238 222.393312879,597.212913739
-
-
- Class
- DKDContinuousBezier
- DKDLockInfo
- 14
- DkBezArrow
- 26
- GraphicID
- D943FD83
- GraphicStyle
- 56
- SVGPath
- M234.543099767,485.475592987 C234.543099767,485.475592987 234.543099767,485.475592987 234.543099767,485.475592987 C278.318439114,485.951153176 283.431057912,462.218627451 308.610971185,457.117492638 C324.284970846,453.942136771 340.063452074,454.951122287 356.970560146,464.82216796
-
-
- AttributedText
-
- String
- v1
- TextAttribute
- 16
-
- Bounds
- {{204.134058262, 456.294574896}, {31.0306494531, 21.0231661209}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- E943FD83
- GraphicStyle
- 8
-
-
- AttributedText
-
- String
- v2
-
- TextAttribute
- 16
-
- Bounds
- {{204.128126854, 477.134378779}, {30.9996031922, 21.0231661209}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- F943FD83
- GraphicStyle
- 8
-
-
- AttributedText
-
- String
- Vertex subclass
- TextAttributes
-
- {0, 6}
- 32
- {6, 9}
- 0
-
-
- Bounds
- {{216.775981825, 687.234341154}, {111.11092077, 21.4163415091}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 0A43FD83
- GraphicStyle
- 10
-
-
- AttributedText
-
- String
- Vertex subclass
- TextAttributes
-
- {0, 6}
- 32
- {6, 9}
- 0
-
-
- Bounds
- {{432.510790464, 534.736856939}, {111.11092077, 21.4163415091}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 1A43FD83
- GraphicStyle
- 10
-
-
- AttributedText
-
- String
- Edge subclass
- TextAttributes
-
- {0, 4}
- 32
- {4, 9}
- 0
-
-
- Bounds
- {{175.882924378, 521.60312307}, {90.1938101669, 21.4163415091}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 2A43FD83
- GraphicStyle
- 10
-
-
- Bounds
- {{343.72361627, 179.302318817}, {87.782600853, 16.648764451}}
- Class
- DKDRectangle
- DKDLockInfo
- 14
- GraphicID
- 43C31293
- GraphicStyle
- 8
-
-
- AttributedText
-
- String
- _edges
- TextAttribute
- 16
-
- Bounds
- {{361.979543375, 195.641229816}, {78.3773221901, 21.0231661209}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 53C31293
- GraphicStyle
- 10
-
-
- Bounds
- {{361.864971875, 484.284040959}, {87.782600853, 16.648764451}}
- Class
- DKDRectangle
- DKDLockInfo
- 14
- GraphicID
- 895D5293
- GraphicStyle
- 8
-
-
- AttributedText
-
- String
- _edges
- TextAttribute
- 16
-
- Bounds
- {{380.12089898, 500.622951958}, {78.3773221901, 21.0231661209}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 995D5293
- GraphicStyle
- 10
-
-
- Class
- DKDBezier
- DKDLockInfo
- 14
- DkBezArrow
- 2
- GraphicID
- AA5AC793
- GraphicStyle
- 56
- SVGPath
- M392.38395542,187.385848569 C392.38395542,187.385848569 392.38395542,187.385848569 392.38395542,187.385848569 C388.874616953,82.0118025472 314.836279053,62.9552738792 252.242178667,64.2646682342 C74.660984366,73.469899094 94.9233564416,159.621417018 155.871923044,158.837670052
-
-
- AttributedText
-
- String
- Undirected graph
- TextAttribute
- 48
-
- Bounds
- {{278.536338118, 269.434500953}, {202.348893933, 34.1385596992}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 14DEC993
- GraphicStyle
- 10
-
-
- AttributedText
-
- String
- Directed graph
- TextAttribute
- 48
-
- Bounds
- {{293.922046293, 579.498747608}, {175.234506692, 31.2274995402}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 55CF0C93
- GraphicStyle
- 10
-
-
- AttributedText
-
- String
- v1 is always the start vertex
- TextAttribute
- 64
-
- Bounds
- {{60.293252336, 441.009991214}, {97.7060551675, 35.5524288103}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 0DE69F93
- GraphicStyle
- 72
-
-
- Class
- DKDLine
- DKDLockInfo
- 14
- GraphicID
- 810832A3
- GraphicStyle
- 72
- SVGPath
- M157.882132105,455.367402409 L205.163707398,464.535419242
-
-
- AttributedText
-
- String
- order doesn't matter
- TextAttribute
- 64
-
- Bounds
- {{241.811440898, 94.6978314387}, {85.897378884, 35.5524288103}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 172903A3
- GraphicStyle
- 72
-
-
- Class
- DKDLine
- DKDLockInfo
- 14
- GraphicID
- 5E2CF3A3
- GraphicStyle
- 72
- SVGPath
- M207.795524408,150.73968488 L240.957211333,113.210245872
-
-
- AttributedText
-
- String
- list of Edges
- TextAttribute
- 64
-
- Bounds
- {{261.400575239, 323.584485991}, {85.897378884, 18.9174921865}}
- Class
- DKDTextArea
- DKDLockInfo
- 14
- GraphicID
- 8BCA09A3
- GraphicStyle
- 72
-
-
- Class
- DKDLine
- DKDLockInfo
- 14
- GraphicID
- 7462B9A3
- GraphicStyle
- 72
- SVGPath
- M221.084225911,339.165550309 L260.524401441,334.093988961
-
-
- HideDimensions
- NO
- LayerColorMod
-
- DKDOnColorMod
- NO
- DKDOpacityColorMod
- 0.5
- DKDOutlineColorMod
- NO
- DKDTintColorColorMod
-
- ColorSpace
- NSCalibratedWhiteColorSpace
- Opacity
- 1
- White
- 0.5
-
- DKDTintFractionColorMod
- 0.5
-
- LayerLock
- NO
- LayerName
- Paper
- LayerState
- Active
- OutlineLayer
- NO
-
-
- DKDPagesSpec
-
- BackgroundDisplay
- Background
- CanvasBorder
-
- Blue
- 0.45904
- BluePlus
- 0.533333
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0.458672
- GreenPlus
- 0.533333
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0.475001
- RedPlus
- 0.54902
-
- CanvasColor
-
- Catalog
- System
- Catalog-Color
- windowBackgroundColor
-
- CanvasMargin
- 0
- DetailsDrawerWidth
- 260
- DisplayAttributesBar
- YES
- DisplayRulers
- NO
- FullScreen
- NO
- FullScreenCanvasMargin
- 141.73228
- LayersDrawerWidth
- 266
- NonFullScreenCanvasMargin
- 0
- NumberAcrossFirst
- YES
- PagesAcross
- 1
- PagesDown
- 1
- PagesSpecBackgroundRGB
-
- ColorSpace
- NSCalibratedWhiteColorSpace
- Opacity
- 1
- White
- 1
-
- PagesSpecPrintBackground
- NO
- ShowPageBreaks
- NO
- SizeChecker
- 8
- aCheckerColor
-
- Blue
- 0.926349
- BluePlus
- 0.941176
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0.926333
- GreenPlus
- 0.941176
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0.926361
- RedPlus
- 0.941176
-
- bCheckerColor
-
- Blue
- 0.737155
- BluePlus
- 0.784314
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0.737142
- GreenPlus
- 0.784314
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0.737164
- RedPlus
- 0.784314
-
-
- DKDPrintInfo
-
- BottomMargin
- 18
- Copies
- 1
- FallBackPaperSizeHeight
- 841.889770508
- FallBackPaperSizeWidth
- 595.27557373
- FirstPage
- 1
- HorizontalPagination
- 2
- HorizontallyCentered
- YES
- LastPage
- -1
- LeftMargin
- 18
- MustCollate
- YES
- Orientation
- 0
- PaperName
- A4
- PaperSizeHeight
- 841.889770508
- PaperSizeWidth
- 595.27557373
- PreviewPageNumber
- 1
- PrintAllPages
- YES
- PrintJobDisposition
- NSPrintSpoolJob
- PrintSavePath
-
- PrintScalingFactor
- 1
- PrinterName
- Brother MFC-9340CDW
- ReversePageOrder
- NO
- RightMargin
- 18
- TopMargin
- 18
- VerticalPagination
- 0
- VerticallyCentered
- YES
- XPrintMirror
- NO
- YPrintMirror
- NO
-
- DKDSaveTimeStamp
- 2020-09-21 23:12:02 +0000
- DKDTablet
-
- BrushDynamic
- NO
- BrushFit
- 6
- PenMax
- 25
- PenMin
- 0.5
- PenPressureFactor
- 0.5
- PencilDynamic
- NO
- PencilFit
- 7
-
- DKDTimeFormat
-
- Field 0 Include
- Weekday
- Field 0 Type
- Long
- Field 1 Include
- Month
- Field 1 Type
- Short
- Field 2 Include
- Day
- Field 2 Type
- Number
- Field 3 Include
- Year
- Field 3 Type
- Long
- Include GMT
- NO
- Include Title
- YES
- IncludeDate
- YES
- IncludeTime
- YES
- Seperator 0
- -
- Seperator 1
- .
- Seperator 2
- ,
- Seperator 3
-
- Time Seperator
- :
- TimeAfterDate
- YES
- Twelve Hour Clock
- YES
- Used Once
- YES
-
- DKDToolbarSelectedButtonPairs
-
- ColorTextToolbarItemIdentifier_0
-
- HSB_10FFFF
-
- ColorFillToolbarItemIdentifier_0
-
- HSB_0000D0
-
- ColorStrokeToolbarItemIdentifier_0
-
- HSB_000020
-
- GradientToolbarItemIdentifier_0
-
-
- EndGradientColor
-
- Blue
- 0.999991
- BluePlus
- 1
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0.999974
- GreenPlus
- 1
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0.999999
- RedPlus
- 0.999996
-
- GradientFillClass
- DKDHorizontalGradientFill
- StartGradientColor
-
- Blue
- 0
- BluePlus
- 0
- ColorSpace
- NSCalibratedRGBColorSpace
- ColorSpacePlus
- DKDsRgbColorSpace
- Green
- 0
- GreenPlus
- 0
- Opacity
- 1
- OpacityPlus
- 1
- Red
- 0
- RedPlus
- 0
-
-
-
- PatternForToolbarItemIdentifier_0
-
- Toolbar_02
-
- TextureForToolbarItemIdentifier_0
-
- Ancient
-
-
- DKDWindowState
-
- CursorMode
- Nothing
- DocCenter
- {279.637786865, 269.670318249}
- DrawersOnMainView
- YES
- GDetailsLayersDrawerEdgePreference
- Auto
- GraphicDetailsOpen
- NO
- LayerActiveAbove
- NO
- LayerOpen
- NO
- LayerSelect
- Active Only
- LayersDrawerEdgePreference
- Auto
- OutlineDrawing
- NO
- WindowLocation
- 852 319 909 912 0 0 2560 1417
- ZoomPercent
- 160.180664
-
- GroupEdit
- Fixed
- NumberColorsToListInContextMenu
- 12
- NumberPairColorsToListInContextMenu
- 6
-
-
diff --git a/docs/source/dgraph.rst b/docs/source/dgraph.rst
deleted file mode 100644
index 32a56832..00000000
--- a/docs/source/dgraph.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-Directed graph
---------------
-
-
-.. autoclass:: pgraph.PGraph.DGraph
- :undoc-members:
- :show-inheritance:
- :inherited-members:
- :special-members: __init__
\ No newline at end of file
diff --git a/docs/source/directed.rst b/docs/source/directed.rst
deleted file mode 100644
index f61bd161..00000000
--- a/docs/source/directed.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-Directed graphs
-===============
-
-
-.. toctree::
- :maxdepth: 2
-
- dgraph
- dvertex
diff --git a/docs/source/dvertex.rst b/docs/source/dvertex.rst
index 7100e7dc..10e4d49f 100644
--- a/docs/source/dvertex.rst
+++ b/docs/source/dvertex.rst
@@ -1,8 +1,9 @@
Directed graph vertex
---------------------
+``DVertex`` overrides only ``connect()`` -- see :doc:`common` for the full
+method list (adjacent, edges, distance, degree, removal, ...).
+
.. autoclass:: pgraph.PGraph.DVertex
- :undoc-members:
+ :members: connect
:show-inheritance:
- :inherited-members:
- :special-members: __init__
\ No newline at end of file
diff --git a/docs/source/edges_vertices.rst b/docs/source/edges_vertices.rst
new file mode 100644
index 00000000..d0d6ea5c
--- /dev/null
+++ b/docs/source/edges_vertices.rst
@@ -0,0 +1,98 @@
+Edges & Vertices
+=================
+
+Underlying data structures
+----------------------------
+
+.. image:: ../figs/datastructures.svg
+
+The graph class maintains a list of vertices and a list of edges. Each vertex maintains
+a list of edges that connect to it, and each edge maintains a reference to the two
+vertices it connects. The graph class provides methods for adding and removing vertices
+and edges, as well as for querying the graph's structure.
+
+Working with vertices and edges directly
+-----------------------------------------
+
+In the earlier examples we did not explicitly create vertices or edges, but we
+can do so if we want to. The graph classes provide methods to create vertices and edges,
+and to add them to the graph.
+
+
+.. runblock:: pycon
+ :session:
+
+ >>> from pgraph import UGraph, UVertex, Edge
+ >>> import numpy as np
+ >>> g = UGraph()
+
+Next, we will explicitly create two vertices
+
+.. runblock:: pycon
+ :session:
+
+ >>> v1 = UVertex(np.random.rand(2))
+ >>> v2 = UVertex(np.random.rand(2))
+
+
+and then add them to the graph
+
+.. runblock:: pycon
+ :session:
+
+ >>> g.add_vertex(v1)
+ >>> g.add_vertex(v2)
+
+Our graph now has two vertices, but no edges
+
+.. runblock:: pycon
+ :session:
+
+ >>> print(g)
+
+We can explicitly create an edge between the two vertices
+
+.. runblock:: pycon
+ :session:
+
+ >>> e = Edge(v1, v2)
+
+and then add it to the graph
+
+.. runblock:: pycon
+ :session:
+
+ >>> g.add_edge(e)
+ >>> print(g)
+
+The ``Edge`` constuctor line above is equivalent to
+
+.. code-block:: python
+
+ >>> e = Edge()
+ >>> e.connect(v1, v2)
+
+Alternatively, we can create a vertex and *connect* it to an existing vertex, which will implitically create an edge between the two vertices and add it to the graph.
+
+.. runblock:: pycon
+ :session:
+
+ >>> v3 = UVertex(np.random.rand(2))
+ >>> g.add_vertex(v3)
+ >>> v2.connect(v3)
+ >>> print(g)
+
+The ``connect`` method of the vertex class creates an edge between the two
+vertices and adds it to the graph. The two vertices must have been added the same graph for the edge to be created.
+The ``connect`` method is available on both the
+directed and undirected vertex classes.
+
+
+.. note:: Where ever a vertex or edge is required, a subclass of the appropriate base class can be used. For example, we can create a subclass of ``UVertex`` called ``MyVertex`` and a subclass of ``Edge`` called ``MyEdge`` and then create a new graph using these classes.
+
+.. toctree::
+ :maxdepth: 2
+
+ dvertex
+ uvertex
+ edge
diff --git a/docs/source/export.rst b/docs/source/export.rst
new file mode 100644
index 00000000..059afcb1
--- /dev/null
+++ b/docs/source/export.rst
@@ -0,0 +1,23 @@
+Exporting a graph
+=================
+
+Graphs can be exported to a number of different formats, including dot (used by
+`GraphViz
`_) mermaid (a JavaScript-based graph
+visualization tool that can be used in MarkDown documents), GraphML (an
+XML-based format for representing graphs), ELK (a graph
+layout engine), as well as various image formats (e.g., PNG, SVG, PDF).
+
+See :doc:`visualization` for rendering the graph using Matplotlib itself rather than exporting
+it.
+
+.. autosummary::
+ :nosignatures:
+
+ ~pgraph.PGraph.BaseGraph.export
+ ~pgraph.PGraph.BaseGraph.dotfile
+
+Details
+-------
+
+.. automethod:: pgraph.PGraph.BaseGraph.export
+.. automethod:: pgraph.PGraph.BaseGraph.dotfile
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 2efbb675..e932f3a0 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -6,21 +6,14 @@
Graphs for Python
=================
-This package provides a set of classes for manipulating simple directed and undirected graphs in Python.
-
-
.. toctree::
- :maxdepth: 2
-
- directed
- undirected
- edge
- planning
- matrices
+ :maxdepth: 3
+ intro
+ api
Indices and tables
-==================
+------------------
* :ref:`genindex`
* :ref:`search`
diff --git a/docs/source/intro.rst b/docs/source/intro.rst
new file mode 100644
index 00000000..6c57ccb6
--- /dev/null
+++ b/docs/source/intro.rst
@@ -0,0 +1,240 @@
+Introduction
+=================
+
+This package provides classes for directed and undirected graphs: vertices
+connected by edges, with edge costs and path planning. Self-loops and
+parallel edges are permitted.
+
+Vertices can optionally be *embedded*: given a coordinate in a space of any
+dimension. Edge costs are then computed from the vertex positions using a
+distance metric (Euclidean, Manhattan, SE(2), or your own), the vertex nearest
+a point can be found, ``A*`` uses the metric as its heuristic, and the graph can
+be plotted, or exported with its layout preserved.
+
+What is a graph?
+-----------------
+
+A graph is an abstract representation of a set of objects connected by links and
+depicted visually as shown below. Graphs can be
+used to represent transport, communications or social networks, and this branch of
+mathematics is graph theory.
+
+Mathematically, a graph is denoted by
+:math:`G(V, E)` where :math:`V` are the vertices or nodes, and :math:`E` are the links that connect pairs
+of vertices and are called edges or arcs. Edges can be directed (shown as arrows) or
+undirected (shown as line segments) as in this case. Edges can have an associated
+weight or cost associated with moving from one vertex to another. A sequence of
+edges from one vertex to another is a path, and a sequence that starts and ends at
+the same vertex is a cycle. An edge from a vertex to itself is a loop.
+
+Creating a graph using the ``pgraph`` package
+----------------------------------------------
+
+To create a new graph using the ``pgraph`` package, we first import the package and create
+a new instance of the ``UGraph`` class, which represents an undirected graph. By default, the vertices of the graph exist in 2-dimensional space.
+
+.. runblock:: pycon
+ :session:
+
+ >>> import pgraph
+ >>> import numpy as np
+ >>> g = pgraph.UGraph()
+
+Next, we add some vertices to the graph, each with a random 2D coordinate which is
+specified as a 2-element array. The coordinates can be used to compute the cost of
+edges, and to plot the graph.
+
+.. runblock:: pycon
+ :session:
+
+ >>> np.random.seed(0) # ensure repeatable results
+ >>> for i in range(5):
+ ... g.add_vertex(np.random.rand(2))
+
+
+The method ``add_vertex`` returns a reference to the newly created vertex object, but
+we can obtain the reference by indexing the graph object. For example vertex 1 is
+
+.. runblock:: pycon
+ :session:
+
+ >>> g[1]
+
+and is an instance of ``UVertex``, a vertex in an undirected graph; it has the coordinate
+:math:`(0.6028, 0.5449)` and has been assigned a default name ``"#1"`` but we could specify
+an explicit name to ``add_vertex``.
+We can also reference a vertex by its name
+
+.. runblock:: pycon
+ :session:
+
+ >>> g["#1"]
+
+A summary of the graph can be displayed
+
+.. runblock:: pycon
+ :session:
+
+ >>> print(g)
+
+and we see that it has 5 vertices, no edges and 5 components, that is, each vertex is isolated.
+
+Next, we add edges to connect specific pairs of vertices
+
+ .. runblock:: pycon
+ :session:
+
+ >>> g.add_edge(g[0], g[1])
+ >>> g.add_edge(g[0], g[2])
+ >>> g.add_edge(g[0], g[3])
+ >>> g.add_edge(g[1], g[2])
+ >>> g.add_edge(g[1], g[3])
+ >>> g.add_edge(g[3], g[4])
+
+
+The ``add_edge`` method returns a reference to the edge object just created. By
+default, the edge cost is the Euclidean distance between the vertices, but this can
+be overridden by a third argument to ``add_edge``.
+
+A summary of the graph can be displayed
+
+ .. runblock:: pycon
+ :session:
+
+ >>> print(g)
+
+and we see that it has 5 vertices, six edges and one component, that is, all the vertices are connected into one net-
+work.
+
+The graph can be plotted by
+
+.. code-block:: python
+
+ >>> g.plot()
+
+.. plot::
+
+ >>> import pgraph
+ >>> import numpy as np
+ >>> g = pgraph.UGraph()
+ >>> np.random.seed(0) # ensure repeatable results
+ >>> for i in range(5):
+ >>> g.add_vertex(np.random.rand(2))
+ >>>
+ >>> g.add_edge(g[0], g[1])
+ >>> g.add_edge(g[0], g[2])
+ >>> g.add_edge(g[0], g[3])
+ >>> g.add_edge(g[1], g[2])
+ >>> g.add_edge(g[1], g[3])
+ >>> g.add_edge(g[3], g[4])
+ >>> g.plot()
+
+The vertices are shown as blue circles, and the edges are
+shown as lines joining vertices. Many options exist to change default plotting be-
+havior. Note that only graphs embedded in 2- and 3-dimensional space can be
+plotted.
+
+The neighbours of vertex 1 are
+
+ .. runblock:: pycon
+ :session:
+
+ >>> g[1].adjacent()
+
+
+which is a list of neighboring vertex objects, those connected to it by an edge. Each
+edge is an object and the edges connecting to vertex 1 are
+
+ .. runblock:: pycon
+ :session:
+
+ >>> g[1].edges()
+
+and each edge has references to the vertices it connects
+
+ .. runblock:: pycon
+ :session:
+
+ >>> g[1].edges()[0].endpoints
+
+
+The cost or length of an edge is
+
+ .. runblock:: pycon
+ :session:
+
+ >>> g[1].edges()[0].cost
+
+The vertex closest to the coordinate :math:`(0.5, 0.5)` is
+
+ .. runblock:: pycon
+ :session:
+
+ >>> g.closest((0.5, 0.5))
+
+The minimum-distance path between any two vertices in the graph can be computed using well-known algorithms such as A (Hart et al. 1968)
+
+ .. runblock:: pycon
+ :session:
+
+ >>> path, length, _ = g.path_Astar(g[2], g[4])
+ >>> path
+
+
+which is a list of vertices representing a total path length of
+
+ .. runblock:: pycon
+ :session:
+
+ >>> length
+
+Graphs can also be represented in other ways, such as adjacency, incidence, degree and Laplacian matrices, and
+methods exist to convert the graph to these.
+
+Arbitrary data can be attached to any vertex or edge by assigning values to attributes
+
+ .. runblock:: pycon
+ :session:
+
+ >>> g[1].data = "this is vertex 1"
+ >>> g[1].edges()[0].data = "this is the edge from vertex 0 to vertex 1"
+
+This exploits the flexible nature of Python, but care must be taken to avoid name clashes with existing attributes.
+
+A more robust and Pythonic approach is to create a subclass of the ``UVertex`` or ``DVertex`` classes class and
+declare them at graph creation time. For example, we can create a subclass of ``UVertex`` called ``MyVertex`` and a subclass of ``Edge`` called ``MyEdge`` and then create a new graph using these classes.
+
+.. runblock:: pycon
+ :session:
+
+ >>> import pgraph
+ >>> import numpy as np
+ >>> class MyVertex(pgraph.UVertex):
+ ... pass
+ >>> class MyEdge(pgraph.Edge):
+ ... pass
+ >>> g = pgraph.UGraph(vertex_class=MyVertex, edge_class=MyEdge)
+ >>> np.random.seed(0) # ensure repeatable results
+ >>> for i in range(5):
+ ... v = g.add_vertex(np.random.rand(2))
+ >>> g.add_edge(g[0], g[1])
+ >>> g.add_edge(g[0], g[2])
+ >>> g.add_edge(g[0], g[3])
+ >>> g.add_edge(g[1], g[2])
+ >>> g.add_edge(g[1], g[3])
+ >>> g.add_edge(g[3], g[4])
+ >>> print(g)
+
+we can see that the type of the vertices and edges is now the user-defined classes
+
+.. runblock:: pycon
+ :session:
+
+ >>> type(g[0])
+ >>> type(g[0].edges()[0])
+
+History
+--------
+
+``pgaph-python`` is based on ``PGraph.m`` which is part of the
+earlier `Spatial Math Toolbox for MATLAB `_.
diff --git a/docs/source/matrices.rst b/docs/source/matrices.rst
deleted file mode 100644
index d323b756..00000000
--- a/docs/source/matrices.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-Convert graph to matrix form
-============================
-
-These methods convert a graph to a matrix representation .
-
-.. autoclass:: pgraph.PGraph._BaseGraph
- :members: distance, adjacency, degree, incidence, laplacian
diff --git a/docs/source/modification.rst b/docs/source/modification.rst
new file mode 100644
index 00000000..23fa98a1
--- /dev/null
+++ b/docs/source/modification.rst
@@ -0,0 +1,42 @@
+Adding and removing vertices and edges
+========================================
+
+Building up and tearing down a graph's structure. ``connect()`` is shown
+here in its base-class form; :doc:`DVertex ` and
+:doc:`UVertex ` override it with different edge-list bookkeeping
+-- see those pages for the concrete behaviour. See :class:`Edge` for
+constructing/removing an edge directly rather than via a vertex or graph.
+
+Graph
+-----
+
+.. autosummary::
+ :nosignatures:
+
+ ~pgraph.PGraph.BaseGraph.add_vertex
+ ~pgraph.PGraph.BaseGraph.add_edge
+ ~pgraph.PGraph.BaseGraph.remove_edge
+ ~pgraph.PGraph.BaseGraph.remove_vertex
+
+Vertex
+------
+
+.. autosummary::
+ :nosignatures:
+
+ ~pgraph.PGraph.BaseVertex.connect
+ ~pgraph.PGraph.BaseVertex.edgeto
+ ~pgraph.PGraph.BaseVertex.remove
+
+Details
+-------
+
+.. automethod:: pgraph.PGraph.BaseGraph.add_vertex
+.. automethod:: pgraph.PGraph.BaseGraph.add_edge
+.. automethod:: pgraph.PGraph.BaseGraph.remove_edge
+.. automethod:: pgraph.PGraph.BaseGraph.remove_vertex
+.. automethod:: pgraph.PGraph.BaseGraph.remove
+
+.. automethod:: pgraph.PGraph.BaseVertex.connect
+.. automethod:: pgraph.PGraph.BaseVertex.edgeto
+.. automethod:: pgraph.PGraph.BaseVertex.remove
diff --git a/docs/source/modules.rst b/docs/source/modules.rst
deleted file mode 100644
index 7de9dadc..00000000
--- a/docs/source/modules.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-pgraph
-======
-
-.. toctree::
- :maxdepth: 4
-
- PGraph
diff --git a/docs/source/planning.rst b/docs/source/planning.rst
index 76dd3326..590abde6 100644
--- a/docs/source/planning.rst
+++ b/docs/source/planning.rst
@@ -3,5 +3,16 @@ Path planning
These methods find optimal paths from a start vertex to a goal vertex.
-.. autoclass:: pgraph.PGraph._BaseGraph
- :members: path_BFS, path_UCS, path_Astar
+.. autosummary::
+ :nosignatures:
+
+ ~pgraph.PGraph.BaseGraph.path_BFS
+ ~pgraph.PGraph.BaseGraph.path_UCS
+ ~pgraph.PGraph.BaseGraph.path_Astar
+
+Details
+-------
+
+.. automethod:: pgraph.PGraph.BaseGraph.path_BFS
+.. automethod:: pgraph.PGraph.BaseGraph.path_UCS
+.. automethod:: pgraph.PGraph.BaseGraph.path_Astar
diff --git a/docs/source/representations.rst b/docs/source/representations.rst
new file mode 100644
index 00000000..52ec2459
--- /dev/null
+++ b/docs/source/representations.rst
@@ -0,0 +1,25 @@
+Transformations to matrix representations
+==========================================
+
+These methods convert the graph to a number of different matrix representations.
+
+
+.. autosummary::
+ :nosignatures:
+
+ ~pgraph.PGraph.BaseGraph.distance
+ ~pgraph.PGraph.BaseGraph.adjacency
+ ~pgraph.PGraph.BaseGraph.degree
+ ~pgraph.PGraph.BaseGraph.incidence
+ ~pgraph.PGraph.BaseGraph.laplacian
+
+Details
+-------
+
+.. automethod:: pgraph.PGraph.BaseGraph.distance
+.. automethod:: pgraph.PGraph.BaseGraph.adjacency
+.. automethod:: pgraph.PGraph.BaseGraph.degree
+.. automethod:: pgraph.PGraph.BaseGraph.incidence
+.. automethod:: pgraph.PGraph.BaseGraph.laplacian
+
+
diff --git a/docs/source/ugraph.rst b/docs/source/ugraph.rst
deleted file mode 100644
index 0ba41fc4..00000000
--- a/docs/source/ugraph.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-Undirected graph
-----------------
-
-
-.. autoclass:: pgraph.PGraph.UGraph
- :undoc-members:
- :show-inheritance:
- :inherited-members:
- :special-members: __init__
\ No newline at end of file
diff --git a/docs/source/undirected.rst b/docs/source/undirected.rst
deleted file mode 100644
index 75ee9487..00000000
--- a/docs/source/undirected.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-Undirected graphs
-=================
-
-
-.. toctree::
- :maxdepth: 2
-
- ugraph
- uvertex
diff --git a/docs/source/uvertex.rst b/docs/source/uvertex.rst
index 1f0d9ee8..8c5a42f4 100644
--- a/docs/source/uvertex.rst
+++ b/docs/source/uvertex.rst
@@ -1,8 +1,9 @@
Undirected graph vertex
-----------------------
+``UVertex`` overrides only ``connect()`` -- see :doc:`common` for the full
+method list (adjacent, edges, distance, degree, removal, ...).
+
.. autoclass:: pgraph.PGraph.UVertex
- :undoc-members:
+ :members: connect
:show-inheritance:
- :inherited-members:
- :special-members: __init__
\ No newline at end of file
diff --git a/docs/source/visualization.rst b/docs/source/visualization.rst
new file mode 100644
index 00000000..74299981
--- /dev/null
+++ b/docs/source/visualization.rst
@@ -0,0 +1,24 @@
+Visualization
+==============
+
+Rendering the graph itself, with matplotlib or via GraphViz. See
+:doc:`representations` for exporting the graph as data (a matrix or dot
+file) rather than displaying it.
+
+.. autosummary::
+ :nosignatures:
+
+ ~pgraph.PGraph.BaseGraph.plot
+ ~pgraph.PGraph.BaseGraph.showgraph
+ ~pgraph.PGraph.BaseGraph.highlight_path
+ ~pgraph.PGraph.BaseGraph.highlight_edge
+ ~pgraph.PGraph.BaseGraph.highlight_vertex
+
+Details
+-------
+
+.. automethod:: pgraph.PGraph.BaseGraph.plot
+.. automethod:: pgraph.PGraph.BaseGraph.showgraph
+.. automethod:: pgraph.PGraph.BaseGraph.highlight_path
+.. automethod:: pgraph.PGraph.BaseGraph.highlight_edge
+.. automethod:: pgraph.PGraph.BaseGraph.highlight_vertex
diff --git a/pyproject.toml b/pyproject.toml
index 32cb28f3..f675c7ad 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -2,7 +2,7 @@
name = "pgraph-python"
version = "0.6.4"
authors = [{ name = "Peter Corke", email = "rvc@petercorke.com" }]
-description = "Mathematical graphs for Python"
+description = "Graphs for Python"
readme = "README.md"
requires-python = ">=3.9"
classifiers = [
diff --git a/src/pgraph/PGraph.py b/src/pgraph/PGraph.py
index 2edbaac7..63282e00 100644
--- a/src/pgraph/PGraph.py
+++ b/src/pgraph/PGraph.py
@@ -198,7 +198,7 @@ def Dict(cls, d: dict, reverse: bool = False, **kwargs: Any) -> BaseGraph:
Behaves like a constructor for a ``DGraph`` or ``UGraph`` from a
dictionary that maps vertices to parents. From this information it
- can create a tree graph.
+ can create a graph that is a tree or forest.
By default parent vertices are linked their children. If ``reverse`` is
True then children are linked to their parents.
@@ -268,13 +268,14 @@ def Adjacency(
:return: graph
:rtype: UGraph or DGraph
- Create a directed or undirected graph where non-zero elements ``A[i,j]``
+ Behaves like a constructor for a ``DGraph`` or ``UGraph`` creating the graph from an adjacency matrix ``A``.
+ Here non-zero elements ``A[i,j]``
correspond to edges from vertex ``i`` to vertex ``j``.
A non-zero diagonal element ``A[i,i]`` is a self-loop on vertex ``i``,
for both kinds of graph.
- .. warning:: For undirected graph ``A`` should be symmetric but this
+ .. warning:: For an undirected graph ``A`` should be symmetric but this
is not checked. Only the upper triangular part, including the
diagonal, is used. Elements are costs, not edge counts: a non-zero
element is a single edge with that element as its cost, so
@@ -332,6 +333,18 @@ def vertex_class(self) -> type[BaseVertex]:
:return: vertex class
:rtype: subclass of ``UVertex`` or ``DVertex``
+ This is read-only. It is set by the ``vertex_class`` argument of the
+ graph constructor, see :meth:`__init__`, and is ``UVertex`` for a
+ :class:`UGraph` and ``DVertex`` for a :class:`DGraph` if not given.
+
+ .. runblock:: pycon
+
+ >>> from pgraph import UGraph, UVertex
+ >>> class MyVertex(UVertex):
+ ... pass
+ >>> g = UGraph(vertex_class=MyVertex)
+ >>> print(g.vertex_class.__name__)
+
:seealso: :meth:`add_vertex` :attr:`edge_class`
"""
return self._vertex_class
@@ -344,6 +357,18 @@ def edge_class(self) -> type[Edge]:
:return: edge class
:rtype: subclass of ``Edge``
+ This is read-only. It is set by the ``edge_class`` argument of the
+ graph constructor, see :meth:`__init__`, and is :class:`Edge` if not
+ given.
+
+ .. runblock:: pycon
+
+ >>> from pgraph import UGraph, Edge
+ >>> class MyEdge(Edge):
+ ... pass
+ >>> g = UGraph(edge_class=MyEdge)
+ >>> print(g.edge_class.__name__)
+
:seealso: :meth:`add_edge` :attr:`vertex_class`
"""
return self._edge_class
@@ -567,6 +592,10 @@ def copy(self) -> BaseGraph:
``RecursionError`` for a graph with a path of about a hundred
vertices.
+ Copies the graph, its vertices and edges, but not any external data that may be
+ attached to them. The copy is a new graph of the same kind, with the same
+ vertices and edges, but the vertices and edges are new objects.
+
.. runblock:: pycon
>>> from pgraph import UGraph
@@ -688,6 +717,8 @@ def add_vertex(
:return: the added vertex
:rtype: BaseVertex subclass
+ This is a graph-centric way of creating a vertex.
+
- ``g.add_vertex()`` creates a new vertex with optional ``coord`` and
``name``.
- ``g.add_vertex(v)`` takes an instance of this graph's
@@ -708,21 +739,19 @@ def add_vertex(
in the graph but unreachable by name. A default name could also
clash with an existing one after a vertex had been removed.
- The vertex is placed into a dictionary with a key equal to its name.
-
- This single implementation, shared by :class:`UGraph` and
- :class:`DGraph`, is parameterized by the graph's :attr:`vertex_class`
- rather than duplicated per subclass -- see :doc:`policy` for why that
- matters.
+ The vertex is placed into the graph's vertex dictionary with a key equal to its name.
.. runblock:: pycon
>>> from pgraph import UGraph, UVertex
>>> g = UGraph()
>>> v1 = g.add_vertex(coord=[0,0])
+ >>> repr(v1)
+ >>> print(v1)
>>> print(v1.name)
>>> v2 = g.add_vertex(UVertex(coord=[1,1], name='v2'))
>>> print(v2.name)
+ >>> g['v2']
If the graph was constructed with a required ``dim`` (see
:meth:`BaseGraph.__init__`), every embedded vertex must have a
@@ -736,6 +765,11 @@ def add_vertex(
>>> v1 = g.add_vertex(coord=[0, 0, 0, 0, 0, 0], name='pose1')
>>> print(v1)
+ .. note:: This single implementation, shared by :class:`UGraph` and
+ :class:`DGraph`, is parameterized by the graph's :attr:`vertex_class`
+ rather than duplicated per subclass -- see :doc:`policy` for why that
+ matters.
+
:seealso: :meth:`vertex_copy`
"""
if isinstance(coord, self._vertex_class):
@@ -881,31 +915,32 @@ def add_edge(
"""
Add an edge to the graph (base class method)
- :param v1: first vertex (start if a directed graph), or an existing
- edge that already carries its two vertices
+ :param v1: first vertex (start if a directed graph), or an existing edge that
+ already carries its two vertices
:type v1: BaseVertex subclass, str or Edge
- :param v2: second vertex (end if a directed graph), must be omitted
- if ``v1`` is an edge
+ :param v2: second vertex (end if a directed graph), must be omitted if ``v1`` is
+ an edge
:type v2: BaseVertex subclass or str, optional
- :param kwargs: optional arguments to pass to ``BaseVertex.connect``,
- not allowed if ``v1`` is an edge
- :raises TypeError: ``v1`` or ``v2`` is of the wrong type, or ``v2``,
- ``cost`` or ``data`` is given along with an edge
- :raises ValueError: the edge has no vertices, or the vertices do not
- belong to this graph
+ :param kwargs: optional arguments to pass to ``BaseVertex.connect``, not allowed
+ if ``v1`` is an edge
+ :raises TypeError: ``v1`` or ``v2`` is of the wrong type, or ``v2``, ``cost`` or
+ ``data`` is given along with an edge
+ :raises ValueError: the edge has no vertices, or the vertices do not belong to
+ this graph
:return: edge
:rtype: Edge
- - ``g.add_edge(v1, v2)`` creates an edge between a vertex pair and
- adds it to the graph.
- - ``g.add_edge(e)`` takes an edge, or an instance of an ``Edge``
- subclass, that was constructed with its two vertices and adds it to
- the graph, just as ``g.add_vertex(v)`` takes an existing vertex.
+ This is a graph-centric way of creating an edge. The alternative is the
+ ``connect`` method of a vertex.
- This is a graph centric way of creating an edge. The
- alternative is the ``connect`` method of a vertex.
+ - ``g.add_edge(v1, v2)`` creates an edge between a vertex pair and adds it to
+ the graph.
+ - ``g.add_edge(e)`` takes an edge, or an instance of an ``Edge`` subclass, that
+ was constructed with its two vertices and adds it to the graph, just as
+ ``g.add_vertex(v)`` takes an existing vertex.
.. runblock:: pycon
+ :linenos:
>>> from pgraph import UGraph
>>> g = UGraph()
@@ -917,9 +952,12 @@ def add_edge(
>>> e2 = g.add_edge('v2', 'v3', cost=99)
>>> print(e2)
+ Note that at line 9 the vertices are specified by their string names.
+
Adding an instance of a user-defined ``Edge`` subclass:
.. runblock:: pycon
+ :linenos:
>>> from pgraph import UGraph, Edge
>>> class MyEdge(Edge):
@@ -930,6 +968,8 @@ def add_edge(
>>> e = g.add_edge(MyEdge(v1, v2, data="a road"))
>>> print(type(e).__name__, e.data)
+ .. note:: Vertices have coordinates and the edge ``cost`` defaults to the distance between them, but if the vertices have no coordinates the edge cost must be set explicitly, otherwise it will be ``None`` and path planning will fail with a ``ValueError``. See :meth:`_require_cost` for details.
+
.. note:: To supply an edge that does not yet have vertices use
``g.add_edge(v1, v2, edge=e)`` or ``e.connect(v1, v2)``.
@@ -978,10 +1018,6 @@ def remove_edge(self, edge: Edge) -> None:
.. warning:: The connectivity of the network may be changed.
- .. note:: An undirected edge is held by both of its vertices and a
- directed edge only by its source (see :meth:`BaseVertex.edges`).
- Each vertex kind knows which, so this method does not.
-
.. runblock:: pycon
>>> from pgraph import UGraph
@@ -992,6 +1028,13 @@ def remove_edge(self, edge: Edge) -> None:
>>> g.remove_edge(e)
>>> print(g)
+ .. note:: A directed edge is tracked only by its source vertex's
+ edge list, not its target's (see :attr:`BaseVertex.edges`), so
+ membership is checked per endpoint rather than assumed for both
+ -- removing a directed edge from an undirected-only
+ implementation would otherwise raise ``ValueError`` on the
+ target side.
+
:seealso: :meth:`remove_vertex` :meth:`Edge.remove`
"""
if edge not in self._edges:
@@ -1024,12 +1067,6 @@ def remove_vertex(self, vertex: BaseVertex) -> None:
.. warning:: The connectivity of the network may be changed.
- .. note:: This scans the graph's own edge set for edges touching
- ``vertex``, rather than iterating ``vertex.edges()`` --
- for a ``DGraph`` vertex that only ever reports outgoing edges
- (see :attr:`BaseVertex.edges`), so incoming edges would
- otherwise be missed and left dangling.
-
.. runblock:: pycon
>>> from pgraph import UGraph
@@ -1040,6 +1077,12 @@ def remove_vertex(self, vertex: BaseVertex) -> None:
>>> g.remove_vertex(v2)
>>> print(g)
+ .. note:: This scans the graph's own edge set for edges touching
+ ``vertex``, rather than iterating ``vertex.edges()`` --
+ for a ``DGraph`` vertex that only ever reports outgoing edges
+ (see :attr:`BaseVertex.edges`), so incoming edges would
+ otherwise be missed and left dangling.
+
:seealso: :meth:`remove_edge` :meth:`BaseVertex.remove`
"""
if vertex._graph is not self:
@@ -1159,16 +1202,7 @@ def nc(self) -> int:
:return: Number of components
:rtype: int
- .. note::
-
- - Components are labeled from 0 to ``g.nc-1``.
- - A graph coloring algorithm is run if the graph connectivity
- has changed.
-
- .. note:: A lazy approach is used, and if a connectivity changing
- operation has been performed since the last call, the graph
- coloring algorithm is run which is potentially expensive for
- a large graph.
+ Number of components in the graph. Components are labeled from 0 to ``g.nc-1``.
.. runblock:: pycon
@@ -1179,6 +1213,13 @@ def nc(self) -> int:
>>> v3 = g.add_vertex(name='v3')
>>> g.add_edge(v1, v2)
>>> print(g.nc)
+
+ .. note:: A lazy approach is used, and if a connectivity changing
+ operation has been performed since the last call, the graph
+ coloring algorithm is run which is potentially expensive for
+ a large graph.
+
+ :seealso: :meth:`component` :meth:`samecomponent`
"""
n = self._graphcolor()
if n is not None:
@@ -1460,7 +1501,7 @@ def closest(self, coord: ArrayLike) -> tuple[BaseVertex | None, float]:
def edges(self) -> list[Edge]:
"""
- Get all edges in graph (base class method)
+ Return a set of all edges in graph (base class method)
:return: All edges in the graph
:rtype: list of Edge references
@@ -1513,7 +1554,7 @@ def plot(
ax: Any = None,
) -> None:
"""
- Plot the graph
+ Plot graph as a vertex/edge diagram using Matplotlib
:param vopt: vertex format, defaults to 12pt o-marker
:type vopt: dict, optional
@@ -1533,10 +1574,17 @@ def plot(
:raises ValueError: the graph is empty, or a vertex has no coordinate
or fewer than two coordinate values
- The graph is plotted using matplotlib.
+ The graph is plotted using Matplotlib according to the dimensionality of the vertex
+ coordinates (set by the `dim` parameter to graph constructor). If the dimensionality is
+
+ - 2, then a 2D plot is generated.
+ - 3, then a 3D plot is generated.
+ - 4 or more, then a 3D plot is generated using the first three coordinates.
- If ``colorcomponents`` is True then each component is assigned a unique
- color. ``vertex`` and ``edge`` cannot include a color keyword.
+ If a vertex has no coordinate or fewer than two values, a ValueError is raised.
+
+ If ``colorcomponents`` is True then all edges and vertices within a component are assigned a unique
+ color.
If ``text`` is a dict it is used to format text labels for the vertices
which are the vertex names. If ``text`` is None or True default
@@ -1549,20 +1597,26 @@ def plot(
.. runblock:: pycon
>>> from pgraph import UGraph
+ >>> import numpy as np
+ >>> np.random.seed(0)
>>> g = UGraph()
- >>> v1 = g.add_vertex(coord=[0,0], name='v1')
- >>> v2 = g.add_vertex(coord=[1,1], name='v2')
- >>> g.add_edge(v1, v2)
+ >>> for i in range(5):
+ ... g.add_vertex(np.random.rand(2));
+ >>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
+ ... g.add_edge(g[i], g[j]);
>>> g.plot(block=None)
.. plot::
- from pgraph import UGraph
- g = UGraph()
- v1 = g.add_vertex(coord=[0,0], name='v1')
- v2 = g.add_vertex(coord=[1,1], name='v2')
- g.add_edge(v1, v2)
- g.plot(block=None)
+ >>> from pgraph import UGraph
+ >>> import numpy as np
+ >>> np.random.seed(0)
+ >>> g = UGraph()
+ >>> for i in range(5):
+ ... g.add_vertex(np.random.rand(2));
+ >>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
+ ... g.add_edge(g[i], g[j]);
+ >>> g.plot(block=None)
:seealso: :meth:`highlight_path`
"""
@@ -1671,26 +1725,30 @@ def highlight_path(
.. runblock:: pycon
>>> from pgraph import UGraph
+ >>> import numpy as np
+ >>> np.random.seed(0)
>>> g = UGraph()
- >>> v1 = g.add_vertex(coord=[0,0], name='v1')
- >>> v2 = g.add_vertex(coord=[1,1], name='v2')
- >>> v3 = g.add_vertex(coord=[2,2], name='v3')
- >>> g.add_edge(v1, v2)
- >>> g.add_edge(v2, v3)
+ >>> for i in range(5):
+ ... g.add_vertex(np.random.rand(2));
+ >>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
+ ... g.add_edge(g[i], g[j]);
>>> g.plot(block=None)
- >>> g.highlight_path([v1, v2, v3], block=None)
+ >>> path, length, _ = g.path_Astar(g[2], g[4])
+ >>> g.highlight_path(path, block=None)
.. plot::
- from pgraph import UGraph
- g = UGraph()
- v1 = g.add_vertex(coord=[0,0], name='v1')
- v2 = g.add_vertex(coord=[1,1], name='v2')
- v3 = g.add_vertex(coord=[2,2], name='v3')
- g.add_edge(v1, v2)
- g.add_edge(v2, v3)
- g.plot(block=None)
- g.highlight_path([v1, v2, v3], block=None)
+ >>> from pgraph import UGraph
+ >>> import numpy as np
+ >>> np.random.seed(0)
+ >>> g = UGraph()
+ >>> for i in range(5):
+ ... g.add_vertex(np.random.rand(2));
+ >>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
+ ... g.add_edge(g[i], g[j]);
+ >>> g.plot(block=None)
+ >>> path, length, _ = g.path_Astar(g[2], g[4])
+ >>> g.highlight_path(path, block=None)
:seealso: :meth:`highlight_vertex` :meth:`highlight_edge`
"""
@@ -1706,11 +1764,11 @@ def highlight_edge(
self, edge: Edge, scale: float = 2, color: str = "r", alpha: float = 0.5
) -> None:
"""
- Highlight an edge in the graph
+ Highlight an edge in a plot of the graph
:param edge: The edge to highlight
:type edge: Edge subclass
- :param scale: Overwrite with a line this much bigger than the original,
+ :param scale: Overwrite with a line that is thicker than the original,
defaults to 1.5
:type scale: float, optional
:param color: Overwrite with a line in this color, defaults to 'r'
@@ -1724,26 +1782,33 @@ def highlight_edge(
.. runblock:: pycon
>>> from pgraph import UGraph
+ >>> import numpy as np
+ >>> np.random.seed(0)
+
>>> g = UGraph()
- >>> v1 = g.add_vertex(coord=[0,0], name='v1')
- >>> v2 = g.add_vertex(coord=[1,1], name='v2')
- >>> e = g.add_edge(v1, v2)
+ >>> for i in range(5):
+ ... g.add_vertex(np.random.rand(2));
+ >>> edges = []
+ >>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
+ ... edges.append(g.add_edge(g[i], g[j]));
>>> g.plot(block=None)
- >>> g.highlight_edge(e)
-
- The plot produced looks like:
+ >>> g.highlight_edge(edges[2])
.. plot::
- from pgraph import UGraph
- g = UGraph()
- v1 = g.add_vertex(coord=[0,0], name='v1')
- v2 = g.add_vertex(coord=[1,1], name='v2')
- e = g.add_edge(v1, v2)
- g.plot(block=None)
- g.highlight_edge(e)
+ >>> from pgraph import UGraph
+ >>> import numpy as np
+ >>> np.random.seed(0)
+ >>> g = UGraph()
+ >>> for i in range(5):
+ ... g.add_vertex(np.random.rand(2));
+ >>> edges = []
+ >>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
+ ... edges.append(g.add_edge(g[i], g[j]));
+ >>> g.plot(block=None)
+ >>> g.highlight_edge(edges[2])
- :seealso: :meth:`highlight_vertex` :meth:`highlight_path`
+ :seealso: :meth:`plot` :meth:`highlight_vertex` :meth:`highlight_path`
"""
p1 = edge.v1
p2 = edge.v2
@@ -1765,7 +1830,7 @@ def highlight_vertex(
:param vertex: The vertex (or vertices, or vertex names) to highlight
:type vertex: BaseVertex subclass, or iterable of BaseVertex subclass or str
- :param scale: Overwrite with a line this much bigger than the original,
+ :param scale: Overwrite with a marker that is larger than the original,
defaults to 1.5
:type scale: float, optional
:param color: Overwrite with a line in this color, defaults to 'r'
@@ -1777,22 +1842,28 @@ def highlight_vertex(
.. runblock:: pycon
>>> from pgraph import UGraph
+ >>> import numpy as np
+ >>> np.random.seed(0)
>>> g = UGraph()
- >>> v1 = g.add_vertex(coord=[0,0], name='v1')
- >>> v2 = g.add_vertex(coord=[1,1], name='v2')
- >>> g.add_edge(v1, v2)
+ >>> for i in range(5):
+ ... g.add_vertex(np.random.rand(2));
+ >>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
+ ... g.add_edge(g[i], g[j]);
>>> g.plot(block=None)
- >>> g.highlight_vertex(v1)
+ >>> g.highlight_vertex(g[2])
.. plot::
- from pgraph import UGraph
- g = UGraph()
- v1 = g.add_vertex(coord=[0,0], name='v1')
- v2 = g.add_vertex(coord=[1,1], name='v2')
- g.add_edge(v1, v2)
- g.plot(block=None)
- g.highlight_vertex(v1)
+ >>> from pgraph import UGraph
+ >>> import numpy as np
+ >>> np.random.seed(0)
+ >>> g = UGraph()
+ >>> for i in range(5):
+ ... g.add_vertex(np.random.rand(2));
+ >>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
+ ... g.add_edge(g[i], g[j]);
+ >>> g.plot(block=None)
+ >>> g.highlight_vertex(g[2])
"""
if isinstance(vertex, Iterable):
@@ -1812,7 +1883,7 @@ def export(
**options: Any,
) -> str | None:
"""
- Export the graph as text or as a rendered image
+ Convert and save the graph in a graph export or image format
:param filename: destination path or open file, defaults to None
:type filename: str, path-like or file object, optional
@@ -1950,13 +2021,10 @@ def dotfile(
- The graph is undirected if it is a subclass of ``UGraph``
- The graph is directed if it is a subclass of ``DGraph``
- The ``graphviz`` formatters ``dot`` and ``neato`` can be used to render the
- graph in various formats including PDF, PNG, JPG, GIF, SVG, etc. The formmatters are
- similar, but ``dot`` is better suited for directed graphs while ``neato`` is better
- suited for undirected graphs.
-
- .. note:: If ``filename`` is a file object then the file will *not*
- be closed after the GraphViz model is written.
+ .. note:: The ``graphviz`` formatters ``dot`` and ``neato`` can be used to render the
+ graph in various formats including PDF, PNG, JPG, GIF, SVG, etc. The formmatters are
+ similar, but ``dot`` is better suited for directed graphs while ``neato`` is better
+ suited for undirected graphs.
.. runblock:: pycon
@@ -1967,6 +2035,12 @@ def dotfile(
>>> g.add_edge(v1, v2)
>>> g.dotfile()
+ .. note:: Edge costs are not included in the output. Use :meth:`export` with
+ ``costs=True`` to include them.
+
+ .. note:: If ``filename`` is a file object then the file will *not*
+ be closed after the GraphViz model is written. Safe for use with ``sys.stdout`` or ``sys.stderr``.
+
:seealso: :meth:`export` :meth:`showgraph`
"""
from . import exporters
@@ -1982,7 +2056,7 @@ def dotfile(
def showgraph(self, display: bool = True, **options: Any) -> str | None:
"""
- Display graph in a browser tab
+ Display graph as a vertex/edge diagram in a browser tab
:param display: open the rendered PDF in a browser tab, defaults to True
:param options: ``engine``, ``direction``, ``colorcomponents`` and
@@ -1996,6 +2070,8 @@ def showgraph(self, display: bool = True, **options: Any) -> str | None:
``display=False`` the PDF is rendered but not opened and its path is
returned, which is useful for tests and notebooks.
+ .. note:: Vertices do not have to have coordinates for this to work, but if they do the coordinates are used to position the vertices in the output. If no coordinates are given, GraphViz will choose a layout.
+
:seealso: :meth:`export` :meth:`dotfile`
"""
pdf = tempfile.NamedTemporaryFile(suffix=".pdf", delete=False)
@@ -2026,18 +2102,6 @@ def iscyclic(self) -> bool:
vertices' outgoing edges via :meth:`BaseVertex.adjacent` the same
way :meth:`path_BFS` and friends do.
- .. note:: A self-loop is a cycle of length one, so it makes either kind
- of graph cyclic. Two parallel edges between the same pair of
- vertices are a cycle in an undirected graph, but a repeated
- arrow in a directed graph is not.
-
- .. note:: A matrix-based test also exists in theory -- a digraph is
- acyclic iff its adjacency matrix is nilpotent (all eigenvalues
- zero) -- but that needs an O(N^3) eigendecomposition plus a
- floating-point zero-tolerance judgement call, to answer a
- question Kahn's algorithm answers exactly with integers in
- O(V+E). Not used here for that reason.
-
.. runblock:: pycon
>>> from pgraph import UGraph
@@ -2051,6 +2115,18 @@ def iscyclic(self) -> bool:
>>> g.add_edge(v3, v1)
>>> print(g.iscyclic())
+ .. note:: A self-loop is a cycle of length one, so it makes either kind
+ of graph cyclic. Two parallel edges between the same pair of
+ vertices are a cycle in an undirected graph, but a repeated
+ arrow in a directed graph is not.
+
+ .. note:: A matrix-based test also exists in theory -- a digraph is
+ acyclic iff its adjacency matrix is nilpotent (all eigenvalues
+ zero) -- but that needs an O(N^3) eigendecomposition plus a
+ floating-point zero-tolerance judgement call, to answer a
+ question Kahn's algorithm answers exactly with integers in
+ O(V+E). Not used here for that reason.
+
:seealso: :meth:`adjacency`
"""
if isinstance(self, UGraph):
@@ -2099,11 +2175,11 @@ def average_degree(self) -> float:
>>> v1 = g.add_vertex(name='v1')
>>> v2 = g.add_vertex(name='v2')
>>> v3 = g.add_vertex(name='v3')
- >>> g.add_edge(v1, v2)
- >>> g.add_edge(v2, v3)
+ >>> g.add_edge(v1, v2);
+ >>> g.add_edge(v2, v3);
>>> print(g.average_degree())
- :seealso: :meth:`degree`
+ :seealso: :meth:`degree` :meth:`connectivity` :attr:`BaseVertex.degree`
"""
return 2 * self.ne / self.n
@@ -2113,7 +2189,7 @@ def average_degree(self) -> float:
def laplacian(self) -> NDArray:
"""
- Laplacian matrix for the graph
+ Convert the graph to a Laplacian matrix
:return: Laplacian matrix
:rtype: NumPy ndarray
@@ -2127,11 +2203,9 @@ def laplacian(self) -> NDArray:
>>> import numpy as np
>>> g = UGraph()
>>> for i in range(5):
- ... g.add_vertex(np.random.rand(2))
- ...
+ ... g.add_vertex(np.random.rand(2));
>>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
- ... g.add_edge(g[i], g[j])
- ...
+ ... g.add_edge(g[i], g[j]);
>>> L = g.laplacian()
>>> print(L)
@@ -2145,12 +2219,11 @@ def laplacian(self) -> NDArray:
zero-valued eigenvalues equals the number of connected
components.
- For a **directed** graph, this computes the out-degree
- Laplacian (a real, recognized construction, e.g. in directed
+ Laplacian (used in directed
consensus/synchronization literature) -- but it is generally
*not* symmetric, its eigenvalues can be complex, and the
zero-eigenvalue/component-count relationship above does not
- hold. For example a simple weakly-connected out-tree (one
- component) already has two zero eigenvalues, not one.
+ hold.
.. rubric:: For graphs with parallel edges or loops
@@ -2219,11 +2292,9 @@ def connectivity(self, vertices: Iterable[BaseVertex] | None = None) -> list[int
>>> import numpy as np
>>> g = UGraph()
>>> for i in range(5):
- ... g.add_vertex(np.random.rand(2))
- ...
+ ... g.add_vertex(np.random.rand(2));
>>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
- ... g.add_edge(g[i], g[j])
- ...
+ ... g.add_edge(g[i], g[j]);
>>> c = g.connectivity()
>>> print(c)
@@ -2231,7 +2302,7 @@ def connectivity(self, vertices: Iterable[BaseVertex] | None = None) -> list[int
.. note:: This is the diagonal of :meth:`degree`. Parallel edges are
counted individually.
- :seealso: :meth:`degree`
+ :seealso: :meth:`degree` :meth:`average_degree` :attr:`BaseVertex.degree`
"""
c = []
@@ -2243,7 +2314,7 @@ def connectivity(self, vertices: Iterable[BaseVertex] | None = None) -> list[int
def degree(self) -> NDArray:
"""
- Degree matrix of graph
+ Convert graph to a degree matrix
:return: degree matrix
:rtype: ndarray(N,N)
@@ -2265,11 +2336,9 @@ def degree(self) -> NDArray:
>>> import numpy as np
>>> g = UGraph()
>>> for i in range(5):
- ... g.add_vertex(np.random.rand(2))
- ...
+ ... g.add_vertex(np.random.rand(2));
>>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
- ... g.add_edge(g[i], g[j])
- ...
+ ... g.add_edge(g[i], g[j]);
>>> d = g.degree()
>>> print(d)
@@ -2287,7 +2356,7 @@ def degree(self) -> NDArray:
def adjacency(self) -> NDArray:
"""
- Adjacency matrix of graph
+ Convert graph to an adjacency matrix
:returns: adjacency matrix
:rtype: ndarray(N,N)
@@ -2301,11 +2370,9 @@ def adjacency(self) -> NDArray:
>>> import numpy as np
>>> g = UGraph()
>>> for i in range(5):
- ... g.add_vertex(np.random.rand(2))
- ...
+ ... g.add_vertex(np.random.rand(2));
>>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
- ... g.add_edge(g[i], g[j])
- ...
+ ... g.add_edge(g[i], g[j]);
>>> A = g.adjacency()
>>> print(A)
@@ -2316,7 +2383,7 @@ def adjacency(self) -> NDArray:
- for an undirected graph the matrix is symmetric
- Eigenvalues of ``A`` are real and are known as the spectrum of the graph.
- The element ``A[i,j]`` is the number of walks of length one
- edge from vertex ``i`` to vertex ``j``, which is the number of
+ from vertex ``i`` to vertex ``j``, which is the number of
edges between them (zero or one for a simple graph).
- If ``Ak = A ** k`` the element ``Ak[i,j]`` is the number of
walks of length ``k`` from vertex ``i`` to vertex ``j``.
@@ -2344,7 +2411,7 @@ def adjacency(self) -> NDArray:
def incidence(self) -> NDArray:
"""
- Incidence matrix of graph
+ Convert graph to an incidence matrix
:returns: incidence matrix
:rtype: ndarray(n,ne)
@@ -2358,18 +2425,16 @@ def incidence(self) -> NDArray:
>>> import numpy as np
>>> g = UGraph()
>>> for i in range(5):
- ... g.add_vertex(np.random.rand(2))
- ...
+ ... g.add_vertex(np.random.rand(2));
>>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
- ... g.add_edge(g[i], g[j])
- ...
+ ... g.add_edge(g[i], g[j]);
>>> I = g.incidence()
>>> print(I)
.. note::
- - vertices are numbered in their order of creation. A vertex index
+ - Vertices are numbered in their order of creation. A vertex index
can be resolved to a vertex reference by ``graph[i]``.
- - edges are numbered in the order they appear in :meth:`edges`, which
+ - Edges are numbered in the order they appear in :meth:`edges`, which
is the order they were added.
- Both endpoints of every edge are marked, regardless of
direction -- for a ``DGraph`` this means a vertex that is only
@@ -2405,7 +2470,7 @@ def incidence(self) -> NDArray:
def distance(self) -> NDArray:
"""
- Distance matrix of graph
+ Convert graph to a distance matrix
:return: distance matrix
:rtype: ndarray(n,n)
@@ -2420,11 +2485,9 @@ def distance(self) -> NDArray:
>>> import numpy as np
>>> g = UGraph()
>>> for i in range(5):
- ... g.add_vertex(np.random.rand(2))
- ...
+ ... g.add_vertex(np.random.rand(2));
>>> for i, j in [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (3, 4)]:
- ... g.add_edge(g[i], g[j])
- ...
+ ... g.add_edge(g[i], g[j]);
>>> d = g.distance()
>>> print(d)
@@ -2468,10 +2531,11 @@ def component(self, c: int) -> list[BaseVertex]:
>>> v1 = g.add_vertex(name='v1')
>>> v2 = g.add_vertex(name='v2')
>>> v3 = g.add_vertex(name='v3')
- >>> g.add_edge(v1, v2)
+ >>> g.add_edge(v1, v2);
+ >>> print(g)
>>> print(g.component(0))
- :seealso: :meth:`nc` :meth:`samecomponent`
+ :seealso: :attr:`nc` :meth:`samecomponent`
"""
self._graphcolor() # ensure labels are uptodate
return [v for v in self if v.label == c]
@@ -2503,7 +2567,7 @@ def samecomponent(self, v1: BaseVertex, v2: BaseVertex) -> bool:
>>> print(g.samecomponent(v1, v2))
>>> print(g.samecomponent(v1, v3))
- :seealso: :meth:`component`
+ :seealso: :meth:`component` :attr:`nc`
"""
self._graphcolor() # ensure labels are uptodate
@@ -2530,7 +2594,12 @@ def path_BFS(
None if there is no path
:rtype: (list of BaseVertex subclass, float) or None
- Returns a list of vertices that form a path from vertex ``S`` to
+ Compute a path from vertex ``S`` to vertex ``G`` using breadth-first search. The
+ path is guaranteed to be the shortest in terms of number of edges, but not
+ necessarily the cheapest in terms of edge costs. This search is not suited
+ to graphs with edge weights, and is inefficient in that it explores all vertices.
+
+ Returns a list of vertices that starts with vertex ``S`` and ends with
vertex ``G`` if possible, otherwise returns None -- so check the
result before unpacking it.
@@ -2634,7 +2703,10 @@ def path_UCS(
search tree, or None if there is no path
:rtype: (list of BaseVertex subclass, float, dict) or None
- Returns a list of vertices that form a path from vertex ``S`` to
+ Compute the lowest-cost path from vertex ``S`` to vertex ``G`` using uniform cost search. The
+ path is guaranteed to be the shortest in terms of traversed edge cost, but is inefficient in that it explores all vertices.
+
+ Returns a list of vertices that starts with vertex ``S`` and ends with
vertex ``G`` if possible, otherwise returns None -- so check the
result before unpacking it.
@@ -2756,7 +2828,11 @@ def path_Astar(
search tree, or None if there is no path
:rtype: (list of BaseVertex subclass, float, dict) or None
- Returns a list of vertices that form a path from vertex ``S`` to
+ Compute the lowest-cost path from vertex ``S`` to vertex ``G`` using A*t search. The
+ path is guaranteed to be the shortest in terms of traversed edge cost, and the search is efficient in
+ terms of the number of vertices explored.
+
+ Returns a list of vertices that starts with vertex ``S`` and ends with
vertex ``G`` if possible, otherwise returns None -- so check the
result before unpacking it.
@@ -3676,7 +3752,7 @@ def connect(
vertices must agree with them: in either order if undirected,
exactly ``self`` then ``dest`` if directed.
- Both vertices must already have been added to the same graph,
- e.g. via :meth:`PGraph.add_vertex` -- since a graph only ever
+ e.g. via :meth:`BaseGraph.add_vertex` -- since a graph only ever
accepts its own vertex subclass (see :meth:`UGraph.add_vertex`,
:meth:`DGraph.add_vertex`), this also rules out connecting a
``UVertex`` to a ``DVertex``.
@@ -3825,21 +3901,20 @@ def edgeto(self, dest: BaseVertex) -> Edge:
def edges(self) -> list[Edge]:
"""
- All outgoing edges of vertex
-
- :return: List of all edges leaving this vertex
- :rtype: list of Edge
+ Return a list of the edges for vertex
- The edges are in the order they were connected. This is a new list,
- so it can be modified, and edges can be removed from the graph while
- iterating over it.
+ :return: the edges at this vertex
+ :rtype: list of ``Edge``
- .. note::
+ For a directed graph these are the edges leaving this vertex. For an
+ undirected graph they are the edges incident on it, whichever end it
+ is. A self-loop in an undirected graph is listed twice, once for each
+ end.
- - For a directed graph the edges are those leaving this vertex
- - For a non-directed graph the edges are those leaving or entering
- this vertex, and a self-loop is listed twice, once for each of
- its ends
+ The list is a new one on every call, in the order the edges were
+ connected, so changing it does not change the graph, and edges can be
+ removed from the graph while iterating over it. Use
+ :meth:`BaseGraph.remove_edge` to remove one.
.. runblock:: pycon
@@ -4193,7 +4268,7 @@ def z(self) -> float:
def closest(self) -> tuple[BaseVertex | None, float]:
"""
- BaseVertex closest to this vertex
+ Return the closest vertex to this vertex
:return: closest vertex and its distance
:rtype: BaseVertex subclass or None, float