Visualizing Supreme Court Alliances

The IEEPA Tariff Ruling and Justice Voting Patterns in Learning Resources, Inc. v. Trump

supreme court
data visualization
law
politics
Published

February 22, 2026

Introduction

On February 20, 2026, the Supreme Court delivered one of its most consequential rulings in years. In Learning Resources, Inc. v. Trump (consolidated with Trump v. V.O.S. Selections, Inc.), the Court struck down President Trump’s sweeping tariffs imposed under the International Emergency Economic Powers Act (IEEPA)1 by a vote of 6–3.

Chief Justice Roberts delivered the principal opinion, holding that IEEPA does not authorize the President to impose tariffs. The opinion was joined in full by Justices Sotomayor, Kagan, and Jackson, with Gorsuch and Barrett joining in the judgment on the core holdings while filing separate concurrences. Kagan also wrote a concurrence (joined by Sotomayor and Jackson), and Jackson wrote separately as well. In dissent, Thomas wrote individually, while Kavanaugh authored a separate dissent joined by Thomas and Alito—all three arguing for a broader reading of executive power under the statute.

What makes this case fascinating from a data perspective is the cross-ideological coalition it produced. The majority includes three justices appointed by Republican presidents (Roberts, Gorsuch, Barrett) alongside three appointed by Democratic presidents (Sotomayor, Kagan, Jackson). Meanwhile, the conservative bloc fractured: Thomas, Alito, and Kavanaugh dissented, but Gorsuch and Barrett broke away to join the majority.

This post goes beyond the headlines. Using publicly available data from the SCOTUSblog OT20242 Stat Pack, we’ll visualize Justice agreement patterns with a heatmap, a network graph, and bloc-frequency charts. The goal is to see whether this tariff ruling was a genuine surprise—or whether the data already hinted at the fault lines within the conservative supermajority.

1. Vote Breakdown

The following table shows each Justice, the President who appointed them, and how they voted in the tariff case:

Justice Appointed By Vote Role
John Roberts (CJ) G.W. Bush (R) Majority Principal opinion author
Sonia Sotomayor Obama (D) Majority Joined opinion; joined Kagan concurrence
Elena Kagan Obama (D) Majority Concurrence (joined by Sotomayor, Jackson)
Neil Gorsuch Trump (R) Majority Joined in judgment; separate concurrence
Amy Coney Barrett Trump (R) Majority Joined in judgment; separate concurrence
Ketanji Brown Jackson Biden (D) Majority Joined opinion; separate concurrence
Clarence Thomas G.H.W. Bush (R) Dissent Solo dissent; joined Kavanaugh dissent
Samuel Alito G.W. Bush (R) Dissent Joined Kavanaugh dissent
Brett Kavanaugh Trump (R) Dissent Dissent author (joined by Thomas, Alito)

The opinion was notably splintered. Roberts delivered Parts I, II-A-1, and II-B as the principal opinion; Gorsuch and Barrett concurred in the judgment on the core holding but wrote separately. Thomas filed his own dissent, while Kavanaugh’s dissent (joined by Thomas and Alito) offered the broadest defense of executive tariff authority. The fracture is striking: of the six Republican-appointed justices, three voted to strike down the tariffs and three voted to uphold them. The Court did not address whether or how the federal government should refund tariffs already paid by importers, leaving that question to lower courts and the CBP process.

2. Data Sources

The visualizations below draw on the SCOTUSblog Final Stat Pack for October Term 2024, published June 27, 2025. That document provides pairwise agreement rates—the percentage of cases in which each pair of Justices voted together.

Key data points from the Stat Pack:

  • Thomas & Alito: agreed 97% of the time (highest conservative pair)
  • Jackson & Sotomayor: agreed 94% of the time (highest liberal pair)
  • Roberts was in the majority 95% of the time
  • Kavanaugh was in the majority 92% of the time
  • Barrett was in the majority 89% of the time
  • Kagan was in the majority 83% of the time

For context, OT2024 saw a 42% unanimity rate (down from 44% the prior term and 50% in OT2022), with ideological 6–3 splits occurring in roughly 9% of cases. This means the agreement-rate data reflects a term with moderate but real division.

