diffusion_baseline / upstreams /langflow /scripts /generate_timeline.py
jyliuAI's picture
Add files using upload-large-folder tool
bfdae48 verified
Raw History Blame Contribute Delete
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)