Download upstreams/langflow/scripts/generate_timeline.py from jyliuAI/diffusion_baseline: direct link, hf CLI and curl.
- Browser
- Download file 7.57 kB
-
https://huggingface.co/jyliuAI/diffusion_baseline/resolve/main/upstreams/langflow/scripts/generate_timeline.py
- Command line
-
hf download hf://jyliuAI/diffusion_baseline/upstreams/langflow/scripts/generate_timeline.py
-
curl -L -o generate_timeline.py https://huggingface.co/jyliuAI/diffusion_baseline/resolve/main/upstreams/langflow/scripts/generate_timeline.py
7.57 kB
| import pandas as pd | |
| import matplotlib.pyplot as plt | |
| import matplotlib.patches as patches | |
| import matplotlib.path as mpath | |
| import os | |
| # Configure input and output paths | |
| SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) | |
| PROJECT_ROOT = os.path.dirname(SCRIPT_DIR) | |
| INPUT_CSV = os.path.join(SCRIPT_DIR, 'data', 'timeline_data.csv') | |
| OUTPUT_PNG = os.path.join(PROJECT_ROOT, 'assets', 'timeline_output.png') | |
| # Color configuration | |
| COLORS = { | |
| 'Continuous': '#FCE4D6', # Light orange | |
| 'Discrete': '#E2F0D9', # Light green | |
| 'Border_Validated': '#1F3864', # Dark blue border | |
| } | |
| def get_rounded_rect_path(x, y, w, h, r_inch, ax): | |
| """Generate a rectangular path with perfect rounded corners to avoid border distortion""" | |
| bbox = ax.get_window_extent().transformed(ax.figure.dpi_scale_trans.inverted()) | |
| width_inch = bbox.width | |
| height_inch = bbox.height | |
| xmin, xmax = ax.get_xlim() | |
| ymin, ymax = ax.get_ylim() | |
| x_range = xmax - xmin | |
| y_range = ymax - ymin | |
| # Convert physical inch radius to radius in data coordinate system | |
| rx = r_inch * (x_range / width_inch) | |
| ry = r_inch * (y_range / height_inch) | |
| # Bezier curve control point ratio | |
| kappa = 0.552284749831 | |
| cx = kappa * rx | |
| cy = kappa * ry | |
| verts = [ | |
| (x + rx, y), | |
| (x + w - rx, y), | |
| (x + w - rx + cx, y), (x + w, y + ry - cy), (x + w, y + ry), | |
| (x + w, y + h - ry), | |
| (x + w, y + h - ry + cy), (x + w - rx + cx, y + h), (x + w - rx, y + h), | |
| (x + rx, y + h), | |
| (x + rx - cx, y + h), (x, y + h - ry + cy), (x, y + h - ry), | |
| (x, y + ry), | |
| (x, y + ry - cy), (x + rx - cx, y), (x + rx, y), | |
| (0, 0) | |
| ] | |
| codes = [ | |
| mpath.Path.MOVETO, | |
| mpath.Path.LINETO, | |
| mpath.Path.CURVE4, mpath.Path.CURVE4, mpath.Path.CURVE4, | |
| mpath.Path.LINETO, | |
| mpath.Path.CURVE4, mpath.Path.CURVE4, mpath.Path.CURVE4, | |
| mpath.Path.LINETO, | |
| mpath.Path.CURVE4, mpath.Path.CURVE4, mpath.Path.CURVE4, | |
| mpath.Path.LINETO, | |
| mpath.Path.CURVE4, mpath.Path.CURVE4, mpath.Path.CURVE4, | |
| mpath.Path.CLOSEPOLY | |
| ] | |
| return mpath.Path(verts, codes) | |
| def generate_timeline(csv_path, output_path): | |
| if not os.path.exists(csv_path): | |
| print(f"Error: Input file {csv_path} not found") | |
| return | |
| # Read CSV data | |
| df = pd.read_csv(csv_path) | |
| # --- Layout Constants --- | |
| BOX_WIDTH = 0.85 | |
| BOX_HEIGHT = 0.25 | |
| BOX_SPACING = 0.05 | |
| TIMELINE_Y = 0.0 | |
| TIMELINE_TO_BOX_SPACING = 0.10 | |
| YEAR_TEXT_SPACING = 0.15 | |
| # Derived layout constants | |
| VERTICAL_STEP = BOX_HEIGHT + BOX_SPACING | |
| FIRST_BOX_Y_CENTER = TIMELINE_Y - TIMELINE_TO_BOX_SPACING - (BOX_HEIGHT / 2) | |
| # Legend position (2 boxes below the 4th box of 2022) | |
| # 2022 has 4 boxes (index 0, 1, 2, 3), so lowest box is at index 3 | |
| LOWEST_2022_BOX_Y = FIRST_BOX_Y_CENTER - 3 * VERTICAL_STEP | |
| LEGEND_Y_START = LOWEST_2022_BOX_Y - 2 * VERTICAL_STEP | |
| # Calculate bounds | |
| X_MIN, X_MAX = 0.2, 7.0 | |
| Y_MAX = TIMELINE_Y + YEAR_TEXT_SPACING + 0.25 | |
| Y_MIN = LEGEND_Y_START - 2 * VERTICAL_STEP - (BOX_HEIGHT / 2) - 0.2 | |
| # Calculate figsize to maintain equal aspect ratio | |
| FIGSIZE_X = 15.0 | |
| FIGSIZE_Y = FIGSIZE_X * ((Y_MAX - Y_MIN) / (X_MAX - X_MIN)) | |
| # Create chart | |
| fig, ax = plt.subplots(figsize=(FIGSIZE_X, FIGSIZE_Y), dpi=300) | |
| ax.set_xlim(X_MIN, X_MAX) | |
| ax.set_ylim(Y_MIN, Y_MAX) | |
| ax.set_aspect('equal') | |
| ax.axis('off') # Hide axes | |
| # Draw timeline (main line) | |
| ax.plot([0.5, 6.7], [TIMELINE_Y, TIMELINE_Y], color='black', linewidth=3, zorder=1) | |
| # Draw arrow | |
| ax.arrow(6.7, TIMELINE_Y, 0.05, 0, head_width=0.05, head_length=0.1, fc='black', ec='black', linewidth=3, zorder=1) | |
| # Map years to X coordinates | |
| years = sorted(df['Year'].unique()) | |
| year_x_map = {year: i + 1 for i, year in enumerate(range(2021, 2027))} | |
| # Draw year nodes and text | |
| for year, x in year_x_map.items(): | |
| ax.plot(x, TIMELINE_Y, marker='o', color='black', markersize=8, zorder=2) | |
| ax.text(x, TIMELINE_Y + YEAR_TEXT_SPACING, str(year), ha='center', va='bottom', fontsize=16, fontweight='bold', fontfamily='serif') | |
| # Draw model boxes | |
| corner_radius_inch = 0.05 # Control physical radius of rounded corners (inches) | |
| for year in years: | |
| year_data = df[df['Year'] == year] | |
| x_center = year_x_map[year] | |
| for i, row in enumerate(year_data.itertuples()): | |
| y_center = FIRST_BOX_Y_CENTER - i * VERTICAL_STEP | |
| # Determine background and border colors | |
| bg_color = COLORS[row.Type] | |
| if row.Validated == 'Yes': | |
| edge_color = COLORS['Border_Validated'] | |
| line_width = 2 | |
| else: | |
| edge_color = bg_color # No obvious border | |
| line_width = 0 | |
| # Use custom path to draw rounded rectangle to avoid border distortion | |
| path = get_rounded_rect_path(x_center - BOX_WIDTH/2, y_center - BOX_HEIGHT/2, BOX_WIDTH, BOX_HEIGHT, corner_radius_inch, ax) | |
| rect = patches.PathPatch( | |
| path, | |
| facecolor=bg_color, | |
| edgecolor=edge_color, | |
| linewidth=line_width, | |
| zorder=3 | |
| ) | |
| ax.add_patch(rect) | |
| # Add text | |
| ax.text(x_center, y_center, row.Model, ha='center', va='center', fontsize=14, fontfamily='serif', zorder=4) | |
| # Draw legend (bottom left, inserted in the blank space below 2021 and 2022) | |
| legend_x = 1.0 | |
| # 1. Continuous diffusion | |
| path1 = get_rounded_rect_path(legend_x - BOX_WIDTH/2, LEGEND_Y_START - BOX_HEIGHT/2, BOX_WIDTH, BOX_HEIGHT, corner_radius_inch, ax) | |
| rect1 = patches.PathPatch( | |
| path1, | |
| facecolor=COLORS['Continuous'], | |
| edgecolor=COLORS['Continuous'], | |
| linewidth=0, | |
| zorder=3 | |
| ) | |
| ax.add_patch(rect1) | |
| ax.text(legend_x + BOX_WIDTH/2 + 0.2, LEGEND_Y_START, 'Continuous diffusion', ha='left', va='center', fontsize=12, fontweight='bold', fontfamily='serif') | |
| # 2. Discrete diffusion | |
| path2 = get_rounded_rect_path(legend_x - BOX_WIDTH/2, LEGEND_Y_START - VERTICAL_STEP - BOX_HEIGHT/2, BOX_WIDTH, BOX_HEIGHT, corner_radius_inch, ax) | |
| rect2 = patches.PathPatch( | |
| path2, | |
| facecolor=COLORS['Discrete'], | |
| edgecolor=COLORS['Discrete'], | |
| linewidth=0, | |
| zorder=3 | |
| ) | |
| ax.add_patch(rect2) | |
| ax.text(legend_x + BOX_WIDTH/2 + 0.2, LEGEND_Y_START - VERTICAL_STEP, 'Discrete diffusion', ha='left', va='center', fontsize=12, fontweight='bold', fontfamily='serif') | |
| # 3. Validated under the setup of GPT-2-small | |
| path3 = get_rounded_rect_path(legend_x - BOX_WIDTH/2, LEGEND_Y_START - 2*VERTICAL_STEP - BOX_HEIGHT/2, BOX_WIDTH, BOX_HEIGHT, corner_radius_inch, ax) | |
| rect3 = patches.PathPatch( | |
| path3, | |
| facecolor='white', | |
| edgecolor=COLORS['Border_Validated'], | |
| linewidth=2, | |
| zorder=3 | |
| ) | |
| ax.add_patch(rect3) | |
| ax.text(legend_x + BOX_WIDTH/2 + 0.2, LEGEND_Y_START - 2*VERTICAL_STEP, 'Validated under the setup of GPT-2-small', ha='left', va='center', fontsize=12, fontweight='bold', fontfamily='serif') | |
| # Save image | |
| plt.tight_layout() | |
| plt.savefig(output_path, format='png', bbox_inches='tight', pad_inches=0.1) | |
| print(f"Chart successfully generated and saved to: {output_path}") | |
| plt.close() | |
| if __name__ == '__main__': | |
| generate_timeline(INPUT_CSV, OUTPUT_PNG) | |