Graphing hierarchical data without overlapping nodes

42 Views Asked by At

I have a dataset of a bunch of books in the following JSON format:

{
   "Book1":{
      "BookName":"Book1",
      "Author":"author",
      "YearPublished":2000,
      "commentaries":[
         "Book2",
         "Book3"
      ]
   },
   "Book2":{
      "BookName":"Book2",
      "Author":"author",
      "YearPublished":2020,
      "commentaries":[
         "Book4",
         "Book5"
      ]
   }
}

I am trying to graph the data to display the name and author of every book, as well as the relationships between each book and its commentaries. The books should also be positioned so that y_pos is equal to the year published. X_pos doesn't matter, but ideally, I'd like common commentaries to be grouped.

I have tried using multiple libraries (including Graphviz, Matplotlib, Networkx, and Draw.IO), but cannot seem to get everything positioned properly. Either the nodes overlap, or the graph doesn't render without messing with the y position too.

Below is the best working code I have so far:

import networkx as nx
import matplotlib.pyplot as plt
import json

# Load JSON data
with open('book_database.json', 'r') as file:
    data = json.load(file)


# Create a directed graph
G = nx.DiGraph()

# Add nodes (books and commentaries)
for book_id, book_data in data.items():
    G.add_node(
        book_id,
        label=f"{book_data['BookName']} by {book_data['BookAuthor']}",
        year_published=book_data['BookYear']  # Adding year_published attribute
    )
    for commentary_id in book_data['commentaries']:
        if str(commentary_id) in data:
            G.add_node(commentary_id, label=f"Commentary ID: {commentary_id}")
            G.add_edge(book_id, str(commentary_id))

# Use a layout algorithm to position nodes without overlap
pos = nx.multipartite_layout(G, subset_key="year_published", align="horizontal")

# Draw the graph with labels
plt.figure(figsize=(10, 8))
nx.draw(G, pos, with_labels=True, labels=nx.get_node_attributes(G, 'label'), node_size=500, font_size=10)
plt.show()

I would appreciate any solution to this - either in python or javascript please.

Thank you

0

There are 0 best solutions below