import matplotlib.pyplot as plt import matplotlib.ticker as ticker import numpy as np # --- Data --- phases = [ "Naive ring\narrangement", "LP + simulated\nannealing", "Multi-start\noptimization", "SLSQP joint\noptimization", "Iterated\nperturbation", ] scores = [0.96, 2.50, 2.555, 2.619, 2.63598844] x = np.arange(len(phases)) SOTA = 2.63598308 # --- Style Config (matching blog CSS variables) --- color_main = "#4a6fa5" # --accent color_sota = "#c0392b" # warm red color_text = "#1a1a2e" # --bold-num color_secondary = "#555" # --text-secondary color_bg = "#fafaf7" # --bg color_border = "#e0ddd8" # --border color_green = "#1a7f37" # blog green for breakthrough plt.rcParams["font.family"] = "sans-serif" plt.rcParams["font.sans-serif"] = ["Lato", "Helvetica", "Arial"] # 更紧凑的画布比例 fig, ax = plt.subplots(figsize=(10, 5.5)) fig.patch.set_facecolor(color_bg) ax.set_facecolor(color_bg) # 1. Background & Area ax.fill_between(x, scores, color=color_main, alpha=0.06, zorder=1) ax.yaxis.set_major_locator(ticker.MultipleLocator(0.5)) ax.grid(axis="y", color=color_border, linestyle="-", linewidth=0.8, alpha=0.6, zorder=0) # 2. SOTA Reference ax.axhline(y=SOTA, color=color_sota, linestyle="--", linewidth=1.2, alpha=0.45, zorder=2) ax.text(-0.35, SOTA + 0.015, f"PREVIOUS SOTA: {SOTA:.8f}", fontsize=11, color=color_sota, fontweight="bold", va="bottom") # 3. The Line ax.plot(x, scores, color=color_main, linewidth=3.5, zorder=3, alpha=0.85) # 4. Points & Score Labels for i, score in enumerate(scores): is_breakthrough = score > SOTA is_last = (i == len(scores) - 1) m_color = color_green if is_breakthrough else color_main ax.scatter(x[i], score, color=m_color, s=280, zorder=4, alpha=0.12) ax.scatter(x[i], score, color=m_color, s=90, zorder=5, edgecolors=color_bg, linewidths=1.5) label = f"{score:.8f}" if is_last else f"{score:.3f}" y_offset = 0.06 if is_last else 0.05 ax.text(x[i], score + y_offset, label, ha="center", va="bottom", fontsize=14 if not is_last else 16, fontweight="bold", color=m_color, zorder=6) # 5. Staggered Annotations box_style_default = dict(boxstyle="round,pad=0.4", fc=color_bg, ec=color_border, alpha=0.95) box_style_highlight = dict(boxstyle="round,pad=0.4", fc="#dafbe1", ec=color_green, alpha=1) # 三个注释框都放在曲线下方,y 位置逐渐升高避免重叠 ax.annotate( "Agent reads ArXiv paper,\nswitches to LP formulation", xy=(x[1], scores[1]), xytext=(x[1], 1.35), fontsize=13, color=color_secondary, ha="center", arrowprops=dict(arrowstyle="->", color="#999", lw=1.2, connectionstyle="arc3,rad=0.1"), bbox=box_style_default, zorder=7 ) ax.annotate( "SLSQP breakthrough:\njoint radius + position opt.", xy=(x[3], scores[3]), xytext=(x[3], 1.65), fontsize=13, color=color_secondary, ha="center", arrowprops=dict(arrowstyle="->", color="#999", lw=1.2, connectionstyle="arc3,rad=0.1"), bbox=box_style_default, zorder=7 ) ax.annotate( "Parallel perturbation\nchains surpass SOTA", xy=(x[4], scores[4]), xytext=(x[4], 1.95), fontsize=13, color=color_green, ha="center", fontweight="bold", arrowprops=dict(arrowstyle="->", color=color_green, lw=1.5, connectionstyle="arc3,rad=0.1"), bbox=box_style_highlight, zorder=7 ) # --- Final Layout --- ax.set_xticks(x) ax.set_xticklabels(phases, fontsize=13, color=color_secondary, fontweight="medium") ax.set_ylabel("Score (Sum of Radii)", fontsize=13, color=color_secondary, labelpad=10) ax.set_title("Circle Packing Score Progression (26 circles in unit square)", fontsize=19, fontweight="bold", color=color_text, pad=16) for spine in ["top", "right", "left"]: ax.spines[spine].set_visible(False) ax.spines["bottom"].set_color(color_border) # 收紧 Y 轴范围,减少空白 ax.set_ylim(0.75, 2.95) ax.set_xlim(-0.4, len(phases) - 0.2) plt.tight_layout() # Save high-res to publish directory output_path = "/home/tengxiao/pj/ShinkaEvolve/ccevolve/blog/publish/score_progression.png" plt.savefig(output_path, dpi=300, bbox_inches="tight", facecolor=color_bg) print(f"Saved to {output_path}") plt.show()