We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/mckinsey/vizro'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
"""Generate color and palette reference images for documentation."""
import json
from pathlib import Path
import numpy as np
import plotly.graph_objects as go
from vizro.themes import colors, palettes
def _load_theme_colors(theme):
"""Load background and text colors from Plotly template JSON files."""
template_file = Path(__file__).parent.parent / "src" / "vizro" / "themes" / f"vizro_{theme}.json"
with open(template_file) as f:
template = json.load(f)
return template["layout"]["plot_bgcolor"], template["layout"]["font"]["color"]
def _get_text_color(hex_color):
"""Determine contrasting text color (black/white) for a given hex color."""
BRIGHTNESS_THRESHOLD = 128
if not hex_color.startswith("#"):
return "black"
r, g, b = int(hex_color[1:3], 16), int(hex_color[3:5], 16), int(hex_color[5:7], 16)
return "white" if (r * 299 + g * 587 + b * 114) / 1000 < BRIGHTNESS_THRESHOLD else "black"
def _save_image(fig, output_path):
"""Save figure to image file."""
fig.write_image(output_path, width=fig.layout.width, height=fig.layout.height, scale=2)
print(f"✓ Generated {output_path}") # noqa: T201
def make_color_swatches(color_groups, cols, labels):
"""Create color swatch visualization."""
BOX_SIZE, GAP = 100, 0.15
counts = [len(group) for group in color_groups.values()]
# Generate coordinates
xs = [i * (1 + GAP) for count in counts for i in range(count)]
ys = [r * (1 + GAP) for r, count in enumerate(counts) for _ in range(count)]
fig = go.Figure(
go.Scatter(
x=xs,
y=ys,
mode="markers",
marker={"symbol": "square", "size": BOX_SIZE, "color": cols, "line": {"width": 1, "color": "#ddd"}},
hoverinfo="skip",
)
)
# Add labels inside boxes
for x, y, label, col in zip(xs, ys, labels, cols):
fig.add_annotation(
x=x,
y=y,
text=label,
showarrow=False,
font={"size": 12, "color": _get_text_color(col)},
)
fig.update_layout(
width=max(counts) * (1 + GAP) * BOX_SIZE + 50,
height=len(counts) * (1 + GAP) * BOX_SIZE + 60,
margin={"l": 0, "r": 0, "t": 10, "b": 10},
xaxis={"visible": False},
yaxis={"visible": False, "autorange": "reversed", "scaleanchor": "x", "scaleratio": 1},
plot_bgcolor="white",
paper_bgcolor="white",
showlegend=False,
)
return fig
def generate_colors_image(output_path):
"""Generate colors reference image."""
color_groups = {
"Qualitative": [
"blue",
"dark_purple",
"turquoise",
"dark_green",
"light_purple",
"light_green",
"light_pink",
"dark_pink",
"yellow",
"gray",
],
"Blue": [f"blue_{i}00" for i in range(1, 10)],
"Purple": [f"purple_{i}00" for i in range(1, 10)],
"Turquoise": [f"turquoise_{i}00" for i in range(1, 10)],
"Green": [f"green_{i}00" for i in range(1, 10)],
"Pink": [f"pink_{i}00" for i in range(1, 10)],
"Yellow": [f"yellow_{i}00" for i in range(1, 10)],
"Grey": [f"gray_{i}00" for i in range(1, 10)],
"Special": ["transparent", "white", "black"],
}
labels = [name for group in color_groups.values() for name in group]
cols = [getattr(colors, name) for name in labels]
_save_image(make_color_swatches(color_groups, cols, labels), output_path)
def make_palette_gradients(palette_groups, theme="light"):
"""Create continuous gradient bars for palettes using heatmap."""
bg_color, text_color = _load_theme_colors(theme)
BAR_HEIGHT, BAR_WIDTH, GAP = 80, 600, 10
NUM_ROWS, NUM_COLS = 50, 500
left_margin = 260
total_height = len(palette_groups) * (BAR_HEIGHT + GAP) - GAP + 40
fig = go.Figure()
y_tickvals, y_ticktext = [], []
for idx, (name, palette) in enumerate(palette_groups.items()):
y_pos = idx * (BAR_HEIGHT + GAP)
y_tickvals.append(y_pos + BAR_HEIGHT / 2)
y_ticktext.append(name)
fig.add_trace(
go.Heatmap(
z=np.tile(np.linspace(0, 1, NUM_COLS), (NUM_ROWS, 1)),
y=np.linspace(y_pos, y_pos + BAR_HEIGHT, NUM_ROWS),
x=np.linspace(0, BAR_WIDTH, NUM_COLS),
colorscale=[[i / (len(palette) - 1), color] for i, color in enumerate(palette)],
showscale=False,
hoverinfo="skip",
zmin=0,
zmax=1,
)
)
fig.update_layout(
width=left_margin + BAR_WIDTH + 40,
height=total_height,
margin={"l": left_margin, "r": 40, "t": 20, "b": 20},
xaxis={"visible": False, "range": [-20, BAR_WIDTH + 10]},
yaxis={
"visible": True,
"range": [-10, total_height - 30],
"tickmode": "array",
"tickvals": y_tickvals,
"ticktext": y_ticktext,
"tickfont": {"size": 24, "color": text_color},
"showgrid": False,
"zeroline": False,
"autorange": "reversed",
},
plot_bgcolor=bg_color,
paper_bgcolor=bg_color,
showlegend=False,
)
return fig
def make_qualitative_palette(palette, theme="light"):
"""Create discrete color boxes for qualitative palette."""
bg_color, text_color = _load_theme_colors(theme)
BOX_SIZE, GAP = 80, 0.15
fig = go.Figure(
go.Scatter(
x=[i * (1 + GAP) for i in range(len(palette))],
y=[0] * len(palette),
mode="markers",
marker={"symbol": "square", "size": BOX_SIZE, "color": palette, "line": {"width": 0}},
hoverinfo="skip",
)
)
fig.update_layout(
width=len(palette) * (1 + GAP) * BOX_SIZE + 260,
height=140,
margin={"l": 220, "r": 10, "t": 20, "b": 20},
xaxis={"visible": False},
yaxis={
"visible": True,
"range": [-0.6, 0.6],
"scaleanchor": "x",
"scaleratio": 1,
"tickmode": "array",
"tickvals": [0],
"ticktext": ["qualitative"],
"tickfont": {"size": 24, "color": text_color},
"showgrid": False,
"zeroline": False,
},
plot_bgcolor=bg_color,
paper_bgcolor=bg_color,
showlegend=False,
)
return fig
def generate_qualitative_palette_image(output_path, theme="light"):
"""Generate qualitative palette reference image with discrete boxes."""
_save_image(make_qualitative_palette(palettes.qualitative, theme), output_path)
def generate_palettes_image(output_path, theme="light"):
"""Generate palettes reference image with continuous gradients (excluding qualitative)."""
palette_groups = {name: getattr(palettes, name) for name in vars(palettes) if name != "qualitative"}
_save_image(make_palette_gradients(palette_groups, theme), output_path)
def main():
"""Generate theme reference images."""
output_dir = Path(__file__).parent.parent / "docs" / "assets" / "user_guides" / "themes"
output_dir.mkdir(parents=True, exist_ok=True)
print("Generating theme reference images...") # noqa: T201
generate_colors_image(output_dir / "colors.png")
for theme in ["light", "dark"]:
generate_qualitative_palette_image(output_dir / f"palette_qualitative_{theme}.png", theme)
generate_palettes_image(output_dir / f"palettes_continuous_{theme}.png", theme)
print("\n✅ All theme images generated successfully!") # noqa: T201
if __name__ == "__main__":
main()