diff --git a/plots/streamline-basic/implementations/python/plot-dark.png b/plots/streamline-basic/implementations/python/plot-dark.png new file mode 100644 index 0000000000..20e828c389 Binary files /dev/null and b/plots/streamline-basic/implementations/python/plot-dark.png differ diff --git a/plots/streamline-basic/implementations/python/plot-light.png b/plots/streamline-basic/implementations/python/plot-light.png new file mode 100644 index 0000000000..8db5b6615a Binary files /dev/null and b/plots/streamline-basic/implementations/python/plot-light.png differ diff --git a/plots/streamline-basic/implementations/python/seaborn.py b/plots/streamline-basic/implementations/python/seaborn.py index 8032b32606..4b641bb97b 100644 --- a/plots/streamline-basic/implementations/python/seaborn.py +++ b/plots/streamline-basic/implementations/python/seaborn.py @@ -1,9 +1,11 @@ -""" pyplots.ai +""" anyplot.ai streamline-basic: Basic Streamline Plot -Library: seaborn 0.13.2 | Python 3.13.11 -Quality: 91/100 | Created: 2025-12-31 +Library: seaborn 0.13.2 | Python 3.13.13 +Quality: 86/100 | Updated: 2026-05-14 """ +import os + import matplotlib.pyplot as plt import numpy as np import pandas as pd @@ -11,20 +13,23 @@ from matplotlib.patches import FancyArrowPatch +# Theme tokens +THEME = os.getenv("ANYPLOT_THEME", "light") +PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" +ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420" +INK = "#1A1A17" if THEME == "light" else "#F0EFE8" +INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" + # Set seed for reproducibility np.random.seed(42) # Vortex flow field: u = -y, v = x (creates circular streamlines) -# Velocity magnitude = distance from center - -# Generate streamlines using Euler integration streamlines_data = [] -arrow_data = [] # Store arrow positions for flow direction indicators +arrow_data = [] streamline_id = 0 -# Starting points at different radii - removed innermost radius to eliminate overlap artifacts +# Starting points at different radii radii = [0.8, 1.2, 1.6, 2.0, 2.4, 2.8] -# Use fewer streamlines at inner radii to prevent crowding n_per_radius_map = {0.8: 3, 1.2: 4, 1.6: 5, 2.0: 5, 2.4: 6, 2.8: 6} dt = 0.03 max_steps = 250 @@ -39,11 +44,10 @@ # Trace streamline using Euler integration for step in range(max_steps): - # Check bounds first if abs(x) > 3.2 or abs(y) > 3.2: break - # Vector field: circular vortex (u = -y, v = x) + # Vector field: circular vortex u = -y v = x speed = np.sqrt(u**2 + v**2) @@ -51,7 +55,6 @@ if speed < 1e-6: break - # Store point with velocity magnitude (= radius in vortex) vel_mag = np.sqrt(x**2 + y**2) streamlines_data.append( { @@ -64,19 +67,18 @@ ) streamline_points.append((x, y, u, v, vel_mag)) - # Normalize and step x = x + dt * u / speed y = y + dt * v / speed - # Store arrow position at midpoint of each streamline + # Store arrow position at midpoint if len(streamline_points) > 20: mid_idx = len(streamline_points) // 2 px, py, pu, pv, pvel = streamline_points[mid_idx] - arrow_data.append({"x": px, "y": py, "u": pu, "v": pv, "velocity": pvel, "radius": r}) + arrow_data.append({"x": px, "y": py, "u": pu, "v": pv, "velocity": pvel}) streamline_id += 1 -# Create DataFrame +# Create DataFrames df = pd.DataFrame(streamlines_data) arrows_df = pd.DataFrame(arrow_data) @@ -85,25 +87,31 @@ avg_velocity.columns = ["streamline_id", "avg_velocity"] df = df.merge(avg_velocity, on="streamline_id") -# Create velocity bins for categorical legend - seaborn-centric approach -velocity_bins = pd.qcut(df["avg_velocity"], q=6, duplicates="drop") -df["Speed Range"] = velocity_bins.apply(lambda x: f"{x.left:.1f}-{x.right:.1f} m/s") - -# Set seaborn style with custom aesthetics +# Configure seaborn with theme-adaptive colors sns.set_theme( - style="whitegrid", rc={"axes.labelsize": 20, "axes.titlesize": 24, "xtick.labelsize": 16, "ytick.labelsize": 16} + style="ticks", + rc={ + "figure.facecolor": PAGE_BG, + "axes.facecolor": PAGE_BG, + "axes.edgecolor": INK_SOFT, + "axes.labelcolor": INK, + "text.color": INK, + "xtick.color": INK_SOFT, + "ytick.color": INK_SOFT, + "grid.color": INK, + "grid.alpha": 0.10, + }, ) -sns.set_context("talk", font_scale=1.2) -# Create square figure to better utilize canvas for equal aspect ratio plot -fig, ax = plt.subplots(figsize=(12, 12)) +# Create square figure for equal aspect ratio +fig, ax = plt.subplots(figsize=(12, 12), facecolor=PAGE_BG) +ax.set_facecolor(PAGE_BG) -# Use seaborn color_palette to create viridis colors for continuous mapping +# Use viridis colormap for continuous velocity data palette = sns.color_palette("viridis", as_cmap=True) norm = plt.Normalize(df["avg_velocity"].min(), df["avg_velocity"].max()) -# Plot streamlines using seaborn's lineplot with hue for velocity -# Each streamline is a separate unit, colored by average velocity +# Plot streamlines with continuous color encoding sns.lineplot( data=df, x="x", @@ -125,7 +133,6 @@ px, py = arrow["x"], arrow["y"] pu, pv = arrow["u"], arrow["v"] speed = np.sqrt(pu**2 + pv**2) - # Normalize direction dx = 0.15 * pu / speed dy = 0.15 * pv / speed color = cmap(norm(arrow["velocity"])) @@ -140,24 +147,30 @@ ) ax.add_patch(arrow_patch) -# Add colorbar manually (seaborn lineplot doesn't auto-create one for continuous hue) +# Add colorbar sm = plt.cm.ScalarMappable(cmap="viridis", norm=norm) sm.set_array([]) cbar = fig.colorbar(sm, ax=ax, shrink=0.8, aspect=20) -cbar.set_label("Flow Speed (m/s)", fontsize=20) -cbar.ax.tick_params(labelsize=16) - -# Use seaborn despine for cleaner appearance -sns.despine(ax=ax, left=False, bottom=False) - -# Styling with units explicitly in axis labels -ax.set(xlabel="X Position (m)", ylabel="Y Position (m)") -ax.set_title("streamline-basic · seaborn · pyplots.ai", fontsize=24, fontweight="bold") -ax.tick_params(axis="both", labelsize=16) +cbar.set_label("Flow Speed (m/s)", fontsize=20, color=INK) +cbar.ax.tick_params(labelsize=16, colors=INK_SOFT) + +# Style axes +ax.set_xlabel("X Position (m)", fontsize=20, color=INK) +ax.set_ylabel("Y Position (m)", fontsize=20, color=INK) +ax.set_title("streamline-basic · seaborn · anyplot.ai", fontsize=24, fontweight="medium", color=INK) +ax.tick_params(axis="both", labelsize=16, colors=INK_SOFT) ax.set_aspect("equal") ax.set_xlim(-3.5, 3.5) ax.set_ylim(-3.5, 3.5) -ax.grid(True, alpha=0.3, linestyle="--") + +# Remove spines +ax.spines["top"].set_visible(False) +ax.spines["right"].set_visible(False) +ax.spines["left"].set_color(INK_SOFT) +ax.spines["bottom"].set_color(INK_SOFT) + +# Subtle grid +ax.yaxis.grid(True, alpha=0.15, linewidth=0.8, color=INK) plt.tight_layout() -plt.savefig("plot.png", dpi=300, bbox_inches="tight") +plt.savefig(f"plot-{THEME}.png", dpi=300, bbox_inches="tight", facecolor=PAGE_BG) diff --git a/plots/streamline-basic/metadata/python/seaborn.yaml b/plots/streamline-basic/metadata/python/seaborn.yaml index 4b3cf03511..9c9f2886b1 100644 --- a/plots/streamline-basic/metadata/python/seaborn.yaml +++ b/plots/streamline-basic/metadata/python/seaborn.yaml @@ -1,162 +1,184 @@ library: seaborn +language: python specification_id: streamline-basic created: '2025-12-31T00:48:49Z' -updated: '2025-12-31T01:07:48Z' -generated_by: claude-opus-4-5-20251101 -workflow_run: 20609206863 +updated: '2026-05-14T07:26:07Z' +generated_by: claude-haiku +workflow_run: 25847266637 issue: 2861 -python_version: 3.13.11 +python_version: 3.13.13 library_version: 0.13.2 -preview_url: https://storage.googleapis.com/anyplot-images/plots/streamline-basic/seaborn/plot.png -preview_html: null -quality_score: 91 -impl_tags: - dependencies: [] - techniques: - - colorbar - - annotations - patterns: - - data-generation - - iteration-over-groups - dataprep: [] - styling: - - alpha-blending - - grid-styling +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/streamline-basic/python/seaborn/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/streamline-basic/python/seaborn/plot-dark.png +preview_html_light: null +preview_html_dark: null +quality_score: 86 review: strengths: - - Excellent visual clarity with well-sized streamlines and viridis color encoding - - Creative solution using seaborn lineplot with units parameter to render individual - streamlines - - Proper Euler integration for tracing streamlines through the vector field - - Clean vortex pattern demonstrates the circular flow field effectively - - Arrowheads correctly indicate flow direction - - Good use of seaborn theming (sns.set_theme, sns.set_context, sns.despine) + - 'Perfect theme adaptation: both light and dark renders have correct backgrounds, + text colors, and chrome, with no legibility failures' + - 'Clean mathematical visualization: Euler-integrated streamlines accurately represent + the vortex field; arrowheads clearly indicate direction' + - 'Professional polish: minimal spine design, subtle grid, generous whitespace, + proper colorbar integration' + - 'Reproducible and robust: deterministic seed, clean code structure, no edge cases + or failures' + - 'Perceptually uniform colormap: viridis is CVD-safe and correctly applied to continuous + velocity data' weaknesses: - - Colorbar label missing units in rendered output - - Axis labels in rendered image missing units despite being in code - image_description: 'The plot shows a series of concentric circular streamlines visualizing - a vortex flow field. The streamlines are colored using the viridis colormap, ranging - from dark purple (inner rings, ~0.8 m/s) through blues and greens (middle rings) - to yellow (outer rings, ~3.0 m/s). The plot has a square 1:1 aspect ratio with - axes ranging from -3 to 3 on both X and Y. Axis labels show "X Position" and "Y - Position" (missing units on axes). A colorbar on the right indicates "Flow Speed" - (also missing units). The title correctly follows the required format: "streamline-basic - · seaborn · pyplots.ai". The grid is subtle (dashed, low alpha). Small arrowheads - are visible on the streamlines indicating counter-clockwise flow direction.' + - 'Design is competent but standard: lacks custom visual refinement beyond defaults; + could benefit from intentional color palette choices or annotations' + - 'Limited seaborn-specific usage: core visualization logic relies on custom Euler + integration and matplotlib patches rather than seaborn features' + - 'No visual hierarchy emphasis: focal point emerges from data structure, not intentional + design decisions (e.g., color contrast, size variation, annotated insights)' + image_description: |- + Light render (plot-light.png): + Background: Warm off-white (#FAF8F1) - correct theme surface + Chrome: Title "streamline-basic · seaborn · anyplot.ai" in dark text (INK) at 24pt, clearly readable. Axis labels "X Position (m)" and "Y Position (m)" in dark text at 20pt, legible. Tick labels in medium gray (INK_SOFT) at 16pt, clearly visible. Colorbar label "Flow Speed (m/s)" in dark text. Grid lines subtle (alpha=0.10), barely visible but present. + Data: Concentric circular streamlines colored with viridis (purple to yellow), representing flow speed 0-2.75 m/s. Small arrowheads at streamline midpoints show counterclockwise flow direction. All elements clearly distinguishable from background. + Legibility verdict: PASS - All text fully readable, no light-on-light failures, data visualization clear. + + Dark render (plot-dark.png): + Background: Warm near-black (#1A1A17) - correct dark theme surface + Chrome: Title, axis labels, colorbar label all rendered in light text (INK adjusted to #F0EFE8), providing excellent contrast against dark background. Tick labels in lighter gray (INK_SOFT adjusted for dark theme). Grid lines remain subtle and visible (alpha=0.10 but with light color). NO dark-on-dark failures detected - text colors have properly inverted from light theme. + Data: Viridis colormap streamlines are identical to light render (purple to yellow), confirming only chrome has flipped per specification. Arrowheads visible and consistent. Flow direction clear. + Legibility verdict: PASS - All text readable on dark background, color contrast appropriate, data colors consistent with light render. criteria_checklist: visual_quality: - score: 36 - max: 40 + score: 30 + max: 30 items: - id: VQ-01 name: Text Legibility - score: 10 - max: 10 + score: 8 + max: 8 passed: true - comment: Title 24pt, labels 20pt, ticks 16pt - all clearly readable + comment: All text explicitly sized (24pt title, 20pt labels, 16pt ticks) and + readable in both light and dark renders. Theme tokens correctly adapt colors. - id: VQ-02 name: No Overlap - score: 8 - max: 8 + score: 6 + max: 6 passed: true - comment: No overlapping text or visual elements + comment: Concentric streamlines non-overlapping, arrowheads distributed without + collisions, colorbar does not obscure plot. - id: VQ-03 name: Element Visibility - score: 8 - max: 8 + score: 6 + max: 6 passed: true - comment: Streamlines are clearly visible with good line width and alpha + comment: All streamlines distinct and visible, arrowheads small but clear, + colorbar well-proportioned. - id: VQ-04 name: Color Accessibility - score: 5 - max: 5 + score: 2 + max: 2 passed: true - comment: Viridis colormap is colorblind-safe + comment: Viridis is CVD-safe perceptually uniform. Colorbar labels magnitude. + No red-green signal. - id: VQ-05 - name: Layout Balance - score: 5 - max: 5 + name: Layout & Canvas + score: 4 + max: 4 passed: true - comment: Square aspect ratio fills canvas well, balanced margins + comment: Square 12x12 figsize with equal aspect ratio appropriate for vortex. + Xlim/ylim ±3.5, no cut-off. - id: VQ-06 - name: Axis Labels - score: 1 + name: Axis Labels & Title + score: 2 max: 2 - passed: false - comment: Axis labels say "X Position" and "Y Position" but code has units - in label ("X Position (m)"), yet rendered image shows labels WITHOUT units + passed: true + comment: Title format correct. X/Y axes labeled with units. - id: VQ-07 - name: Grid & Legend + name: Palette Compliance score: 2 max: 2 passed: true - comment: Subtle dashed grid at alpha=0.3, colorbar well-placed + comment: Viridis correct for continuous data. Backgrounds match spec. Data + colors identical between renders. + design_excellence: + score: 12 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 5 + max: 8 + passed: true + comment: Clean minimalist design, viridis well-chosen, arrowheads thoughtfully + integrated, but lacks custom visual distinction. + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: true + comment: L-shaped spine frame, subtle grid (alpha=0.15), generous whitespace. + Professional but standard refinement. + - id: DE-03 + name: Data Storytelling + score: 3 + max: 6 + passed: true + comment: Concentric circles and color gradient guide viewer; focal point natural + from data structure, not intentional design. spec_compliance: - score: 25 - max: 25 + score: 15 + max: 15 items: - id: SC-01 name: Plot Type - score: 8 - max: 8 - passed: true - comment: Correct streamline visualization of vector field - - id: SC-02 - name: Data Mapping score: 5 max: 5 passed: true - comment: X/Y grid with velocity components correctly mapped - - id: SC-03 + comment: Correct streamline plot type with smooth field-tangent curves. + - id: SC-02 name: Required Features - score: 5 - max: 5 + score: 4 + max: 4 passed: true - comment: Streamlines with density control, color encoding velocity, direction - arrows - - id: SC-04 - name: Data Range + comment: 'All features present: streamlines, direction arrows, velocity encoding, + field topology.' + - id: SC-03 + name: Data Mapping score: 3 max: 3 passed: true - comment: All data visible within -3.5 to 3.5 range - - id: SC-05 - name: Legend Accuracy - score: 2 - max: 2 - passed: true - comment: Colorbar correctly labeled - - id: SC-06 - name: Title Format - score: 2 - max: 2 + comment: X/Y coordinates and velocity magnitude correctly mapped. Domain fully + visible. + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 passed: true - comment: 'Uses correct format: streamline-basic · seaborn · pyplots.ai' + comment: Title format matches spec. Colorbar serves as legend. data_quality: - score: 18 - max: 20 + score: 15 + max: 15 items: - id: DQ-01 name: Feature Coverage - score: 8 - max: 8 + score: 6 + max: 6 passed: true - comment: Shows vortex flow with circular streamlines at multiple radii + comment: 'Demonstrates all aspects: multiple starting positions, continuous + paths, velocity encoding, arrows, appropriate density.' - id: DQ-02 name: Realistic Context score: 5 - max: 7 - passed: false - comment: Vortex flow is a plausible physics scenario; could be stronger with - domain context + max: 5 + passed: true + comment: Vortex field (u=-y, v=x) is canonical physics example, mathematically + correct and neutral. - id: DQ-03 name: Appropriate Scale - score: 5 - max: 5 + score: 4 + max: 4 passed: true - comment: Values are sensible for a normalized flow field + comment: Domain [-3.2, 3.2] well-chosen. Velocity 0-2.75 m/s reasonable. Integration + parameters produce smooth streamlines. code_quality: - score: 9 + score: 10 max: 10 items: - id: CQ-01 @@ -164,41 +186,62 @@ review: score: 3 max: 3 passed: true - comment: 'Linear flow: imports → data generation → plot → save' + comment: No functions/classes. Straightforward data generation and visualization + pipeline. - id: CQ-02 name: Reproducibility - score: 3 - max: 3 + score: 2 + max: 2 passed: true - comment: np.random.seed(42) is set + comment: np.random.seed(42) ensures deterministic output. - id: CQ-03 name: Clean Imports - score: 1 + score: 2 max: 2 - passed: false - comment: All imports used; pandas import used for DataFrame + passed: true + comment: Minimal imports, all used. No bloat. - id: CQ-04 - name: No Deprecated API - score: 1 - max: 1 + name: Code Elegance + score: 2 + max: 2 passed: true - comment: Uses current seaborn API + comment: Euler integration appropriate and well-implemented. FancyArrowPatch + idiomatic. No fake UI. - id: CQ-05 - name: Output Correct + name: Output & API score: 1 max: 1 passed: true - comment: Saves as plot.png - library_features: - score: 3 - max: 5 + comment: Saves as plot-{THEME}.png. Current seaborn API. + library_mastery: + score: 4 + max: 10 items: - - id: LF-01 - name: Uses distinctive library features + - id: LM-01 + name: Idiomatic Usage score: 3 max: 5 - passed: false - comment: Uses sns.lineplot with hue/units, sns.set_theme, sns.despine, sns.color_palette - - good usage but streamlines aren't a native seaborn plot type, mostly relies - on matplotlib FancyArrowPatch for arrows + passed: true + comment: Uses sns.lineplot with units parameter and sns.set_theme correctly. + Core streamline logic is matplotlib/numpy, not seaborn-specific. + - id: LM-02 + name: Distinctive Features + score: 1 + max: 5 + passed: true + comment: Does not showcase seaborn-specific capabilities. Streamlines and + arrows are matplotlib/numpy. Acceptable for this plot type. verdict: APPROVED +impl_tags: + dependencies: [] + techniques: + - colorbar + - patches + patterns: + - data-generation + - iteration-over-groups + - explicit-figure + dataprep: [] + styling: + - custom-colormap + - grid-styling