diff --git a/src/pyplaml/diagram.py b/src/pyplaml/diagram.py
index 81cf1ba83e2096884b9cb0885b73e14ecf15fe20..658cb481a985e76550d0e1345705186c86fe2759 100644
--- a/src/pyplaml/diagram.py
+++ b/src/pyplaml/diagram.py
@@ -6,6 +6,11 @@ from .diagram_object import DiagramObject
 
 
 class Diagram(VGroup):
+    """Container for diagram objects.
+
+    Objects with duplicate names are merged into one,
+    merging can be defined in method append_to_diagram in any DiagramObject.
+    """
 
     def __init__(self, layout: DiagramLayout | None = None, **kwargs):
         super().__init__(**kwargs)
@@ -14,9 +19,13 @@ class Diagram(VGroup):
         self.tagged: typing.Dict[str, set[DiagramObject]] = {}
         self.last_object: DiagramObject | None = None
 
+        self.__layout_scale_x = 1
+        self.__layout_scale_y = 1
+
         self.do_show_icons = True
 
     def add(self, *vmobjects: DiagramObject):
+        """Adds objects to diagram. Checks duplicate names and merges them."""
         for o in vmobjects:
             exists = o.get_key() in self.objects
             o = o.append_to_diagram(self)
@@ -27,7 +36,11 @@ class Diagram(VGroup):
                 super().add(o)
 
     def apply_layout(self, scale_x: float = 1, scale_y: float = 1):
+        """Applies provided layout. Edges are automatically redrawn, to match new DiagramObjects positions."""
         if self.layout is not None:
+            self.__layout_scale_x = scale_x
+            self.__layout_scale_y = scale_y
+
             positions = self.layout.apply(
                 {k: v for k, v in self.objects.items() if
                  isinstance(v, pyplaml.DiagramClass | pyplaml.DiagramNote) and v.do_draw},
@@ -42,24 +55,26 @@ class Diagram(VGroup):
                 for e in self[name].edges:
                     e.redraw()
 
-    def objects_degree(self):
+    def objects_by_degree(self):
+        """Returns dictionary of objects where key is their key and value their degree."""
         degrees = {}
-        for n, o in self.objects.items():
+        for _, o in self.objects.items():
             if hasattr(o, "edges"):
-                if n in degrees:
-                    degrees[n] += len(o.edges)
+                if o.get_key() in degrees:
+                    degrees[o.get_key()] += len(o.edges)
                 else:
-                    degrees[n] = len(o.edges)
+                    degrees[o.get_key()] = len(o.edges)
 
                 for e in o.edges:
-                    if e.target.name in degrees:
-                        degrees[e.target.name] += 1
+                    if e.target.get_key() in degrees:
+                        degrees[e.target.get_key()] += 1
                     else:
-                        degrees[e.target.name] = 1
+                        degrees[e.target.get_key()] = 1
 
         return degrees
 
     def add_to_tagged(self, tag: str, obj: DiagramObject):
+        """Adds object to specified tag. Objects can be later hidden/removed/shown by their tags."""
         if tag in self.tagged:
             self.tagged[tag].add(obj)
         else:
@@ -67,57 +82,83 @@ class Diagram(VGroup):
             self.tagged[tag].add(obj)
 
     def remove_by_tag(self, tag: str):
+        """Removes all objects with specified tag from diagram. Removed objects are invisible and don't matter in diagram layout."""
         if tag in self.tagged:
             for o in self.tagged[tag]:
-                o.do_draw = False
-                o.set_opacity(0)
+                self.remove_object(o.get_key())
 
     def restore_by_tag(self, tag: str):
+        """Restores all previously removed objects by tag."""
         if tag in self.tagged:
             for o in self.tagged[tag]:
-                o.do_draw = True
-                o.set_opacity(1)
+                self.restore_object(o.get_key())
 
     def hide_by_tag(self, tag: str):
+        """Hides objects by tag. Hidden objects are invisible, but still matter in diagram layout."""
         if tag in self.tagged:
             for o in self.tagged[tag]:
-                o.is_hidden = True
-                o.set_opacity(0)
+                self.hide_object(o.get_key())
 
     def show_by_tag(self, tag: str):
+        """Shows previously hidden objects by tag."""
         if tag in self.tagged:
             for o in self.tagged[tag]:
-                o.is_hidden = False
-                o.set_opacity(1)
+                self.show_object(o.get_key())
 
     def show_icons(self, show: bool):
+        """Sets if icons of DiagramClass objects should be drawn."""
         self.do_show_icons = show
         for n, o in self.objects.items():
             if isinstance(o, pyplaml.DiagramClass):
                 o.set_show_icon(show)
 
     def remove_unlinked(self):
-        for n, deg in self.objects_degree().items():
-            if deg == 0:
-                self[n].do_draw = False
-                self[n].set_opacity(0)
+        """Removes all objects with no inbound/outbound DiagramEdges. Removed objects are invisible and don't matter in diagram layout."""
+        objects = self.objects_by_degree()
+        if objects:
+            for n, deg in objects.items():
+                if deg == 0:
+                    self.remove_object(n)
 
     def restore_unlinked(self):
-        for n, deg in self.objects_degree().items():
-            if deg == 0:
-                self[n].do_draw = True
-                self[n].set_opacity(1)
+        """Restores all objects with no inbound/outbound DiagramEdges."""
+        objects = self.objects_by_degree()
+        if objects:
+            for n, deg in objects.items():
+                if deg == 0:
+                    self.restore_object(n)
 
     def hide_unlinked(self):
-        print(self.objects_degree())
-        for n, deg in self.objects_degree().items():
+        """Hides all objects with no inbound/outbound DiagramEdges. Hidden objects are invisible, but still matter in diagram layout."""
+        for n, deg in self.objects_by_degree().items():
             if deg == 0:
-                self[n].set_opacity(0)
+                self.hide_object(n)
 
     def show_unlinked(self):
-        for n, deg in self.objects_degree().items():
+        """Shows all objects with no inbound/outbound DiagramEdges."""
+        for n, deg in self.objects_by_degree().items():
             if deg == 0:
-                self[n].set_opacity(1)
+                self.show_object(n)
+
+    def hide_object(self, key: str):
+        """Hides an object, object still matters in diagram layout."""
+        self[key].set_opacity(0)
+
+    def show_object(self, key: str):
+        """Shows previously hidden object"""
+        self[key].set_opacity(1)
+
+    def remove_object(self, key: str):
+        """Removes an object, object no longer matters in diagram layout."""
+        self[key].do_draw = False
+        self[key].set_opacity(0)
+        self.remove(self[key])
+
+    def restore_object(self, key: str):
+        """Restores previously removed object"""
+        self[key].do_draw = True
+        self[key].set_opacity(1)
+        self.add(self.objects.pop(key))
 
     def __setitem__(self, key: str, val: DiagramObject):
         if not isinstance(val, DiagramObject):
diff --git a/src/pyplaml/diagram_edge.py b/src/pyplaml/diagram_edge.py
index afec5c758705976a646974e5a843671dd31df871..825491670c6277335980eb735a8670d525dc5e55 100644
--- a/src/pyplaml/diagram_edge.py
+++ b/src/pyplaml/diagram_edge.py
@@ -60,7 +60,7 @@ class DiagramEdge(DiagramObject):
     def redraw(self):
         super().redraw()
 
-        if self.source.is_hidden or self.target.is_hidden:
+        if self.source.background_stroke_opacity or self.target.background_stroke_opacity:
             return
 
         always_redraw(self.__line_updater)
diff --git a/src/pyplaml/diagram_object.py b/src/pyplaml/diagram_object.py
index 84ed981d85c126865b04ee16c7b6bb2dd77a892e..0e1038a6fffcbbf81a324ba1f993261856863790 100644
--- a/src/pyplaml/diagram_object.py
+++ b/src/pyplaml/diagram_object.py
@@ -16,7 +16,6 @@ class DiagramObject(VGroup):
         super().__init__(**kwargs)
         self.name = name
         self.alias = None
-        self.is_hidden = False
         self.do_draw = True
         self.notes: Dict[pyplaml.Direction, List[pyplaml.DiagramNote]] = {}
 
@@ -73,9 +72,8 @@ class DiagramObject(VGroup):
         return self.name
 
     def __repr__(self):
-        return "({}) \"{}\", hidden: {}, draw: {}".format(
+        return "({}) \"{}\", draw: {}".format(
             self.__class__.__name__,
             self.get_key() or "NAME NOT SET",
-            "yes" if self.is_hidden else "no",
             "yes" if self.do_draw else "no",
         )
diff --git a/src/pyplaml/puml_parser.py b/src/pyplaml/puml_parser.py
index 2effa7f1bb8fa167bba573278841bf67e4a016a6..0b052dab7783ea131a3e0b8b38acec41e91eb4d6 100644
--- a/src/pyplaml/puml_parser.py
+++ b/src/pyplaml/puml_parser.py
@@ -289,11 +289,8 @@ class PUMLParser(object):
         if p[2][0] == "@":
             if p[2] == "@unlinked":
                 self.diagram.remove_unlinked()
-
             return
-
-        self.diagram[p[2]].do_draw = False
-        self.diagram[p[2]].set_opacity(0)
+        self.diagram.remove_object(self.diagram[p[2]])
 
     def p_remove_by_tag(self, p):
         """
@@ -308,11 +305,8 @@ class PUMLParser(object):
         if p[2][0] == "@":
             if p[2] == "@unlinked":
                 self.diagram.restore_unlinked()
-
             return
-
-        self.diagram[p[2]].do_draw = True
-        self.diagram[p[2]].set_opacity(1)
+        self.diagram.restore_object(self.diagram[p[2]].get_key())
 
     def p_restore_by_tag(self, p):
         """
@@ -332,8 +326,7 @@ class PUMLParser(object):
         elif name == "circle":
             self.diagram.show_icons(False)
         else:
-            self.diagram[name].is_hidden = True
-            self.diagram[name].set_opacity(0)
+            self.diagram.hide_object(self.diagram[name])
 
     def p_hide_by_tag(self, p):
         """
@@ -353,8 +346,7 @@ class PUMLParser(object):
         elif name == "circle":
             self.diagram.show_icons(True)
         else:
-            self.diagram[p[2]].is_hidden = False
-            self.diagram[p[2]].set_opacity(1)
+            self.diagram.show_object(self.diagram[p[2]])
 
     def p_show_by_tag(self, p):
         """