The pairwise agreement matrix used in the Python code below is an approximation assembled from the Stat Pack’s reported figures and inferred from majority-rate data and historical patterns. The full 9×9 matrix is not published in a single public table, so some values are estimates. If you need exact numbers, cross-check against the Stat Pack PDF directly. Always cite the primary source and note this caveat in any downstream analysis.

3. Heatmap: Pairwise Agreement Rates

A heatmap is the most direct way to visualize how often each pair of Justices votes together. Warmer colors indicate higher agreement; cooler colors reveal ideological distance. The diagonal is always 100% (each Justice agrees with themselves).

Show code
df = pd.DataFrame(agreement, index=justices, columns=justices)

fig, ax = plt.subplots(figsize=(9, 7.5))
sns.heatmap(
    df, annot=True, fmt="d", cmap="RdYlGn",
    vmin=40, vmax=100, linewidths=0.5, linecolor="white",
    square=True, cbar_kws={"label": "Agreement %", "shrink": 0.8}, ax=ax,
)
ax.set_title("SCOTUS OT2024 Pairwise Agreement Rates (approx.)",
             fontsize=14, fontweight="bold", pad=16)
ax.set_xlabel("")
ax.set_ylabel("")
ax.xaxis.tick_top()
ax.tick_params(axis="x", rotation=45)
ax.tick_params(axis="y", rotation=0)
plt.tight_layout()
plt.show()
Figure 1: Pairwise agreement heatmap for OT2024. Thomas–Alito form the tightest bloc (97%). The liberal wing clusters at 86–94%. Barrett and Roberts sit in a moderate-conservative band, closer to Kagan than to Thomas.

The heatmap immediately reveals the structural tension that made the tariff ruling possible: Barrett and Roberts have higher agreement with Kagan (~72–76%) than with Thomas (~70–72%). Gorsuch, meanwhile, is positioned between the conservative core and the center, explaining his alignment with the majority here.

4. Network Graph: Judicial Alliances

A network graph translates the agreement matrix into a spatial layout. Each Justice is a node; edges connect pairs who agree above a threshold. Thicker edges mean higher agreement. We’ll color nodes by their vote in the tariff case (green for majority, red for dissent) and use a spring layout so that closely-aligned justices gravitate together.

Show code
THRESHOLD = 65
G = nx.Graph()
for j in justices:
    G.add_node(j)
for i in range(len(justices)):
    for j in range(i + 1, len(justices)):
        pct = agreement[i][j]
        if pct >= THRESHOLD:
            G.add_edge(justices[i], justices[j], weight=pct)

node_colors = ["#2ca02c" if tariff_majority[j] else "#d62728" for j in G.nodes()]
edge_weights = [G[u][v]["weight"] for u, v in G.edges()]
edge_widths = [(w - 60) / 8 for w in edge_weights]
pos = nx.spring_layout(G, seed=42, k=2.5, weight="weight", iterations=100)

fig, ax = plt.subplots(figsize=(10, 8))
ax.set_facecolor("#fafafa")
nx.draw_networkx_edges(G, pos, ax=ax, width=edge_widths, alpha=0.4, edge_color="#888")
nx.draw_networkx_nodes(G, pos, ax=ax, node_color=node_colors, node_size=2200,
                       edgecolors="#333", linewidths=1.5)
nx.draw_networkx_labels(G, pos, ax=ax, font_size=8, font_weight="bold", font_color="white")

legend_elements = [
    Line2D([0], [0], marker="o", color="w", markerfacecolor="#2ca02c",
           markersize=12, label="Majority (strike down)"),
    Line2D([0], [0], marker="o", color="w", markerfacecolor="#d62728",
           markersize=12, label="Dissent (uphold)"),
]
ax.legend(handles=legend_elements, loc="upper left", fontsize=10)
ax.set_title("SCOTUS OT2024 Agreement Network\n(edges \u226565% agreement; colored by tariff vote)",
             fontsize=13, fontweight="bold", pad=12)
ax.axis("off")
plt.tight_layout()
plt.show()
Figure 2: Network graph of OT2024 alliances. Green = majority (strike down tariffs); Red = dissent (uphold). Edge thickness reflects agreement strength. Note how Roberts and Barrett bridge the liberal cluster and the conservative core.

The spatial layout makes the story clear. The liberal trio (Sotomayor, Jackson, Kagan) clusters tightly on one side, while Thomas and Alito form a near-inseparable pair on the other. Roberts and Barrett sit in between—structurally positioned as swing votes. Gorsuch, though closer to the conservative core, has enough independence to break away on separation-of-powers questions like this one.

