diff --git a/docs/examples/client_example.ipynb b/docs/examples/client_example.ipynb index d45f1fb..d7cb2ba 100644 --- a/docs/examples/client_example.ipynb +++ b/docs/examples/client_example.ipynb @@ -1497,6 +1497,120 @@ "client.get_item(item_id=\"NMC811_e1_c1\", load_blocks=True, display=True);" ] }, + { + "cell_type": "markdown", + "id": "0683d0d5-c0b9-43bc-b02b-9b1add502c1e", + "metadata": {}, + "source": [ + "## Exploring relationships between items" + ] + }, + { + "cell_type": "markdown", + "id": "241be170-44e3-4ff5-a477-f7c992379fb7", + "metadata": {}, + "source": [ + "Items in *datalab* can be linked together, e.g., a cell may be made from several samples, which in turn were synthesised from starting materials.\n", + "The graph of these relationships can be retrieved with `get_item_graph`, either for all items you can see, or centred on a particular item.\n", + "\n", + "With `as_networkx=True`, the graph is returned as a [`networkx.DiGraph`](https://networkx.org/documentation/stable/reference/classes/digraph.html), with edges pointing from parent to child.\n", + "This requires the optional `networkx` dependency (`pip install datalab-api[networkx]`); we will also use `matplotlib` to draw the graph below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10918dcc-53bf-497f-a40f-7b78d84e03f6", + "metadata": {}, + "outputs": [], + "source": [ + "graph = client.get_item_graph(item_id=\"NMC811_e1\", max_depth=2, as_networkx=True)\n", + "print(f\"{graph.number_of_nodes()} items, {graph.number_of_edges()} relationships\")" + ] + }, + { + "cell_type": "markdown", + "id": "81e1c738-74d3-4c1a-ada2-f023c23f98b2", + "metadata": {}, + "source": [ + "Each node is keyed by its item ID, with the rest of the item summary (e.g., `name` and `type`) stored as node attributes:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b86b0122-2a5d-4242-b8a5-7d6118de74db", + "metadata": {}, + "outputs": [], + "source": [ + "for item_id, data in graph.nodes(data=True):\n", + " print(f\"{item_id:<30} {data.get('type', ''):<20} {data.get('name', '')}\")" + ] + }, + { + "cell_type": "markdown", + "id": "33102cef-4b72-46d0-8576-c4cd21b46b03", + "metadata": {}, + "source": [ + "The graph can then be analysed or visualised with any of the usual `networkx` tools, for example, colouring each item by its type:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2dd36755-0ac3-4711-8820-230c0242a147", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import networkx as nx\n", + "\n", + "type_colours = {\n", + " \"samples\": \"tab:blue\",\n", + " \"starting_materials\": \"tab:green\",\n", + " \"cells\": \"tab:orange\",\n", + " \"equipment\": \"tab:purple\",\n", + "}\n", + "node_colours = [\n", + " type_colours.get(data.get(\"type\"), \"tab:gray\") for _, data in graph.nodes(data=True)\n", + "]\n", + "\n", + "fig, ax = plt.subplots(figsize=(10, 8))\n", + "pos = nx.spring_layout(graph, seed=42)\n", + "nx.draw_networkx(\n", + " graph,\n", + " pos=pos,\n", + " ax=ax,\n", + " node_color=node_colours,\n", + " node_size=800,\n", + " font_size=8,\n", + " arrowsize=15,\n", + ")\n", + "for item_type, colour in type_colours.items():\n", + " ax.scatter([], [], color=colour, label=item_type)\n", + "ax.legend(loc=\"best\")\n", + "ax.axis(\"off\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "a10a9032-8299-43c9-9eca-79bc4421fe18", + "metadata": {}, + "source": [ + "Standard graph algorithms can also be used to answer questions about your items, for example, finding everything that went into making a given item:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "04e9f79b-8c07-4778-b2ed-dd82aa735cc4", + "metadata": {}, + "outputs": [], + "source": [ + "nx.ancestors(graph, \"NMC811_e1\")" + ] + }, { "cell_type": "markdown", "id": "243e941b-c465-4395-94f8-e8db441aece2",