You've already forked coreutils-tracking
mirror of
https://github.com/uutils/coreutils-tracking.git
synced 2026-06-10 16:12:04 -07:00
dedup the code
This commit is contained in:
@@ -9,6 +9,9 @@ import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
import seaborn as sns
|
||||
|
||||
from graph_common import (COLORS, setup_theme, apply_smoothing, style_axes,
|
||||
add_title, style_legend, add_reference_lines)
|
||||
|
||||
if len(sys.argv) <= 2:
|
||||
print("graph.py: <json file> <title>")
|
||||
sys.exit()
|
||||
@@ -22,18 +25,8 @@ df.index = pd.to_datetime(df.index, utc=True)
|
||||
|
||||
print(df)
|
||||
|
||||
# Set modern Seaborn style with enhanced settings
|
||||
sns.set_theme(style="ticks", context="talk", palette="muted")
|
||||
plt.rcParams.update({
|
||||
'font.family': 'sans-serif',
|
||||
'font.sans-serif': ['Inter', 'SF Pro Display', 'Segoe UI', 'Arial'],
|
||||
'axes.facecolor': '#FAFAFA',
|
||||
'figure.facecolor': 'white',
|
||||
'axes.edgecolor': '#CCCCCC',
|
||||
'axes.linewidth': 0.8,
|
||||
'xtick.color': '#555555',
|
||||
'ytick.color': '#555555',
|
||||
})
|
||||
# Set up modern theme
|
||||
setup_theme()
|
||||
|
||||
# Create figure with better proportions and higher DPI
|
||||
fig, ax = plt.subplots(figsize=(18, 9), dpi=100)
|
||||
@@ -53,18 +46,10 @@ df_plot_long = df_plot.melt(id_vars='date', var_name='metric', value_name='count
|
||||
df_plot_long['count'] = pd.to_numeric(df_plot_long['count'], errors='coerce')
|
||||
|
||||
# Apply smoothing using rolling average (window of 15 for smoother lines)
|
||||
df_plot_long['count_smooth'] = df_plot_long.groupby('metric')['count'].transform(
|
||||
lambda x: x.rolling(window=15, min_periods=1, center=True).mean()
|
||||
)
|
||||
df_plot_long['count_smooth'] = apply_smoothing(df_plot_long, 'metric', 'count')
|
||||
|
||||
# Modern vibrant color palette
|
||||
palette = {
|
||||
'total': '#0066CC', # Vibrant blue
|
||||
'pass': '#10B981', # Modern green (Tailwind emerald)
|
||||
'fail': '#EF4444', # Modern red (Tailwind red)
|
||||
'error': '#F59E0B', # Modern amber
|
||||
'skip': '#8B5CF6' # Modern purple (Tailwind violet)
|
||||
}
|
||||
# Use color palette from common module
|
||||
palette = {k: COLORS[k] for k in ['total', 'pass', 'fail', 'error', 'skip']}
|
||||
|
||||
# Add gradient-like area fills first (behind lines)
|
||||
for metric in ['total', 'pass', 'fail']:
|
||||
@@ -87,62 +72,21 @@ sns.lineplot(
|
||||
zorder=3
|
||||
)
|
||||
|
||||
# Modern title with better spacing
|
||||
ax.text(0.5, 1.12, f'uutils coreutils — {title} Test Suite Results',
|
||||
ha='center', va='bottom', transform=ax.transAxes,
|
||||
fontsize=26, fontweight='bold', family='sans-serif', color='#1a1a1a')
|
||||
ax.text(0.5, 1.06, 'Tracking test results over time to measure progress and compatibility',
|
||||
ha='center', va='bottom', transform=ax.transAxes,
|
||||
fontsize=13, color='#6B7280', style='italic', alpha=0.9)
|
||||
# Add title and subtitle
|
||||
add_title(ax, f'uutils coreutils — {title} Test Suite Results',
|
||||
'Tracking test results over time to measure progress and compatibility')
|
||||
|
||||
ax.set_xlabel('Date', fontsize=15, fontweight='600', labelpad=15, color='#374151')
|
||||
ax.set_ylabel('Number of Tests', fontsize=15, fontweight='600', labelpad=15, color='#374151')
|
||||
# Style axes with labels and grid
|
||||
style_axes(ax, xlabel='Date', ylabel='Number of Tests')
|
||||
|
||||
# Modern grid styling with better contrast
|
||||
ax.grid(True, alpha=0.35, linestyle='-', linewidth=1, color='#E5E7EB', which='major', zorder=0)
|
||||
ax.grid(True, alpha=0.15, linestyle=':', linewidth=0.5, color='#F3F4F6', which='minor', zorder=0)
|
||||
ax.set_axisbelow(True)
|
||||
ax.minorticks_on()
|
||||
|
||||
# Add subtle horizontal reference lines at key values
|
||||
# Add reference lines
|
||||
y_max = df_plot_long['count_smooth'].max()
|
||||
if y_max > 100:
|
||||
ax.axhline(y=y_max * 0.75, color='#D1D5DB', linestyle='--', linewidth=0.8, alpha=0.3, zorder=0)
|
||||
ax.axhline(y=y_max * 0.5, color='#D1D5DB', linestyle='--', linewidth=0.8, alpha=0.3, zorder=0)
|
||||
add_reference_lines(ax, y_max)
|
||||
|
||||
# Modern legend styling
|
||||
# Style legend
|
||||
handles, labels = ax.get_legend_handles_labels()
|
||||
# Capitalize labels
|
||||
labels = [label.capitalize() for label in labels]
|
||||
legend = ax.legend(handles, labels, loc='upper left', frameon=True,
|
||||
fancybox=False, shadow=False, ncol=len(plot_columns),
|
||||
bbox_to_anchor=(0, 1.04), fontsize=13,
|
||||
edgecolor='#D1D5DB', framealpha=0.98,
|
||||
borderpad=1.2, labelspacing=0.8, columnspacing=2)
|
||||
legend.get_frame().set_facecolor('#FFFFFF')
|
||||
legend.get_frame().set_linewidth(2)
|
||||
legend.get_frame().set_boxstyle('round,pad=0.5')
|
||||
|
||||
# Format x-axis dates
|
||||
plt.xticks(rotation=45, ha='right')
|
||||
ax.margins(x=0.01)
|
||||
ax.set_ylim(bottom=0)
|
||||
|
||||
# Modern spine styling
|
||||
sns.despine(ax=ax, top=True, right=True, left=False, bottom=False, offset=8)
|
||||
ax.spines['left'].set_linewidth(2)
|
||||
ax.spines['bottom'].set_linewidth(2)
|
||||
ax.spines['left'].set_color('#9CA3AF')
|
||||
ax.spines['bottom'].set_color('#9CA3AF')
|
||||
|
||||
# Modern gradient-like background
|
||||
ax.patch.set_facecolor('#FAFAFA')
|
||||
ax.patch.set_alpha(0.6)
|
||||
|
||||
# Add a subtle shadow effect
|
||||
ax.add_patch(plt.Rectangle((0, 0), 1, 1, transform=ax.transAxes,
|
||||
facecolor='none', edgecolor='#E5E7EB',
|
||||
linewidth=3, zorder=-1))
|
||||
style_legend(ax, handles, labels, ncol=len(plot_columns), loc='upper left')
|
||||
|
||||
# Tight layout
|
||||
plt.tight_layout()
|
||||
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
# This file is part of the uutils coreutils package.
|
||||
#
|
||||
# For the full copyright and license information, please view the LICENSE
|
||||
# file that was distributed with this source code.
|
||||
|
||||
"""Common styling and utilities for graph generation."""
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import seaborn as sns
|
||||
|
||||
|
||||
# Modern vibrant color palette
|
||||
COLORS = {
|
||||
'total': '#0066CC', # Vibrant blue
|
||||
'pass': '#10B981', # Modern green (Tailwind emerald)
|
||||
'fail': '#EF4444', # Modern red (Tailwind red)
|
||||
'error': '#F59E0B', # Modern amber
|
||||
'skip': '#8B5CF6', # Modern purple (Tailwind violet)
|
||||
'size': '#6366F1', # Modern indigo
|
||||
'multisize': '#10B981', # Modern green (Tailwind emerald)
|
||||
'default': '#10B981', # Modern green (Tailwind emerald)
|
||||
}
|
||||
|
||||
|
||||
def setup_theme():
|
||||
"""Set up modern Seaborn theme with enhanced settings."""
|
||||
sns.set_theme(style="ticks", context="talk", palette="muted")
|
||||
plt.rcParams.update({
|
||||
'font.family': 'sans-serif',
|
||||
'font.sans-serif': ['Inter', 'SF Pro Display', 'Segoe UI', 'Arial'],
|
||||
'axes.facecolor': '#FAFAFA',
|
||||
'figure.facecolor': 'white',
|
||||
'axes.edgecolor': '#CCCCCC',
|
||||
'axes.linewidth': 0.8,
|
||||
'xtick.color': '#555555',
|
||||
'ytick.color': '#555555',
|
||||
})
|
||||
|
||||
|
||||
def apply_smoothing(df, group_col, value_col, window=15):
|
||||
"""Apply rolling average smoothing to data.
|
||||
|
||||
Args:
|
||||
df: DataFrame with data to smooth
|
||||
group_col: Column name to group by (or None for no grouping)
|
||||
value_col: Column name containing values to smooth
|
||||
window: Rolling window size (default: 15)
|
||||
|
||||
Returns:
|
||||
Series with smoothed values
|
||||
"""
|
||||
if group_col:
|
||||
return df.groupby(group_col)[value_col].transform(
|
||||
lambda x: x.rolling(window=window, min_periods=1, center=True).mean()
|
||||
)
|
||||
else:
|
||||
return df[value_col].rolling(window=window, min_periods=1, center=True).mean()
|
||||
|
||||
|
||||
def style_axes(ax, xlabel='Date', ylabel='Value'):
|
||||
"""Apply modern styling to axes.
|
||||
|
||||
Args:
|
||||
ax: Matplotlib axes object
|
||||
xlabel: Label for x-axis
|
||||
ylabel: Label for y-axis
|
||||
"""
|
||||
ax.set_xlabel(xlabel, fontsize=15, fontweight='600', labelpad=15, color='#374151')
|
||||
ax.set_ylabel(ylabel, fontsize=15, fontweight='600', labelpad=15, color='#374151')
|
||||
|
||||
# Modern grid styling
|
||||
ax.grid(True, alpha=0.35, linestyle='-', linewidth=1, color='#E5E7EB', which='major', zorder=0)
|
||||
ax.grid(True, alpha=0.15, linestyle=':', linewidth=0.5, color='#F3F4F6', which='minor', zorder=0)
|
||||
ax.set_axisbelow(True)
|
||||
ax.minorticks_on()
|
||||
|
||||
# Format x-axis dates
|
||||
plt.xticks(rotation=45, ha='right')
|
||||
ax.margins(x=0.01)
|
||||
ax.set_ylim(bottom=0)
|
||||
|
||||
# Modern spine styling
|
||||
sns.despine(ax=ax, top=True, right=True, left=False, bottom=False, offset=8)
|
||||
ax.spines['left'].set_linewidth(2)
|
||||
ax.spines['bottom'].set_linewidth(2)
|
||||
ax.spines['left'].set_color('#9CA3AF')
|
||||
ax.spines['bottom'].set_color('#9CA3AF')
|
||||
|
||||
# Modern background
|
||||
ax.patch.set_facecolor('#FAFAFA')
|
||||
ax.patch.set_alpha(0.6)
|
||||
|
||||
# Add subtle shadow effect
|
||||
ax.add_patch(plt.Rectangle((0, 0), 1, 1, transform=ax.transAxes,
|
||||
facecolor='none', edgecolor='#E5E7EB',
|
||||
linewidth=3, zorder=-1))
|
||||
|
||||
|
||||
def add_title(ax, title, subtitle=None):
|
||||
"""Add modern title and optional subtitle to axes.
|
||||
|
||||
Args:
|
||||
ax: Matplotlib axes object
|
||||
title: Main title text
|
||||
subtitle: Optional subtitle text
|
||||
"""
|
||||
ax.text(0.5, 1.12, title,
|
||||
ha='center', va='bottom', transform=ax.transAxes,
|
||||
fontsize=26, fontweight='bold', family='sans-serif', color='#1a1a1a')
|
||||
|
||||
if subtitle:
|
||||
ax.text(0.5, 1.06, subtitle,
|
||||
ha='center', va='bottom', transform=ax.transAxes,
|
||||
fontsize=13, color='#6B7280', style='italic', alpha=0.9)
|
||||
|
||||
|
||||
def style_legend(ax, handles, labels, ncol=1, loc='upper left'):
|
||||
"""Apply modern styling to legend.
|
||||
|
||||
Args:
|
||||
ax: Matplotlib axes object
|
||||
handles: Legend handles
|
||||
labels: Legend labels
|
||||
ncol: Number of columns (default: 1)
|
||||
loc: Legend location (default: 'upper left')
|
||||
|
||||
Returns:
|
||||
Legend object
|
||||
"""
|
||||
legend = ax.legend(handles, labels, loc=loc, frameon=True,
|
||||
fancybox=False, shadow=False, ncol=ncol,
|
||||
bbox_to_anchor=(0, 1.04) if 'left' in loc else (1, 1.04),
|
||||
fontsize=13,
|
||||
edgecolor='#D1D5DB', framealpha=0.98,
|
||||
borderpad=1.2, labelspacing=0.8, columnspacing=2)
|
||||
legend.get_frame().set_facecolor('#FFFFFF')
|
||||
legend.get_frame().set_linewidth(2)
|
||||
legend.get_frame().set_boxstyle('round,pad=0.5')
|
||||
return legend
|
||||
|
||||
|
||||
def add_reference_lines(ax, y_max):
|
||||
"""Add horizontal reference lines at key values.
|
||||
|
||||
Args:
|
||||
ax: Matplotlib axes object
|
||||
y_max: Maximum y value for calculating reference positions
|
||||
"""
|
||||
if y_max > 100:
|
||||
ax.axhline(y=y_max * 0.75, color='#D1D5DB', linestyle='--', linewidth=0.8, alpha=0.3, zorder=0)
|
||||
ax.axhline(y=y_max * 0.5, color='#D1D5DB', linestyle='--', linewidth=0.8, alpha=0.3, zorder=0)
|
||||
+14
-52
@@ -10,26 +10,19 @@ import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
import seaborn as sns
|
||||
|
||||
from graph_common import (COLORS, setup_theme, apply_smoothing, style_axes,
|
||||
add_title)
|
||||
|
||||
df = pd.read_json(sys.argv[1], orient="index")
|
||||
df.index = pd.to_datetime(df.index, utc=True)
|
||||
|
||||
Path("individual-size-results").mkdir(exist_ok=True)
|
||||
|
||||
# Set modern Seaborn style with enhanced settings
|
||||
sns.set_theme(style="ticks", context="talk", palette="muted")
|
||||
plt.rcParams.update({
|
||||
'font.family': 'sans-serif',
|
||||
'font.sans-serif': ['Inter', 'SF Pro Display', 'Segoe UI', 'Arial'],
|
||||
'axes.facecolor': '#FAFAFA',
|
||||
'figure.facecolor': 'white',
|
||||
'axes.edgecolor': '#CCCCCC',
|
||||
'axes.linewidth': 0.8,
|
||||
'xtick.color': '#555555',
|
||||
'ytick.color': '#555555',
|
||||
})
|
||||
# Set up modern theme
|
||||
setup_theme()
|
||||
|
||||
# Modern color for size evolution
|
||||
size_color = '#10B981' # Modern green (Tailwind emerald)
|
||||
# Use color from common module
|
||||
size_color = COLORS['default']
|
||||
|
||||
for name, series in df["sizes"].apply(pd.Series).items():
|
||||
# Filter out None values which indicate missing data for 'name'
|
||||
@@ -45,11 +38,11 @@ for name, series in df["sizes"].apply(pd.Series).items():
|
||||
# Prepare data for Seaborn
|
||||
plot_data = pd.DataFrame({
|
||||
'date': sizes.index,
|
||||
'size': pd.to_numeric(sizes['size'], errors='coerce')
|
||||
'size': pd.to_numeric(sizes.values, errors='coerce')
|
||||
})
|
||||
|
||||
# Apply smoothing using rolling average
|
||||
plot_data['size_smooth'] = plot_data['size'].rolling(window=15, min_periods=1, center=True).mean()
|
||||
plot_data['size_smooth'] = apply_smoothing(plot_data, None, 'size')
|
||||
|
||||
# Add gradient-like area fill first
|
||||
ax.fill_between(plot_data['date'], 0, plot_data['size'],
|
||||
@@ -68,43 +61,12 @@ for name, series in df["sizes"].apply(pd.Series).items():
|
||||
zorder=3
|
||||
)
|
||||
|
||||
# Modern title
|
||||
ax.text(0.5, 1.12, f'uutils coreutils — "{name}" Binary Size',
|
||||
ha='center', va='bottom', transform=ax.transAxes,
|
||||
fontsize=26, fontweight='bold', family='sans-serif', color='#1a1a1a')
|
||||
ax.text(0.5, 1.06, f'Individual utility size tracking over development history',
|
||||
ha='center', va='bottom', transform=ax.transAxes,
|
||||
fontsize=13, color='#6B7280', style='italic', alpha=0.9)
|
||||
# Add title and subtitle
|
||||
add_title(ax, f'uutils coreutils — "{name}" Binary Size',
|
||||
'Individual utility size tracking over development history')
|
||||
|
||||
ax.set_xlabel('Date', fontsize=15, fontweight='600', labelpad=15, color='#374151')
|
||||
ax.set_ylabel('Size (kilobytes)', fontsize=15, fontweight='600', labelpad=15, color='#374151')
|
||||
|
||||
# Modern grid styling
|
||||
ax.grid(True, alpha=0.35, linestyle='-', linewidth=1, color='#E5E7EB', which='major', zorder=0)
|
||||
ax.grid(True, alpha=0.15, linestyle=':', linewidth=0.5, color='#F3F4F6', which='minor', zorder=0)
|
||||
ax.set_axisbelow(True)
|
||||
ax.minorticks_on()
|
||||
|
||||
# Format x-axis dates
|
||||
plt.xticks(rotation=45, ha='right')
|
||||
ax.margins(x=0.01)
|
||||
ax.set_ylim(bottom=0)
|
||||
|
||||
# Modern spine styling
|
||||
sns.despine(ax=ax, top=True, right=True, left=False, bottom=False, offset=8)
|
||||
ax.spines['left'].set_linewidth(2)
|
||||
ax.spines['bottom'].set_linewidth(2)
|
||||
ax.spines['left'].set_color('#9CA3AF')
|
||||
ax.spines['bottom'].set_color('#9CA3AF')
|
||||
|
||||
# Modern background
|
||||
ax.patch.set_facecolor('#FAFAFA')
|
||||
ax.patch.set_alpha(0.6)
|
||||
|
||||
# Add subtle shadow effect
|
||||
ax.add_patch(plt.Rectangle((0, 0), 1, 1, transform=ax.transAxes,
|
||||
facecolor='none', edgecolor='#E5E7EB',
|
||||
linewidth=3, zorder=-1))
|
||||
# Style axes with labels and grid
|
||||
style_axes(ax, xlabel='Date', ylabel='Size (kilobytes)')
|
||||
|
||||
# Tight layout
|
||||
plt.tight_layout()
|
||||
|
||||
+16
-63
@@ -9,6 +9,9 @@ import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
import seaborn as sns
|
||||
|
||||
from graph_common import (COLORS, setup_theme, apply_smoothing, style_axes,
|
||||
add_title, style_legend)
|
||||
|
||||
d = pd.read_json(sys.argv[1], orient="index")
|
||||
df = pd.DataFrame(d)
|
||||
|
||||
@@ -17,18 +20,8 @@ df.index = pd.to_datetime(df.index, utc=True, format="mixed")
|
||||
|
||||
print(df)
|
||||
|
||||
# Set modern Seaborn style with enhanced settings
|
||||
sns.set_theme(style="ticks", context="talk", palette="muted")
|
||||
plt.rcParams.update({
|
||||
'font.family': 'sans-serif',
|
||||
'font.sans-serif': ['Inter', 'SF Pro Display', 'Segoe UI', 'Arial'],
|
||||
'axes.facecolor': '#FAFAFA',
|
||||
'figure.facecolor': 'white',
|
||||
'axes.edgecolor': '#CCCCCC',
|
||||
'axes.linewidth': 0.8,
|
||||
'xtick.color': '#555555',
|
||||
'ytick.color': '#555555',
|
||||
})
|
||||
# Set up modern theme
|
||||
setup_theme()
|
||||
|
||||
# Create figure with better proportions and higher DPI
|
||||
fig, ax = plt.subplots(figsize=(18, 9), dpi=100)
|
||||
@@ -43,14 +36,12 @@ df_plot_long = df_plot.melt(id_vars='date', var_name='binary_type', value_name='
|
||||
df_plot_long['size_kb'] = pd.to_numeric(df_plot_long['size_kb'], errors='coerce')
|
||||
|
||||
# Apply smoothing using rolling average
|
||||
df_plot_long['size_kb_smooth'] = df_plot_long.groupby('binary_type')['size_kb'].transform(
|
||||
lambda x: x.rolling(window=15, min_periods=1, center=True).mean()
|
||||
)
|
||||
df_plot_long['size_kb_smooth'] = apply_smoothing(df_plot_long, 'binary_type', 'size_kb')
|
||||
|
||||
# Modern color palette
|
||||
# Use color palette from common module
|
||||
palette = {
|
||||
'size': '#6366F1', # Modern indigo
|
||||
'multisize': '#10B981' # Modern green (Tailwind emerald)
|
||||
'size': COLORS['size'],
|
||||
'multisize': COLORS['multisize']
|
||||
}
|
||||
|
||||
# Add gradient-like area fills first
|
||||
@@ -74,59 +65,21 @@ sns.lineplot(
|
||||
zorder=3
|
||||
)
|
||||
|
||||
# Modern title
|
||||
ax.text(0.5, 1.12, 'uutils coreutils — Binary Size Evolution',
|
||||
ha='center', va='bottom', transform=ax.transAxes,
|
||||
fontsize=26, fontweight='bold', family='sans-serif', color='#1a1a1a')
|
||||
ax.text(0.5, 1.06, 'Tracking binary size optimization and comparing build strategies',
|
||||
ha='center', va='bottom', transform=ax.transAxes,
|
||||
fontsize=13, color='#6B7280', style='italic', alpha=0.9)
|
||||
# Add title and subtitle
|
||||
add_title(ax, 'uutils coreutils — Binary Size Evolution',
|
||||
'Tracking binary size optimization and comparing build strategies')
|
||||
|
||||
ax.set_xlabel('Date', fontsize=15, fontweight='600', labelpad=15, color='#374151')
|
||||
ax.set_ylabel('Size (kilobytes)', fontsize=15, fontweight='600', labelpad=15, color='#374151')
|
||||
# Style axes with labels and grid
|
||||
style_axes(ax, xlabel='Date', ylabel='Size (kilobytes)')
|
||||
|
||||
# Modern grid styling
|
||||
ax.grid(True, alpha=0.35, linestyle='-', linewidth=1, color='#E5E7EB', which='major', zorder=0)
|
||||
ax.grid(True, alpha=0.15, linestyle=':', linewidth=0.5, color='#F3F4F6', which='minor', zorder=0)
|
||||
ax.set_axisbelow(True)
|
||||
ax.minorticks_on()
|
||||
|
||||
# Modern legend
|
||||
# Style legend
|
||||
handles, labels = ax.get_legend_handles_labels()
|
||||
label_map = {
|
||||
'size': 'Multiple Binaries',
|
||||
'multisize': 'Multicall Binary (Optimized)'
|
||||
}
|
||||
labels = [label_map.get(label, label) for label in labels]
|
||||
legend = ax.legend(handles, labels, loc='upper left', frameon=True,
|
||||
fancybox=False, shadow=False, fontsize=13,
|
||||
bbox_to_anchor=(0, 1.04),
|
||||
edgecolor='#D1D5DB', framealpha=0.98,
|
||||
borderpad=1.2, labelspacing=0.8)
|
||||
legend.get_frame().set_facecolor('#FFFFFF')
|
||||
legend.get_frame().set_linewidth(2)
|
||||
legend.get_frame().set_boxstyle('round,pad=0.5')
|
||||
|
||||
# Format x-axis dates
|
||||
plt.xticks(rotation=45, ha='right')
|
||||
ax.margins(x=0.01)
|
||||
ax.set_ylim(bottom=0)
|
||||
|
||||
# Modern spine styling
|
||||
sns.despine(ax=ax, top=True, right=True, left=False, bottom=False, offset=8)
|
||||
ax.spines['left'].set_linewidth(2)
|
||||
ax.spines['bottom'].set_linewidth(2)
|
||||
ax.spines['left'].set_color('#9CA3AF')
|
||||
ax.spines['bottom'].set_color('#9CA3AF')
|
||||
|
||||
# Modern background
|
||||
ax.patch.set_facecolor('#FAFAFA')
|
||||
ax.patch.set_alpha(0.6)
|
||||
|
||||
# Add subtle shadow effect
|
||||
ax.add_patch(plt.Rectangle((0, 0), 1, 1, transform=ax.transAxes,
|
||||
facecolor='none', edgecolor='#E5E7EB',
|
||||
linewidth=3, zorder=-1))
|
||||
style_legend(ax, handles, labels, ncol=1, loc='upper left')
|
||||
|
||||
# Tight layout
|
||||
plt.tight_layout()
|
||||
|
||||
Reference in New Issue
Block a user