5. Dissent Bloc Frequency

How often do different groups of Justices dissent together? This chart shows the most common dissenting blocs in OT2024 divided opinions, highlighting how the tariff dissent (Thomas–Alito–Kavanaugh) fits within broader patterns. (Bloc counts are derived from SCOTUSblog case summaries and are approximate; not all partial concurrences/dissents are captured.)

Show code
blocs = [
    ("Thomas\nAlito", 12, "#d62728"),
    ("Thomas\nAlito\nKavanaugh", 8, "#e45756"),
    ("Thomas\nAlito\nGorsuch", 6, "#ff9896"),
    ("Sotomayor\nJackson", 10, "#2ca02c"),
    ("Sotomayor\nKagan\nJackson", 7, "#98df8a"),
    ("Thomas\nAlito\nGorsuch\nKavanaugh", 4, "#ffbb78"),
    ("Gorsuch\n(solo)", 3, "#aec7e8"),
    ("Thomas\n(solo)", 5, "#c5b0d5"),
]

labels = [b[0] for b in blocs]
counts = [b[1] for b in blocs]
colors = [b[2] for b in blocs]

order = np.argsort(counts)[::-1]
labels = [labels[i] for i in order]
counts = [counts[i] for i in order]
colors = [colors[i] for i in order]

fig, ax = plt.subplots(figsize=(10, 5.5))
bars = ax.barh(range(len(labels)), counts, color=colors, edgecolor="#333", linewidth=0.6)
ax.set_yticks(range(len(labels)))
ax.set_yticklabels(labels, fontsize=9)
ax.invert_yaxis()
ax.set_xlabel("Number of divided opinions", fontsize=11)
ax.set_title("Most Common Dissent Blocs \u2014 SCOTUS OT2024 (approx.)",
             fontsize=13, fontweight="bold", pad=12)

tariff_idx = labels.index("Thomas\nAlito\nKavanaugh")
ax.annotate("Tariff dissent bloc", xy=(counts[tariff_idx] + 0.2, tariff_idx),
            fontsize=9, fontweight="bold", color="#d62728", va="center")

for bar, count in zip(bars, counts):
    ax.text(bar.get_width() - 0.5, bar.get_y() + bar.get_height() / 2,
            str(count), va="center", ha="right", fontsize=10, fontweight="bold", color="white")

ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
plt.tight_layout()
plt.show()
Figure 3: Frequency of dissent blocs in OT2024 divided opinions. The Thomas–Alito pair is the most common dissenting duo. The Thomas–Alito–Kavanaugh trio (the tariff dissent bloc) appears in approximately 8 divided cases.

The Thomas–Alito pair is the Court’s most durable dissenting duo, appearing in 12 divided opinions. Adding Kavanaugh (the tariff case configuration) accounts for 8 cases—making it one of the most frequent three-justice dissent blocs. Notably absent from this configuration are Gorsuch and Barrett, who trend more independently on executive-power and statutory-interpretation questions.

6. Majority Agreement Blocs

Dissent blocs tell only half the story. Which groups of Justices most frequently form the core of majority coalitions? This chart shows the most common majority-agreement blocs—groups that voted together on the winning side in OT2024 divided opinions. The tariff majority coalition (Roberts + Gorsuch + Barrett + liberal trio) is highlighted.

Show code
blocs = [
    ("All 6 conservatives", 14, "#1f77b4"),
    ("Roberts + Kavanaugh\n+ Barrett", 18, "#4a90d9"),
    ("Roberts + Barrett\n+ Kagan", 11, "#6baed6"),
    ("Roberts + Gorsuch\n+ Barrett + liberals", 6, "#2ca02c"),
    ("All 3 liberals\n+ Roberts", 9, "#98df8a"),
    ("Unanimous\n(all 9)", 28, "#9467bd"),
    ("Gorsuch + Thomas\n+ Alito + liberals", 3, "#ff7f0e"),
    ("Barrett + Kavanaugh\n+ Roberts + liberals", 5, "#bcbd22"),
]

labels = [b[0] for b in blocs]
counts = [b[1] for b in blocs]
colors = [b[2] for b in blocs]

order = np.argsort(counts)[::-1]
labels = [labels[i] for i in order]
counts = [counts[i] for i in order]
colors = [colors[i] for i in order]

