FIFA World Cup 2026 — Brazil vs Morocco¶

Group C · Match 7 · June 13, 2026 · MetLife Stadium, East Rutherford, NJ

Final Score: Brazil 1 – 1 Morocco

All statistics sourced from ESPN, FIFA.com, Opta Analyst, FWC Times, NBC Sports, Sports Media Watch, and Morocco World News.

1. Imports & Theme Setup¶

In [ ]:
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.gridspec as gridspec
import numpy as np

%matplotlib inline

# Colour palette
BRAZIL   = "#009C3B"   # Brazil green
BRAZIL2  = "#FFDF00"   # Brazil yellow accent
MOROCCO  = "#C1272D"   # Morocco red
MOROCCO2 = "#006233"   # Morocco dark-green accent
BG       = "#0D1117"
PANEL    = "#161B22"
TEXT     = "#E6EDF3"
SUBTEXT  = "#8B949E"
GRID     = "#21262D"

plt.rcParams.update({
    "figure.facecolor": BG,
    "axes.facecolor":   PANEL,
    "axes.edgecolor":   GRID,
    "axes.labelcolor":  TEXT,
    "xtick.color":      SUBTEXT,
    "ytick.color":      SUBTEXT,
    "text.color":       TEXT,
    "grid.color":       GRID,
    "grid.linestyle":   "--",
    "grid.alpha":       0.5,
    "font.family":      "DejaVu Sans",
})

print("Theme applied.")

2. Match Data¶

All figures verified from official sources (ESPN, FIFA.com, Opta Analyst).

In [ ]:
# Match statistics
stats_labels = ["Total Shots", "Shots on Target", "Corners", "Fouls", "Saves", "Duels Won"]
brazil_vals  = [12, 5, 6, 16, 2, 53]
morocco_vals = [14, 3, 2, 14, 4, 62]

# Possession
poss_brazil  = 51.3
poss_morocco = 48.7

# Passing
pass_brazil_tot  = 524
pass_morocco_tot = 493
pass_brazil_acc  = 87   # %
pass_morocco_acc = 86   # %

# Expected Goals
xg_brazil  = 1.26
xg_morocco = 1.37

# Goals
goal_times  = [21, 32]
goal_teams  = ["Morocco\nSaibari", "Brazil\nVinicius Jr."]
goal_colors = [MOROCCO, BRAZIL]

# US Viewership — 2026 WC tournament data (Brazil vs Morocco ratings pending)
viewership_labels = [
    "Mexico v\nS.Africa\n(FOX)",
    "Mexico v\nS.Africa\n(Telemundo)",
    "USA v\nParaguay\n(FOX)",
    "USA v\nParaguay\n(Telemundo)",
]
viewership_vals  = [6.31, 12.1, 15.99, 8.9]
view_colors      = ["#1F6FEB", "#A371F7", "#1F6FEB", "#A371F7"]

# Attendance
attended = 80663
capacity = 82500

print("Data loaded.")

3. Helper Function¶

In [ ]:
def hbar_pair(ax, labels, b_vals, m_vals, title):
    """Draw a grouped horizontal bar chart comparing Brazil vs Morocco."""
    y  = np.arange(len(labels))
    h  = 0.35
    b1 = ax.barh(y + h/2, b_vals, h, color=BRAZIL,  label="Brazil",  zorder=3)
    b2 = ax.barh(y - h/2, m_vals, h, color=MOROCCO, label="Morocco", zorder=3)
    ax.set_yticks(y)
    ax.set_yticklabels(labels, fontsize=10)
    ax.set_title(title, fontsize=12, fontweight="bold", pad=8)
    ax.grid(axis="x", zorder=0)
    ax.legend(fontsize=9, loc="lower right")
    max_v = max(b_vals + m_vals)
    for bar, val in zip(b1, b_vals):
        ax.text(bar.get_width() + max_v * 0.02,
                bar.get_y() + bar.get_height() / 2,
                str(val), va="center", fontsize=9, color=TEXT)
    for bar, val in zip(b2, m_vals):
        ax.text(bar.get_width() + max_v * 0.02,
                bar.get_y() + bar.get_height() / 2,
                str(val), va="center", fontsize=9, color=TEXT)

