Repository: networkx/networkx

Issue:
Getting shape types from GraphML written by yEd
<!-- If you have a general question about NetworkX, please use the discussions tab to create a new discussion -->

<!--- Provide a general summary of the issue in the Title above -->


### Current Behavior
<!--- Tell us what happens instead of the expected behavior -->
I have a GraphML file, written by [yEd](https://www.yworks.com/products/yed). NetworkX reads it just fine with `read_graphml()`, however, one very important information is missing: the type of the nodes (eg. `diamond`, `roundrectangle` etc).

### Expected Behavior
<!--- Tell us what should happen -->
I would except to be able to get that information, because it's necessary for processing and understanding the exported graph.

### Steps to Reproduce
<!--- Provide a minimal example that reproduces the bug -->
Create a graph with [yEd](https://www.yworks.com/products/yed) with various shapes. Export it to GraphML and load it back with NetworkX's `read_graphml()`. The shape types are not there.

### Environment
<!--- Please provide details about your local environment -->
Python version: 3.8.5
NetworkX version: 2.5


### Additional context
<!--- Add any other context about the problem here, screenshots, etc. -->
yEd exports the shape type in the XML like this:
```XML
    <node id="n1">
      <data key="d5" xml:space="preserve"><![CDATA[lfx="red"
bela="2"]]></data>
      <data key="d6">
        <y:ShapeNode>
          <y:Geometry height="93.0" width="93.0" x="133.0" y="509.90625"/>
          <y:Fill color="#FFCC00" transparent="false"/>
          <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="29.16015625" x="31.919921875" xml:space="preserve" y="37.515625">RED
             <y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel>
             <y:ModelParameter>
               <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
             </y:ModelParameter>
          </y:NodeLabel>
          <y:Shape type="roundrectangle"/>
        </y:ShapeNode>
      </data>
    </node>
```

Reference: [yEd documentation](https://docs.yworks.com/graphml/schema-doc/http___www.yworks.com_xml_graphml/simpleType/shapeType.type.html)


Discussion:

Resolving patch:
diff --git a/networkx/readwrite/graphml.py b/networkx/readwrite/graphml.py
--- a/networkx/readwrite/graphml.py
+++ b/networkx/readwrite/graphml.py
@@ -247,8 +247,8 @@ def read_graphml(path, node_type=str, edge_key_type=int, force_multigraph=False)
     there is no "key" attribute a default NetworkX multigraph edge key
     will be provided.
 
-    Files with the yEd "yfiles" extension will can be read but the graphics
-    information is discarded.
+    Files with the yEd "yfiles" extension can be read. The type of the node's
+    shape is preserved in the `shape_type` node attribute.
 
     yEd compressed files ("file.graphmlz" extension) can be read by renaming
     the file to "file.graphml.gz".
@@ -912,7 +912,11 @@ def decode_data_elements(self, graphml_keys, obj_xml):
             elif len(list(data_element)) > 0:
                 # Assume yfiles as subelements, try to extract node_label
                 node_label = None
-                for node_type in ["ShapeNode", "SVGNode", "ImageNode"]:
+                # set GenericNode's configuration as shape type
+                gn = data_element.find(f"{{{self.NS_Y}}}GenericNode")
+                if gn:
+                    data["shape_type"] = gn.get("configuration")
+                for node_type in ["GenericNode", "ShapeNode", "SVGNode", "ImageNode"]:
                     pref = f"{{{self.NS_Y}}}{node_type}/{{{self.NS_Y}}}"
                     geometry = data_element.find(f"{pref}Geometry")
                     if geometry is not None:
@@ -920,6 +924,9 @@ def decode_data_elements(self, graphml_keys, obj_xml):
                         data["y"] = geometry.get("y")
                     if node_label is None:
                         node_label = data_element.find(f"{pref}NodeLabel")
+                    shape = data_element.find(f"{pref}Shape")
+                    if shape is not None:
+                        data["shape_type"] = shape.get("type")
                 if node_label is not None:
                     data["label"] = node_label.text
 


Test patch:
diff --git a/networkx/readwrite/tests/test_graphml.py b/networkx/readwrite/tests/test_graphml.py
--- a/networkx/readwrite/tests/test_graphml.py
+++ b/networkx/readwrite/tests/test_graphml.py
@@ -604,6 +604,29 @@ def test_yfiles_extension(self):
         </y:ShapeNode>
       </data>
     </node>
+    <node id="n2">
+      <data key="d6" xml:space="preserve"><![CDATA[description
+line1
+line2]]></data>
+      <data key="d3">
+        <y:GenericNode configuration="com.yworks.flowchart.terminator">
+          <y:Geometry height="40.0" width="80.0" x="950.0" y="286.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content"
+          fontFamily="Dialog" fontSize="12" fontStyle="plain"
+          hasBackgroundColor="false" hasLineColor="false" height="17.96875"
+          horizontalTextPosition="center" iconTextGap="4" modelName="custom"
+          textColor="#000000" verticalTextPosition="bottom" visible="true"
+          width="67.984375" x="6.0078125" xml:space="preserve"
+          y="11.015625">3<y:LabelModel>
+          <y:SmartNodeLabelModel distance="4.0"/></y:LabelModel>
+          <y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0"
+          labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0"
+          offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
     <edge id="e0" source="n0" target="n1">
       <data key="d7">
         <y:PolyLineEdge>
@@ -626,24 +649,36 @@ def test_yfiles_extension(self):
         assert G.has_edge("n0", "n1", key="e0")
         assert G.nodes["n0"]["label"] == "1"
         assert G.nodes["n1"]["label"] == "2"
+        assert G.nodes["n2"]["label"] == "3"
+        assert G.nodes["n0"]["shape_type"] == "rectangle"
+        assert G.nodes["n1"]["shape_type"] == "rectangle"
+        assert G.nodes["n2"]["shape_type"] == "com.yworks.flowchart.terminator"
+        assert G.nodes["n2"]["description"] == "description\nline1\nline2"
         fh.seek(0)
         G = nx.read_graphml(fh)
         assert list(G.edges()) == [("n0", "n1")]
         assert G["n0"]["n1"]["id"] == "e0"
         assert G.nodes["n0"]["label"] == "1"
         assert G.nodes["n1"]["label"] == "2"
+        assert G.nodes["n2"]["label"] == "3"
+        assert G.nodes["n0"]["shape_type"] == "rectangle"
+        assert G.nodes["n1"]["shape_type"] == "rectangle"
+        assert G.nodes["n2"]["shape_type"] == "com.yworks.flowchart.terminator"
+        assert G.nodes["n2"]["description"] == "description\nline1\nline2"
 
         H = nx.parse_graphml(data, force_multigraph=True)
         assert list(H.edges()) == [("n0", "n1")]
         assert H.has_edge("n0", "n1", key="e0")
         assert H.nodes["n0"]["label"] == "1"
         assert H.nodes["n1"]["label"] == "2"
+        assert H.nodes["n2"]["label"] == "3"
 
         H = nx.parse_graphml(data)
         assert list(H.edges()) == [("n0", "n1")]
         assert H["n0"]["n1"]["id"] == "e0"
         assert H.nodes["n0"]["label"] == "1"
         assert H.nodes["n1"]["label"] == "2"
+        assert H.nodes["n2"]["label"] == "3"
 
     def test_bool(self):
         s = """<?xml version="1.0" encoding="UTF-8"?>