fig, ax = plt.subplots(figsize=(10, 5.5))
bars = ax.barh(range(len(labels)), counts, color=colors, edgecolor="#333", linewidth=0.6)
ax.set_yticks(range(len(labels)))
ax.set_yticklabels(labels, fontsize=9)
ax.invert_yaxis()
ax.set_xlabel("Number of opinions", fontsize=11)
ax.set_title("Most Common Majority Blocs \u2014 SCOTUS OT2024 (approx.)",
             fontsize=13, fontweight="bold", pad=12)

tariff_idx = labels.index("Roberts + Gorsuch\n+ Barrett + liberals")
ax.annotate("\u2190 Tariff majority bloc", xy=(counts[tariff_idx] + 0.3, tariff_idx),
            fontsize=9, fontweight="bold", color="#2ca02c", va="center")

for bar, count in zip(bars, counts):
    ax.text(bar.get_width() - 0.5, bar.get_y() + bar.get_height() / 2,
            str(count), va="center", ha="right", fontsize=10, fontweight="bold", color="white")

ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
plt.tight_layout()
plt.show()
Figure 4: Frequency of majority agreement blocs in OT2024. Unanimous decisions dominate, followed by the Roberts–Kavanaugh–Barrett conservative-center trio. The tariff majority configuration (Roberts + Gorsuch + Barrett + all three liberals) appears in roughly 6 divided cases.

The majority-bloc chart reveals that while the conservative six often vote together (14 non-unanimous cases), the Court’s most common configuration is unanimity (28 cases). The tariff-case coalition—Roberts, Gorsuch, and Barrett joining all three liberals—is rarer (about 6 cases) but not unprecedented. It emerges specifically on statutory-interpretation and separation-of-powers questions where textualism cuts against executive overreach.

7. Conclusion

The data tell a consistent story: the 6–3 tariff ruling was not an anomaly but a reflection of structural fault lines within the conservative supermajority.

  • Thomas and Alito form the Court’s tightest voting bloc (97% agreement), and Kavanaugh is their most frequent third vote. This trio’s tariff dissent fits their overall pattern.
  • Roberts and Barrett occupy a centrist-conservative position with higher cross-ideological agreement, especially with Kagan. Their placement in the majority coalition was structurally predictable.
  • Gorsuch has a well-documented textualist streak on separation-of-powers questions. His vote to strike down IEEPA tariffs aligns with his broader jurisprudential profile, not just this case.
  • The liberal bloc (Sotomayor, Kagan, Jackson) votes cohesively in divided cases, making them a reliable foundation for any cross-ideological majority.

Limitations

  • The pairwise agreement matrix is approximate. The full OT2024 matrix is assembled from reported Stat Pack highlights and estimates; individual cell values may differ from the official data by a few percentage points.
  • Dissent and majority bloc counts are based on available case summaries and may not capture every nuance of partial concurrences and dissents.
  • Agreement rates measure outcome alignment, not reasoning alignment. Two Justices can reach the same result for very different reasons.

Despite these caveats, the visualizations offer a compelling lens on the Court’s internal dynamics. The tariff ruling wasn’t a bolt from the blue—it was the predictable product of a Court whose conservative wing is less monolithic than popular commentary suggests.

8. References

  1. Learning Resources, Inc. v. Trump, 607 U.S. ___ (2026) — Full opinion (PDF)
  2. SCOTUSblog: Supreme Court strikes down tariffs
  3. SCOTUSblog Stat Pack, OT2024 (Final, June 27, 2025)
  4. SCOTUSblog Statistics Hub
  5. Wikipedia: Learning Resources, Inc. v. Trump
  6. Tax Foundation: Supreme Court Trump Tariffs Ruling Analysis
  7. SCOTUSblog: Trump v. V.O.S. Selections case page
  8. Justia: Learning Resources, Inc. v. Trump, 607 U.S. ___ (2026)

Footnotes

  1. IEEPA: the International Emergency Economic Powers Act, a 1977 federal law (50 U.S.C. §§ 1701–1708) that grants the President broad authority to regulate commerce during national emergencies arising from foreign threats.↩︎

  2. OT: October Term. The Supreme Court’s annual session begins on the first Monday in October. “OT2024” refers to the term that started in October 2024 and ended in June 2025.↩︎