Spaces:
Running
Running
# -*- coding: utf-8 -*- | |
# author: Martin FajΔΓk | |
# modified by: Jan DoleΕΎal | |
import csv | |
import random | |
import numpy as np | |
from bokeh.plotting import figure | |
from bokeh.models import LabelSet, LogScale, ColumnDataSource, tickers | |
from bokeh.palettes import Turbo256 # A color palette with enough colors | |
# Function to fit a polynomial curve and return the x and y values of the fitted curve | |
def fit_curve(x, y, degree=1): | |
# Fit a polynomial of given degree | |
coeffs = np.polyfit(x, y, degree) | |
poly = np.poly1d(coeffs) | |
x_fit = np.linspace(min(x), max(x), 100) | |
y_fit = poly(x_fit) | |
return x_fit, y_fit | |
# Function to detect and remove outliers using the IQR method | |
def remove_outliers(x, y): | |
x = np.array(x) | |
y = np.array(y) | |
# Calculate Q1 (25th percentile) and Q3 (75th percentile) | |
Q1_x, Q3_x = np.percentile(x, [25, 75]) | |
Q1_y, Q3_y = np.percentile(y, [25, 75]) | |
IQR_x = Q3_x - Q1_x | |
IQR_y = Q3_y - Q1_y | |
# Define bounds for outliers | |
lower_bound_x = Q1_x - 1.5 * IQR_x | |
upper_bound_x = Q3_x + 1.5 * IQR_x | |
lower_bound_y = Q1_y - 1.5 * IQR_y | |
upper_bound_y = Q3_y + 1.5 * IQR_y | |
# Filter out outliers | |
mask_x = (x >= lower_bound_x) & (x <= upper_bound_x) | |
mask_y = (y >= lower_bound_y) & (y <= upper_bound_y) | |
mask = mask_x & mask_y | |
return x[mask], y[mask], x[~mask], y[~mask] | |
def get_ldb_records(name_map, csv_file_path): | |
model_mapping = {model_title: model_title for model_title in name_map.values()} | |
ldb_records={} | |
with open(csv_file_path, mode='r') as file: | |
reader = csv.DictReader(file) | |
for row in reader: | |
sanitized_name = model_mapping[row['Model']] | |
ldb_records[sanitized_name] = row | |
return ldb_records | |
def create_scatter_plot_with_curve_with_variances_named(category, variance_across_categories, x, y, sizes, model_names, ldb_records): | |
FONTSIZE = 12 | |
# Remove outliers | |
x_filtered, y_filtered, x_outliers, y_outliers = remove_outliers(x, y) | |
# Scale the variance to a range suitable for marker sizes (e.g., between 5 and 30) | |
min_marker_size = 5 | |
max_marker_size = 30 | |
def scale_variance_to_size(variance): | |
# Scale variance to marker size (linear mapping) | |
return min_marker_size + (variance - min(variance_across_categories.values())) * (max_marker_size - min_marker_size) / (max(variance_across_categories.values()) - min(variance_across_categories.values())) | |
# Function to get the variance for a given model name | |
def get_variance_for_model(model_name): | |
return variance_across_categories.get(model_name, 0) # Default to 0 if model not found | |
# Get markers | |
filtered_markers = np.array(model_names)[np.in1d(x, x_filtered)] | |
outlier_markers = np.array(model_names)[np.in1d(x, x_outliers)] | |
# Get marker sizes and variances for the filtered data | |
filtered_variances = [get_variance_for_model(mname) for mname in filtered_markers] | |
marker_sizes_filtered = [scale_variance_to_size(var) for var in filtered_variances] | |
# Get marker sizes and variances for the outlier data | |
outlier_variances = [get_variance_for_model(mname) for mname in outlier_markers] | |
marker_sizes_outliers = [scale_variance_to_size(var) for var in outlier_variances] | |
# Assign symbols to the model types | |
# https://docs.bokeh.org/en/latest/docs/examples/basic/scatters/markers.html | |
_model_type2symbol = { | |
'chat': 'circle', | |
'pretrained': 'triangle', | |
'ensemble': 'star', | |
} | |
model_type2symbol = lambda model_type: _model_type2symbol.get(model_type, 'diamond') | |
# Assign symbols to the filtered data points | |
filtered_symbols = [model_type2symbol(ldb_records[mname]['Type']) for mname in filtered_markers] | |
# Assign symbols to the outlier data points | |
outlier_symbols = [model_type2symbol(ldb_records[mname]['Type']) for mname in outlier_markers] | |
# Define a color palette with enough colors | |
stride = len(Turbo256) // len(model_names) | |
color_palette = list(Turbo256[::stride]) # Adjust this palette size based on the number of data points | |
random.shuffle(color_palette) | |
# Create unique colors for filtered data | |
filtered_colors = [color_palette[i % len(color_palette)] for i in range(len(x_filtered))] | |
# Create unique colors for outliers | |
outlier_colors = [color_palette[(i + len(x_filtered)) % len(color_palette)] for i in range(len(x_outliers))] | |
# Create ColumnDataSource with filtered data | |
source_filtered = ColumnDataSource(data={ | |
'x': x_filtered, | |
'y': y_filtered, | |
'sizes': np.array(sizes)[np.in1d(x, x_filtered)], # Keep original model sizes | |
'marker_sizes': marker_sizes_filtered, # New field for marker sizes based on variance | |
'model_names': np.array(model_names)[np.in1d(x, x_filtered)], | |
'variance': filtered_variances, # New field for variance | |
'color': filtered_colors, | |
'symbol': filtered_symbols | |
}) | |
# Create ColumnDataSource with outlier data | |
source_outliers = ColumnDataSource(data={ | |
'x': x_outliers, | |
'y': y_outliers, | |
'sizes': np.array(sizes)[np.in1d(x, x_outliers)], # Keep original model sizes | |
'marker_sizes': marker_sizes_outliers, # New field for marker sizes based on variance | |
'model_names': np.array(model_names)[np.in1d(x, x_outliers)], | |
'variance': outlier_variances, # New field for variance | |
'color': outlier_colors, | |
'symbol': outlier_symbols | |
}) | |
# Create a figure for the category | |
p = figure( | |
sizing_mode="stretch_width", | |
height=800, | |
#title=f"{category} vs Model Size vs Variance Across Categories", | |
tools="pan,wheel_zoom,box_zoom,save,reset", | |
active_scroll="wheel_zoom", | |
tooltips=[ | |
("Model", "@model_names"), | |
("Model Size (B parameters)", "@sizes"), | |
("Variance", "@variance"), # Added variance to the tooltip | |
("Performance", "@y"), | |
] | |
) | |
# Plot filtered data with unique colors and scaled marker sizes | |
p.scatter('x', 'y', size='marker_sizes', source=source_filtered, fill_alpha=0.6, color='color', marker='symbol') | |
# Plot outliers with unique colors and scaled marker sizes | |
p.scatter('x', 'y', size='marker_sizes', source=source_outliers, fill_alpha=0.6, color='color', marker='symbol') | |
# Fit and plot a curve | |
x_fit, y_fit = fit_curve(x_filtered, y_filtered, degree=1) # You can adjust the degree of the polynomial | |
p.line(x_fit, y_fit, line_color='gray', line_width=2, line_dash='dashed') | |
# Add labels (with slight offset to avoid overlap) | |
p.add_layout(LabelSet( | |
x='x', | |
y='y', | |
text='model_names', | |
source=source_filtered, | |
x_offset=5, | |
y_offset=8, | |
text_font_size=f"{FONTSIZE-2}pt", | |
text_color='black', | |
)) | |
p.add_layout(LabelSet( | |
x='x', | |
y='y', | |
text='model_names', | |
source=source_outliers, | |
x_offset=5, | |
y_offset=8, | |
text_font_size=f"{FONTSIZE-2}pt", | |
text_color='black', | |
)) | |
# Set axis labels | |
p.xaxis.axis_label = 'Model Size (B parameters)' | |
p.yaxis.axis_label = f'{category}' | |
# Set axis label font sizes | |
p.xaxis.axis_label_text_font_size = f"{FONTSIZE}pt" # Set font size for x-axis label | |
p.yaxis.axis_label_text_font_size = f"{FONTSIZE}pt" # Set font size for y-axis label | |
# Increase tick label font sizes | |
p.xaxis.major_label_text_font_size = f"{FONTSIZE}pt" # Increase x-axis tick label size | |
p.yaxis.major_label_text_font_size = f"{FONTSIZE}pt" # Increase y-axis tick label size | |
p.x_scale = LogScale() | |
p.xaxis.ticker = tickers.LogTicker() | |
p.xaxis.axis_label_text_font_style = "normal" | |
p.yaxis.axis_label_text_font_style = "normal" | |
return p | |
# EOF | |