1212from matplotlib import patches as mpatches
1313from matplotlib .patches import Rectangle
1414from matplotlib import rcParams
15+ from matplotlib import ticker
16+ from matplotlib .gridspec import GridSpec
1517import numpy as np
1618from datetime import datetime , timedelta
1719import data_cache
1820
19- # Increase all font sizes by 8 points from their defaults
20- rcParams .update ({key : rcParams [key ] + 8 for key in rcParams if "size" in key and isinstance (rcParams [key ], (int , float ))})
21+ # Increase all font sizes by 16 points from their defaults
22+ rcParams .update ({key : rcParams [key ] + 16 for key in rcParams if "size" in key and isinstance (rcParams [key ], (int , float ))})
2123
2224# ============================================================================
2325# CONFIGURATION SECTION
@@ -247,14 +249,16 @@ def generate_distribution_comparison(block_dir, zns_dir, distribution, metric, o
247249
248250 print (f"Found { len (block_runs )} block runs and { len (zns_runs )} ZNS runs" )
249251
250- # Create figure with 6 subplots (1 row x 6 columns)
252+ # Create figure with 6 subplots (1 row x 6 columns) using GridSpec for custom widths
251253 # Subplots are 2/5 original height, but all spacing preserved
252254 num_subplots = len (RATIOS ) * len (CHUNK_SIZES ) # 2 ratios * 3 chunk sizes = 6
253- fig , axes = plt .subplots (1 , num_subplots , figsize = (5 * num_subplots , 5.38 ))
254255
255- # Ensure axes is always a list
256- if num_subplots == 1 :
257- axes = [axes ]
256+ # Width ratios: 1077MiB subplots (indices 2 and 5) are half as wide since they have 2 boxes instead of 4
257+ width_ratios = [1 , 1 , 0.5 , 1 , 1 , 0.5 ]
258+
259+ fig = plt .figure (figsize = (5 * num_subplots , 5.38 ))
260+ gs = GridSpec (1 , num_subplots , figure = fig , width_ratios = width_ratios )
261+ axes = [fig .add_subplot (gs [0 , i ]) for i in range (num_subplots )]
258262
259263 # First pass: collect all data to find global maximum for y-axis
260264 all_subplot_data = []
@@ -391,24 +395,37 @@ def generate_distribution_comparison(block_dir, zns_dir, distribution, metric, o
391395
392396 # Create boxplot for this subplot
393397 if current_data :
398+ # Adjust box width based on number of boxes so they're consistent across subplots
399+ # Base width is 0.8 for 4 boxes, scale proportionally for fewer boxes
400+ # Exception: 1077MiB boxes are made thicker since they have fewer boxes
401+ num_boxes = len (current_data )
402+ if chunk_size == 1129316352 : # 1077MiB
403+ box_width = 0.8 # Full width like regular boxplots
404+ else :
405+ box_width = 0.8 * (num_boxes / 4 ) if num_boxes > 0 else 0.8
406+
394407 bp = axes [idx ].boxplot (current_data ,
395408 showfliers = show_outliers ,
396- widths = 0.8 ,
409+ widths = box_width ,
397410 medianprops = dict (linewidth = 2 , color = 'black' ),
398411 patch_artist = True )
399412
400413 # Apply colors and hatches
401414 for i , (box , color , hatch ) in enumerate (zip (bp ['boxes' ], colors , hatches )):
402415 box .set_facecolor (color )
403416 box .set_hatch (hatch )
417+ box .set_hatch_linewidth (3.0 )
404418 box .set_alpha (0.7 )
405419
406420 # Set x-axis labels (empty for cleaner look, or could add device labels)
407421 axes [idx ].set_xticks (range (1 , len (labels ) + 1 ))
408422 axes [idx ].set_xticklabels ([], rotation = 45 , fontsize = 10 )
409423
410424 # Add chunk size label below subplot
411- axes [idx ].set_xlabel (CHUNK_SIZE_LABELS [chunk_size ], fontsize = 16 , weight = 'bold' )
425+ axes [idx ].set_xlabel (CHUNK_SIZE_LABELS [chunk_size ], fontsize = 28 , weight = 'bold' )
426+
427+ # Use scalar formatter without scientific notation
428+ axes [idx ].yaxis .set_major_formatter (ticker .ScalarFormatter (useOffset = False , useMathText = False ))
412429
413430 # Rotate y-axis labels
414431 for label in axes [idx ].get_yticklabels ():
@@ -425,10 +442,10 @@ def generate_distribution_comparison(block_dir, zns_dir, distribution, metric, o
425442 idx += 1
426443
427444 # Add y-axis label on the far left
428- fig .text (0.02 , 0.5 , metric_label , va = 'center' , rotation = 'vertical' , fontsize = 22 , weight = 'bold' )
445+ fig .text (- 0.005 , 0.5 , metric_label , va = 'center' , rotation = 'vertical' , fontsize = 22 , weight = 'bold' )
429446
430447 # Adjust layout (do these BEFORE computing positions) - subplots at 2/5 height with proportional spacing
431- plt .subplots_adjust (wspace = 0.05 , hspace = 0.0 )
448+ plt .subplots_adjust (wspace = 0.2 , hspace = 0.0 )
432449 plt .tight_layout (pad = 0.0 )
433450 plt .subplots_adjust (top = 0.851 , bottom = 0.279 , left = 0.05 )
434451
@@ -452,8 +469,8 @@ def generate_distribution_comparison(block_dir, zns_dir, distribution, metric, o
452469 g2_width = g2_right - g2_left
453470
454471 # Vertical placement of the grey boxes in figure coords
455- box_y = 0.93
456- box_h = 0.06
472+ box_y = 0.85
473+ box_h = 0.10
457474
458475 # Grey box for Ratio 1:2
459476 fig .add_artist (
@@ -492,7 +509,7 @@ def generate_distribution_comparison(block_dir, zns_dir, distribution, metric, o
492509 "Ratio: 1:2" ,
493510 ha = 'center' ,
494511 va = 'center' ,
495- fontsize = 20 ,
512+ fontsize = 26 ,
496513 weight = 'bold' ,
497514 zorder = 2 ,
498515 )
@@ -502,7 +519,7 @@ def generate_distribution_comparison(block_dir, zns_dir, distribution, metric, o
502519 "Ratio: 1:10" ,
503520 ha = 'center' ,
504521 va = 'center' ,
505- fontsize = 20 ,
522+ fontsize = 26 ,
506523 weight = 'bold' ,
507524 zorder = 2 ,
508525 )
0 commit comments