Skip to content

Commit 2b2eb53

Browse files
committed
Add interactive Jupyter summary for EnzymeML docs
Introduces pyenzyme/widgets.py to provide interactive document summaries in Jupyter notebooks using ipywidgets. Updates pretty.py to use widgets for notebook environments and refactors terminal summary logic for improved separation and clarity.
1 parent 46f6e31 commit 2b2eb53

2 files changed

Lines changed: 438 additions & 47 deletions

File tree

pyenzyme/pretty.py

Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,46 @@
1-
"""
2-
EnzymeML Document Pretty Printing Utilities
3-
4-
This module provides functions to create visually appealing summaries
5-
of EnzymeML documents using rich formatting.
6-
"""
7-
1+
from typing import TYPE_CHECKING
82
from rich.console import Console
93
from rich.panel import Panel
104
from rich.table import Table
115
from rich.columns import Columns
12-
from typing import TYPE_CHECKING
136

147
if TYPE_CHECKING:
158
from pyenzyme.versions.v2 import EnzymeMLDocument
169

1710

18-
def summary(doc: "EnzymeMLDocument", console: Console | None = None) -> None:
11+
def summary(
12+
doc: "EnzymeMLDocument",
13+
console: Console | None = None,
14+
interactive: bool = True,
15+
) -> None:
1916
"""
2017
Create a comprehensive visual summary of an EnzymeML document.
2118
19+
In Jupyter notebooks, creates interactive widgets with dropdowns and selection.
20+
In terminal, creates rich formatted tables and panels.
21+
2222
Args:
2323
doc: EnzymeMLDocument to summarize
24-
console: Rich console instance (creates new one if None)
24+
console: Rich console instance (creates new one if None) - only used for terminal
25+
interactive: Whether to create interactive widgets in Jupyter notebooks
2526
"""
27+
try:
28+
from . import widgets
29+
30+
if widgets._is_notebook() and interactive:
31+
widgets.create_interactive_summary(doc)
32+
return
33+
except ImportError:
34+
pass
35+
36+
# Fall back to terminal summary
37+
_create_terminal_summary(doc, console)
38+
39+
40+
def _create_terminal_summary(
41+
doc: "EnzymeMLDocument", console: Console | None = None
42+
) -> None:
43+
"""Create terminal summary using rich formatting."""
2644
if console is None:
2745
console = Console()
2846

@@ -60,21 +78,14 @@ def summary(doc: "EnzymeMLDocument", console: Console | None = None) -> None:
6078
spaced_content = []
6179
for i, content in enumerate(content_panels):
6280
spaced_content.append(content)
63-
if i < len(content_panels) - 1: # Don't add space after last item
64-
spaced_content.append("") # Empty string for spacing
81+
if i < len(content_panels) - 1:
82+
spaced_content.append("")
6583

66-
# Combine all content into a single container panel
67-
content_group = Group(*spaced_content)
84+
# Print title and content separately
85+
console.print("📋 [bold blue]EnzymeML Document Summary[/bold blue]")
6886

69-
container_panel = Panel(
70-
content_group,
71-
title="📋 EnzymeML Document Summary",
72-
title_align="left",
73-
border_style="bold blue",
74-
padding=(1, 2),
75-
)
76-
77-
console.print(container_panel)
87+
content_group = Group(*spaced_content)
88+
console.print(content_group)
7889

7990

8091
def _create_overview_panel(doc: "EnzymeMLDocument") -> Panel:
@@ -116,8 +127,8 @@ def _create_counts_table(doc: "EnzymeMLDocument") -> Table:
116127
counts_table = Table(
117128
title="📊 Component Counts", show_header=True, header_style="bold magenta"
118129
)
119-
counts_table.add_column("Component", style="cyan", no_wrap=True)
120-
counts_table.add_column("Count", justify="right", style="yellow")
130+
counts_table.add_column("Component", no_wrap=True)
131+
counts_table.add_column("Count", justify="right")
121132