4. Full Dashboard¶

Renders all 8 panels in one figure:

  1. Header banner
  2. Match statistics comparison
  3. Ball possession donut
  4. Expected Goals (xG)
  5. Passes — volume & accuracy
  6. Goal timeline
  7. US viewership by match & network
  8. Stadium attendance gauge
In [ ]:
fig = plt.figure(figsize=(20, 24), facecolor=BG)
gs  = gridspec.GridSpec(4, 3, figure=fig, hspace=0.55, wspace=0.38)

# ── Panel 1: Header banner ───────────────────────────────────────────────────
ax_hdr = fig.add_subplot(gs[0, :])
ax_hdr.set_facecolor(PANEL)
ax_hdr.set_xlim(0, 1)
ax_hdr.set_ylim(0, 1)
ax_hdr.axis("off")

ax_hdr.text(0.5, 0.82, "FIFA World Cup 2026\u2122  \u00b7  Group C  \u00b7  Match 7",
            ha="center", va="center", fontsize=13, color=SUBTEXT)
ax_hdr.text(0.5, 0.50, "BRAZIL  1 \u2013 1  MOROCCO",
            ha="center", va="center", fontsize=30, fontweight="bold", color=TEXT)
ax_hdr.text(0.5, 0.18,
            "MetLife Stadium, East Rutherford, NJ  \u00b7  June 13, 2026  \u00b7  Att: 80,663 / 82,500 (97.8%)",
            ha="center", va="center", fontsize=11, color=SUBTEXT)

goal_text = "* 21'  Ismael Saibari  (Morocco)   |   32'  Vinicius Junior  (Brazil)  *"
ax_hdr.text(0.5, -0.04, goal_text, ha="center", va="center", fontsize=11, color=TEXT,
            bbox=dict(boxstyle="round,pad=0.4", facecolor=GRID, edgecolor=GRID))

# ── Panel 2: Match statistics horizontal bars ────────────────────────────────
ax1 = fig.add_subplot(gs[1, :2])
hbar_pair(ax1, stats_labels, brazil_vals, morocco_vals, "Match Statistics Comparison")

# ── Panel 3: Possession donut ────────────────────────────────────────────────
ax2 = fig.add_subplot(gs[1, 2])
ax2.set_facecolor(PANEL)
ax2.pie([poss_brazil, poss_morocco], colors=[BRAZIL, MOROCCO], startangle=90,
        wedgeprops=dict(width=0.5, edgecolor=BG, linewidth=2))
ax2.text(0,  0.12, f"{poss_brazil}%",  ha="center", fontsize=16, fontweight="bold", color=BRAZIL)
ax2.text(0, -0.18, f"{poss_morocco}%", ha="center", fontsize=16, fontweight="bold", color=MOROCCO)
ax2.set_title("Ball Possession", fontsize=12, fontweight="bold", pad=10)
ax2.legend(["Brazil", "Morocco"], loc="lower center", fontsize=9, bbox_to_anchor=(0.5, -0.06))

# ── Panel 4: xG comparison ───────────────────────────────────────────────────
ax3 = fig.add_subplot(gs[2, 0])
bars = ax3.bar(["Brazil", "Morocco"], [xg_brazil, xg_morocco],
               color=[BRAZIL, MOROCCO], width=0.45, zorder=3, edgecolor=BG, linewidth=1.5)
for bar, val in zip(bars, [xg_brazil, xg_morocco]):
    ax3.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.03,
             f"{val:.2f}", ha="center", fontsize=13, fontweight="bold", color=TEXT)
ax3.set_ylim(0, max(xg_brazil, xg_morocco) * 1.35)
ax3.set_title("Expected Goals (xG)", fontsize=12, fontweight="bold")
ax3.set_ylabel("xG", fontsize=10)
ax3.grid(axis="y", zorder=0)

