Skip to content

Instantly share code, notes, and snippets.

@bdbai
Created March 18, 2026 09:42
Show Gist options
  • Select an option

  • Save bdbai/deadeb6932257b26d2c39f1b44208eb3 to your computer and use it in GitHub Desktop.

Select an option

Save bdbai/deadeb6932257b26d2c39f1b44208eb3 to your computer and use it in GitHub Desktop.
pretty print json in jupyter notebook
#!/usr/bin/env python
# filepath: .\python_notebooks\util\html_display.py
"""
HTML display utilities for rendering Python objects as interactive HTML
Inspired by dotnet interactive's HtmlFormatter
"""
import json
from typing import Any, Dict, List, Union, Optional
import pandas as pd
from IPython.display import HTML, display
from html import escape
# CSS styles for the HTML output
DEFAULT_STYLES = """
<style>
.dni-code-hint {
font-style: italic;
overflow: hidden;
white-space: nowrap;
color: firebrick;
background: rgba(0, 0, 0, 0.1);
}
.dni-treeview {
white-space: nowrap;
}
.dni-treeview td {
vertical-align: top;
text-align: start;
}
details.dni-treeview {
padding-left: 1em;
}
table td {
text-align: start;
}
table tr {
vertical-align: top;
margin: 0em 0px;
}
table tr td pre {
vertical-align: top !important;
margin: 0em 0px !important;
}
table th {
text-align: start;
}
.dni-plaintext {
margin: 5px 10px;
padding: 5px;
border-radius: 3px;
background-color: #f5f5f5;
}
</style>
"""
def dict_to_html_table(data: Dict) -> str:
"""Convert a dictionary to an HTML table"""
if not data:
return "<i>Empty dictionary</i>"
rows = []
for key, value in data.items():
formatted_value = format_value_to_html(value)
rows.append(f"<tr><td><strong>{key}</strong></td><td>{formatted_value}</td></tr>")
return f"<table>{''.join(rows)}</table>"
def list_to_html_table(data: List) -> str:
"""Convert a list to an HTML table"""
if not data:
return "<i>Empty list</i>"
rows = []
for i, value in enumerate(data):
formatted_value = format_value_to_html(value)
rows.append(f"<tr><td>{i}</td><td>{formatted_value}</td></tr>")
return f"<table>{''.join(rows)}</table>"
def format_value_to_html(value: Any) -> str:
"""Format a value to HTML based on its type"""
if value is None:
return "<span style='color: #888'>&lt;null&gt;</span>"
elif isinstance(value, (dict, list)) and not value:
return "<span style='color: #888'>empty</span>"
elif isinstance(value, dict):
# Show the full JSON object similar to dotnet interactive
json_str = json.dumps(value, separators=(',', ':'))
return f"""
<details class="dni-treeview">
<summary><span class="dni-code-hint">{escape(json_str)}</span></summary>
<div>{dict_to_html_table(value)}</div>
</details>
"""
elif isinstance(value, list):
if not value:
return "[]"
# Show full array content similar to dotnet interactive
json_str = json.dumps(value, separators=(',', ':'))
return f"""
<details class="dni-treeview">
<summary><span class="dni-code-hint">{escape(json_str)}</span></summary>
<div>{list_to_html_table(value)}</div>
</details>
"""
elif isinstance(value, str):
if len(value) > 100:
return f"<span>'{escape(value[:100])}...'</span>"
return f"<span>'{escape(value)}'</span>"
elif isinstance(value, (int, float, bool)):
return f"<span>{value}</span>"
else:
return f"<span>{str(value)}</span>"
def json_to_html(data: Union[Dict, List, Any]) -> str:
"""
Convert JSON data to interactive HTML with expandable sections
Args:
data: The data to convert to HTML
Returns:
HTML string representation of the data
"""
html = DEFAULT_STYLES
html += "<div class='dni-treeview-root'>"
if isinstance(data, dict):
html += dict_to_html_table(data)
elif isinstance(data, list):
html += list_to_html_table(data)
else:
html += f"<pre class='dni-plaintext'>{escape(json.dumps(data, indent=2))}</pre>"
html += "</div>"
return html
def display_as_html(data: Any) -> None:
"""
Display data as interactive HTML in a Jupyter notebook
Args:
data: The data to display
"""
display(HTML(json_to_html(data)))
def dataframe_with_json_explorer(df: pd.DataFrame) -> pd.DataFrame:
"""
Add an 'Explore' button to complex JSON columns in a DataFrame
Args:
df: The DataFrame to enhance
Returns:
Enhanced DataFrame with exploration buttons
"""
def _add_explorer_buttons(df):
df_copy = df.copy()
for col in df.columns:
# Check the first non-null value
non_null = df[col].dropna()
if len(non_null) == 0:
continue
sample = non_null.iloc[0]
# Check if column contains complex structures
if isinstance(sample, (dict, list)) or str(sample).startswith('{') or str(sample).startswith('['):
# Create exploration buttons for this column
def make_button(val):
if pd.isna(val):
return val
try:
if isinstance(val, str) and (val.startswith('{') or val.startswith('[')):
val = json.loads(val)
button_id = f"btn_{hash(str(val))}"
return f"""
<button onclick="
$('#{button_id}').toggle();
$(this).text($(this).text() == 'Explore' ? 'Hide' : 'Explore');
">Explore</button>
<div id="{button_id}" style="display: none;">
{format_value_to_html(val)}
</div>
"""
except:
return val
# Apply button creation to each value in the column
df_copy[col] = df_copy[col].apply(make_button)
return df_copy
# For Jupyter notebook, we need to ensure HTML is properly displayed
pd.set_option('display.max_colwidth', None)
# Return DataFrame with HTML formatting applied
return _add_explorer_buttons(df)
def auto_html_display(data: Any) -> Any:
"""
Automatically display data in the best format
Args:
data: The data to display
Returns:
Appropriate HTML visualization or DataFrame
"""
if isinstance(data, pd.DataFrame):
return dataframe_with_json_explorer(data)
elif isinstance(data, (dict, list)):
display_as_html(data)
return None
return data
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment