MindMap / generate_mindmap.py
raannakasturi's picture
Upload 4 files
1641226 verified
raw
history blame
4.52 kB
from graphviz import Digraph
import re
import random
def parse_markdown_to_dict(md_text):
lines = md_text.strip().splitlines()
mindmap = {}
stack = []
for line in lines:
heading_match = re.match(r'^(#{1,6})\s+(.*)', line)
bullet_match = re.match(r'^\s*-\s+(.*)', line)
if heading_match:
level = len(heading_match.group(1))
title = heading_match.group(2).strip()
node = {'title': title, 'children': []}
while len(stack) >= level:
stack.pop()
if stack:
stack[-1]['children'].append(node)
else:
mindmap = node
stack.append(node)
elif bullet_match and stack:
stack[-1]['children'].append({'title': bullet_match.group(1), 'children': []})
return mindmap
generated_colors = set()
def generate_random_color():
"""Generate a random color that hasn't been generated before."""
while True:
# Generate a random color in hex format
color = "#{:02x}{:02x}{:02x}".format(random.randint(128, 255), random.randint(128, 255), random.randint(128, 255))
# If the color is not in the set, it's unique
if color not in generated_colors:
generated_colors.add(color) # Add the color to the set of generated colors
return color # Return the unique color
else:
continue # Try again
def brighten_color(color, factor=0.15):
"""Brighten the color by a certain factor (default 10%)"""
# Remove the '#' symbol
color = color.lstrip('#')
# Convert hex to RGB
r, g, b = [int(color[i:i+2], 16) for i in (0, 2, 4)]
# Increase each component by the factor, but clamp to 255
r = min(255, int(r * (1 + factor)))
g = min(255, int(g * (1 + factor)))
b = min(255, int(b * (1 + factor)))
# Convert back to hex
return "#{:02x}{:02x}{:02x}".format(r, g, b)
def add_nodes_to_graph(graph, node, parent_id=None, font_size=9, parent_color=None):
node_id = str(id(node))
title = node['title']
if parent_color is None:
node_color = "#ADD8E6" # Light Blue for the main heading
border_color = "#000000" # Dark Blue border for the main heading
parent_color = "#ADD8E6"
elif parent_color == "#ADD8E6":
node_color = generate_random_color()
border_color = "#808080"
parent_color = node_color
else:
# Child node and its descendants with the same random color
node_color = brighten_color(parent_color, factor=0.15)
border_color = "#808080"
# Check for markdown links
url_match = re.search(r'\[(.*?)\]\((.*?)\)', title)
if url_match:
prefix_text = title[:url_match.start()].strip()
display_text = url_match.group(1)
url = url_match.group(2)
label = f'{prefix_text} {display_text}'
graph.node(node_id, label=label, shape="box", style="rounded,filled", color=border_color, fontcolor="black", fillcolor=node_color, href=url, tooltip=title, fontsize=str(font_size))
else:
graph.node(node_id, title, shape="box", style="rounded,filled", color=border_color, fontcolor="black", fillcolor=node_color, tooltip=title, fontsize=str(font_size))
if parent_id:
graph.edge(parent_id, node_id)
# Recurse to children, passing down color for the child and its descendants
for child in node.get('children', []):
# Assign a random color to each child node (no inheritance from parent)
add_nodes_to_graph(graph, child, node_id, font_size=max(8, font_size - 1), parent_color=parent_color)
def generate_mindmap_svg(md_text):
mindmap_dict = parse_markdown_to_dict(md_text)
root_title = mindmap_dict.get('title', 'Mindmap')
sanitized_title = re.sub(r'[^a-zA-Z0-9_\-]', '', root_title.replace(" ", ""))
if output_filename is None:
output_filename = sanitized_title
graph = Digraph(format='svg')
graph.attr(rankdir='LR', size='10,10!', pad="0.5", margin="0.2", ratio="auto")
graph.attr('node', fontname="Arial", fontsize="9")
add_nodes_to_graph(graph, mindmap_dict)
svg_content = graph.pipe(format='svg').decode('utf-8')
# Replace %3 with the sanitized filename in the SVG content
svg_content = svg_content.replace("%3", root_title)
# Save the modified SVG content to a file
with open(f'{output_filename}.svg', 'w') as f:
f.write(svg_content)
return f"{output_filename}".svg