Show code
target_date = None # Set via papermill, or auto-detect from manifestAnalysis of blob inclusion patterns in Ethereum mainnet blocks.
target_date = None # Set via papermill, or auto-detect from manifest# Injected Parameters
target_date = "2025-12-07"import altair as alt
import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from loaders import load_parquet
alt.theme.enable("carbonwhite")ThemeRegistry.enable('carbonwhite')
Each dot represents a slot, colored by the number of blobs included (0–9). This shows the temporal distribution of blob activity—gaps indicate missed slots or blocks without blobs.
df_blobs_per_slot = load_parquet("blobs_per_slot", target_date)
fig = px.scatter(
df_blobs_per_slot,
x="time",
y="blob_count",
color="blob_count",
color_continuous_scale="YlOrRd",
title="Blobs per slot",
labels={"time": "Time", "blob_count": "Blob Count"},
template="plotly",
)
fig.update_layout(
showlegend=False,
yaxis=dict(dtick=1, range=[-0.5, 15.5]),
coloraxis_colorbar=dict(title="Blobs"),
height=600,
)
fig.update_traces(marker=dict(size=3))
fig.show()Stacked bar chart showing how blocks within each epoch are distributed by blob count. Each bar represents one epoch (32 slots), with colors indicating the number of blobs in each block.
df_blocks_blob_epoch = load_parquet("blocks_blob_epoch", target_date)
chart = (
alt.Chart(df_blocks_blob_epoch)
.mark_bar()
.encode(
x=alt.X("time:T", title="Epoch Start Time"),
y=alt.Y("block_count:Q", title="Block Count", stack="zero", scale=alt.Scale(domain=[0, 32]), axis=alt.Axis(tickCount=32, labelAngle=-45)),
color=alt.Color(
"series:N",
title="Blob Count",
sort="ascending",
scale=alt.Scale(scheme="inferno"),
),
order=alt.Order("series:N", sort="ascending"),
tooltip=["time:T", "series:N", "block_count:Q"],
)
.properties(title="Blocks with blob counts per epoch", width=1000, height=600)
)
chartHeatmap showing which blob counts are most common over time. Brighter cells indicate more blocks with that blob count during the epoch. Useful for spotting trends in blob usage patterns.
df_blob_popularity = load_parquet("blob_popularity", target_date)
# Pivot for heatmap
df_pivot = df_blob_popularity.pivot(index="blob_count", columns="time", values="count").fillna(0)
fig = go.Figure(
data=go.Heatmap(
z=df_pivot.values,
x=df_pivot.columns,
y=[str(int(b)) for b in df_pivot.index],
colorscale="inferno",
reversescale=False,
colorbar=dict(title="Block Count"),
),
)
fig.update_layout(
template="plotly_white",
title="Blob count popularity by epoch",
xaxis_title="Epoch Start Time",
yaxis_title="Blob Count",
height=500,
)
fig.show()Detailed view of blob counts for each slot position (0–31) within epochs. Each row is an epoch, each column is a slot position. Reveals patterns like whether certain slot positions consistently have more or fewer blobs.
df_slot_in_epoch = load_parquet("slot_in_epoch", target_date)
df_pivot = df_slot_in_epoch.pivot(index="slot_in_epoch", columns="time", values="blob_count").fillna(0)
fig = go.Figure(
data=go.Heatmap(
z=df_pivot.values.T,
x=[str(int(s)) for s in df_pivot.index],
y=df_pivot.columns,
colorscale="thermal",
reversescale=True,
colorbar=dict(
orientation="h",
y=-0.075,
yanchor="top",
x=0,
xanchor="left",
len=1,
),
)
)
fig.update_layout(
title="Blob count per slot within epoch",
xaxis_title="Slot in Epoch",
yaxis_title="Epoch Start Time",
yaxis=dict(autorange="reversed"),
height=1500,
width=500,
)
fig.show()Same data as above but arranged horizontally for easier comparison across longer time ranges. Epochs are stacked in columns, making it easier to see temporal evolution.
df_pivot = df_slot_in_epoch.pivot(index="slot_in_epoch", columns="time", values="blob_count").fillna(0)
# Parameters
n_columns = 4
n_rows = len(df_pivot.columns)
rows_per_chunk = n_rows // n_columns
# Reshape: stack chunks horizontally
chunks = []
for i in range(n_columns):
chunk = df_pivot.T.iloc[i*rows_per_chunk:(i+1)*rows_per_chunk, :]
chunk = chunk.reset_index(drop=True)
chunks.append(chunk)
# Concatenate horizontally (side by side)
df_combined = pd.concat(chunks, axis=1, ignore_index=True)
# Create x-axis labels with dividers
n_slots = len(df_pivot.index)
x_labels = list(range(n_slots)) * n_columns
y_labels = []
for row_idx in range(rows_per_chunk):
time_val = df_pivot.columns[row_idx]
y_labels.append(str(time_val))
fig = go.Figure(
data=go.Heatmap(
z=df_combined.values,
x=list(range(len(df_combined.columns))),
y=y_labels,
colorscale="thermal",
reversescale=True,
colorbar=dict(
orientation="h",
y=-0.15,
yanchor="top",
x=0.5,
xanchor="center",
len=0.8,
),
)
)
# Add vertical dividers between chunks
for i in range(1, n_columns):
fig.add_vline(
x=i * n_slots - 0.5,
line_width=2,
line_color="white",
)
fig.update_layout(
title="Blob count per slot within epoch",
xaxis_title="Slot in Epoch",
yaxis_title="Epoch",
yaxis=dict(autorange="reversed"),
xaxis=dict(
tickvals=list(range(len(df_combined.columns))),
ticktext=[str(i % n_slots) for i in range(len(df_combined.columns))],
tickangle=90,
tickfont=dict(size=6),
),
height=600,
width=1200,
)
fig.show()