# ── Panel 5: Passes — volume & accuracy ─────────────────────────────────────
ax4   = fig.add_subplot(gs[2, 1])
ax4_r = ax4.twinx()
x, w  = np.arange(2), 0.35
b_tot = ax4.bar(x - w/2,  [pass_brazil_tot, pass_morocco_tot], w,
                color=[BRAZIL, MOROCCO], zorder=3, edgecolor=BG, linewidth=1.2)
b_acc = ax4_r.bar(x + w/2, [pass_brazil_acc, pass_morocco_acc], w,
                  color=[BRAZIL2, MOROCCO2], zorder=3, edgecolor=BG, linewidth=1.2)
ax4.set_xticks(x)
ax4.set_xticklabels(["Brazil", "Morocco"])
ax4.set_ylabel("Total Passes",  color=SUBTEXT, fontsize=9)
ax4_r.set_ylabel("Accuracy %",  color=SUBTEXT, fontsize=9)
ax4.set_title("Passes \u2014 Volume & Accuracy", fontsize=12, fontweight="bold")
ax4.grid(axis="y", zorder=0)
for bar, val in zip(b_tot, [pass_brazil_tot, pass_morocco_tot]):
    ax4.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 5,
             str(val), ha="center", fontsize=10, fontweight="bold", color=TEXT)
for bar, val in zip(b_acc, [pass_brazil_acc, pass_morocco_acc]):
    ax4_r.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.3,
               f"{val}%", ha="center", fontsize=10, fontweight="bold", color=TEXT)
ax4.legend(handles=[
    mpatches.Patch(color=BRAZIL,   label="Brazil passes"),
    mpatches.Patch(color=MOROCCO,  label="Morocco passes"),
    mpatches.Patch(color=BRAZIL2,  label="Brazil acc%"),
    mpatches.Patch(color=MOROCCO2, label="Morocco acc%"),
], fontsize=8, loc="lower right")

# ── Panel 6: Goal timeline ───────────────────────────────────────────────────
ax5 = fig.add_subplot(gs[2, 2])
ax5.set_xlim(0, 95)
ax5.set_ylim(0, 1)
ax5.axhline(0.5, color=SUBTEXT, linewidth=2, zorder=1)
ax5.fill_between([0,  45], 0, 1, color=GRID, alpha=0.30)
ax5.fill_between([45, 90], 0, 1, color=GRID, alpha=0.15)
for t, label, color in zip(goal_times, goal_teams, goal_colors):
    ax5.scatter(t, 0.5, s=280, color=color, zorder=5, edgecolors=BG, linewidths=1.5)
    ax5.text(t, 0.72 if color == MOROCCO else 0.22,
             f"{t}'", ha="center", fontsize=11, fontweight="bold", color=color)
    ax5.text(t, 0.84 if color == MOROCCO else 0.10,
             label,  ha="center", fontsize=8, color=color)
ax5.axvline(45, color=SUBTEXT, linewidth=1, linestyle="--", alpha=0.6)
ax5.set_xticks([0, 15, 30, 45, 60, 75, 90])
ax5.set_xticklabels(["0'", "15'", "30'", "HT", "60'", "75'", "FT"])
ax5.set_yticks([])
ax5.set_title("Goal Timeline", fontsize=12, fontweight="bold")
ax5.legend(handles=[
    mpatches.Patch(color=BRAZIL,  label="Brazil"),
    mpatches.Patch(color=MOROCCO, label="Morocco"),
], fontsize=9, loc="upper right")

# ── Panel 7: US Viewership ───────────────────────────────────────────────────
ax6  = fig.add_subplot(gs[3, :2])
x_v  = np.arange(len(viewership_labels))
bars = ax6.bar(x_v, viewership_vals, color=view_colors, width=0.5,
               zorder=3, edgecolor=BG, linewidth=1.5)