122133
# Add all component counts
123134
component_counts = [
@@ -142,10 +153,10 @@ def _create_species_table(doc: "EnzymeMLDocument") -> Table:
142153
species_table = Table(
143154
title="🧬 Species Details", show_header=True, header_style="bold green"
144155
)
145-
species_table.add_column("Type", style="cyan", min_width=12)
156+
species_table.add_column("Type", min_width=12)
146157
species_table.add_column("ID", style="magenta", min_width=15)
147-
species_table.add_column("Name", style="white", min_width=20)
148-
species_table.add_column("Details", style="dim white")
158+
species_table.add_column("Name", min_width=20)
159+
species_table.add_column("Details")
149160

150161
_add_proteins_to_species_table(doc, species_table)
151162
_add_molecules_to_species_table(doc, species_table)
@@ -166,7 +177,10 @@ def _add_proteins_to_species_table(doc: "EnzymeMLDocument", table: Table) -> Non
166177
details.append(f"Vessel: {protein.vessel_id}")
167178

168179
table.add_row(
169-
"Protein", protein.id, protein.name, " | ".join(details) if details else "—"
180+
"Protein",
181+
f"[magenta]{protein.id}[/magenta]",
182+
protein.name,
183+
" | ".join(details) if details else "—",
170184
)
171185

172186
if len(doc.proteins) > 5:
@@ -184,7 +198,7 @@ def _add_molecules_to_species_table(doc: "EnzymeMLDocument", table: Table) -> No
184198

185199
table.add_row(
186200
"Small Molecule",
187-
molecule.id,
201+
f"[magenta]{molecule.id}[/magenta]",
188202
molecule.name,
189203
" | ".join(details) if details else "—",
190204
)
@@ -204,7 +218,7 @@ def _add_complexes_to_species_table(doc: "EnzymeMLDocument", table: Table) -> No
204218

205219
table.add_row(
206220
"Complex",
207-
complex_obj.id,
221+
f"[magenta]{complex_obj.id}[/magenta]",
208222
complex_obj.name,
209223
" | ".join(details) if details else "—",
210224
)
@@ -230,9 +244,9 @@ def _create_vessels_content(doc: "EnzymeMLDocument"):
230244
title="🧪 Vessels", show_header=True, header_style="bold yellow"
231245
)
232246
vessels_table.add_column("ID", style="magenta")
233-
vessels_table.add_column("Name", style="white")
234-
vessels_table.add_column("Volume", style="yellow")
235-
vessels_table.add_column("Constant", justify="center", style="green")
247+
vessels_table.add_column("Name")
248+
vessels_table.add_column("Volume")
249+
vessels_table.add_column("Constant", justify="center")
236250

237251
for vessel in doc.vessels:
238252
unit_str = vessel.unit.name if vessel.unit else "L"
@@ -252,9 +266,9 @@ def _create_reactions_content(doc: "EnzymeMLDocument"):
252266
title="⚡ Reactions", show_header=True, header_style="bold red"
253267
)
254268
reactions_table.add_column("ID", style="magenta", min_width=12)
255-
reactions_table.add_column("Name", style="white", min_width=20)
256-
reactions_table.add_column("Reversible", justify="center", style="yellow")
257-
reactions_table.add_column("Reaction Schema", style="dim white", min_width=30)
269+
reactions_table.add_column("Name", min_width=20)
270+
reactions_table.add_column("Reversible", justify="center")
271+
reactions_table.add_column("Reaction Schema", min_width=30)
258272

259273
for reaction in doc.reactions[:5]: # Limit to first 5
260274
schema = _format_reaction_schema(reaction)
@@ -316,9 +330,9 @@ def _create_measurements_content(doc: "EnzymeMLDocument"):
316330
title="📈 Measurements", show_header=True, header_style="bold cyan"
317331
)
318332
measurements_table.add_column("ID", style="magenta", min_width=12)
319-
measurements_table.add_column("Name", style="white", min_width=20)
320-
measurements_table.add_column("Species Data", justify="center", style="yellow")
321-
measurements_table.add_column("Conditions", style="dim white")
333+
measurements_table.add_column("Name", min_width=20)
334+
measurements_table.add_column("Species Data", justify="center")
335+
measurements_table.add_column("Conditions")
322336

323337
for measurement in doc.measurements[:5]: # Limit to first 5
324338
conditions = _format_measurement_conditions(measurement)
@@ -356,12 +370,12 @@ def _create_parameters_content(doc: "EnzymeMLDocument"):
356370
title="🔢 Parameters", show_header=True, header_style="bold purple"
357371
)
358372
parameters_table.add_column("Symbol", style="magenta")
359-
parameters_table.add_column("Name", style="white")
360-
parameters_table.add_column("Value", style="yellow")
361-
parameters_table.add_column("Initial Value", style="yellow")
362-
parameters_table.add_column("Bounds", style="yellow")
363-
parameters_table.add_column("Unit", style="cyan")
364-
parameters_table.add_column("Constant", justify="center", style="green")
373+
parameters_table.add_column("Name")
374+
parameters_table.add_column("Value")
375+
parameters_table.add_column("Initial Value")
376+
parameters_table.add_column("Bounds")
377+
parameters_table.add_column("Unit")
378+
parameters_table.add_column("Constant", justify="center")
365379

366380
for param in doc.parameters[:8]: # Limit to first 8
367381
# Pre-populate all data for the parameter
@@ -385,7 +399,6 @@ def _create_parameters_content(doc: "EnzymeMLDocument"):
385399
unit_str = param.unit.name if param.unit else "—"
386400
constant_str = "✓" if param.constant else "✗"
387401

388-
# Single add_row call with all columns properly populated
389402
parameters_table.add_row(
390403
symbol,
391404
name,

0 commit comments

Comments
 (0)