for bar, val in zip(bars, viewership_vals):
    ax6.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.2,
             f"{val}M", ha="center", fontsize=11, fontweight="bold", color=TEXT)
ax6.set_xticks(x_v)
ax6.set_xticklabels(viewership_labels, fontsize=10)
ax6.set_ylabel("US Viewers (millions)", fontsize=10)
ax6.set_title("2026 FIFA World Cup \u2014 US Viewership by Match & Network", fontsize=12, fontweight="bold")
ax6.grid(axis="y", zorder=0)
ax6.set_ylim(0, 20)
ax6.legend(handles=[
    mpatches.Patch(color="#1F6FEB", label="FOX (English)"),
    mpatches.Patch(color="#A371F7", label="Telemundo (Spanish)"),
], fontsize=10)
ax6.text(0.98, 0.95,
         "Brazil vs Morocco specific ratings\nnot yet published (match Jun 13)",
         transform=ax6.transAxes, ha="right", va="top", fontsize=8.5,
         color=SUBTEXT, style="italic",
         bbox=dict(boxstyle="round,pad=0.3", facecolor=GRID, edgecolor=GRID, alpha=0.7))

# ── Panel 8: Attendance gauge ────────────────────────────────────────────────
ax7 = fig.add_subplot(gs[3, 2])
ax7.set_facecolor(PANEL)
ax7.set_xlim(0, 1)
ax7.set_ylim(0, 1)
ax7.axis("off")
pct = attended / capacity
theta_bg   = np.linspace(np.pi, 0, 200)
theta_fill = np.linspace(np.pi, np.pi - pct * np.pi, 200)
ax7.plot(0.5 + 0.38 * np.cos(theta_bg),   0.35 + 0.38 * np.sin(theta_bg),
         color=GRID,   linewidth=18, solid_capstyle="round")
ax7.plot(0.5 + 0.38 * np.cos(theta_fill), 0.35 + 0.38 * np.sin(theta_fill),
         color=BRAZIL, linewidth=18, solid_capstyle="round")
ax7.text(0.5, 0.35, f"{attended:,}",         ha="center", fontsize=20, fontweight="bold", color=TEXT)
ax7.text(0.5, 0.16, f"of {capacity:,} capacity", ha="center", fontsize=10, color=SUBTEXT)
ax7.text(0.5, 0.04, f"{pct*100:.1f}% full",  ha="center", fontsize=13, fontweight="bold", color=BRAZIL2)
ax7.set_title("Stadium Attendance\nMetLife Stadium, NJ", fontsize=12, fontweight="bold")

# ── Footer ───────────────────────────────────────────────────────────────────
fig.text(0.5, 0.01,
         "Sources: ESPN \u00b7 FIFA.com \u00b7 Opta Analyst \u00b7 FWC Times \u00b7 NBC Sports \u00b7 Sports Media Watch \u00b7 Morocco World News",
         ha="center", fontsize=8.5, color=SUBTEXT, style="italic")

plt.savefig("/home/pravat/brazil_morocco_wc2026.png", dpi=150, bbox_inches="tight", facecolor=BG)
plt.show()
print("Dashboard saved to /home/pravat/brazil_morocco_wc2026.png")

5. Key Takeaways¶

Metric Winner
Total Shots Morocco (14 vs 12)
Shots on Target Brazil (5 vs 3)
xG Morocco (1.37 vs 1.26)
Possession Brazil (51.3% vs 48.7%)
Passes Brazil (524 vs 493)
Duels Won Morocco (62 vs 53)
Saves Bounou/Morocco (4 vs 2)

Morocco were the better team on the stats — more shots, higher xG, more duels won — but Alisson's double save in the dying minutes preserved Brazil's point.

Attendance: 80,663 / 82,500 (97.8% full) at MetLife Stadium.

Global audience for the 2026 World Cup is projected at 5–6 billion across the tournament, with the final expected to draw 1.6 billion+ viewers.


Sources: ESPN · FIFA.com · Opta Analyst · FWC Times · NBC Sports · Sports Media Watch · Morocco World News