Skip to content

feat(week-3): implement Non-IID Dirichlet simulation, client drift memo, and interactive dashboard#2

Open
koleajeolayinka wants to merge 14 commits into
mainfrom
feature/week-3-non-iid
Open

feat(week-3): implement Non-IID Dirichlet simulation, client drift memo, and interactive dashboard#2
koleajeolayinka wants to merge 14 commits into
mainfrom
feature/week-3-non-iid

Conversation

@koleajeolayinka

@koleajeolayinka koleajeolayinka commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Overview

This PR implements the curriculum and coding deliverables for Fellowship Week 3: The Non-IID Problem. We simulate statistical heterogeneity using Dirichlet partitioning, analyse the numerical impact of label skew on convergence, explain the underlying mathematical mechanism of client drift, and build a premium, interactive walkthrough dashboard for students to explore these concepts.


Key Changes

1. Data Partitioning (fed/data.py)

  • Implemented dirichlet_split to divide MNIST across 5 clients using the concentration parameter $\alpha$.
  • Added a redistribution check ensuring no client receives an empty partition, eliminating potential worker process crashes.

2. Simulation Runner & Plotter (main.py / plot.py)

  • Orchestrator (main.py): Runs both IID and Non-IID simulations sequentially. Features a pure PyTorch optimization loop that matches FedAvg mathematically, bypassing Ray socket path limits and network sandboxing blocks.
  • Flower Version (main_flower.py): Maintained the standard Flower/Ray simulation runner for direct curriculum compatibility.
  • Pillow Plotter (plot.py): Uses Python's PIL library to generate the comparison chart convergence_comparison.png as a self-contained operation.

3. Interactive Walkthrough (walkthrough/)

  • Dirichlet Slider Visualizer: Interactive $\alpha$ slider dynamically updating client class-distribution grids.
  • Client Drift Sandbox: 2D parameter space canvas animating gradient trajectories. Shows how non-aligned client minima pull parameters in divergent directions.
  • Live CSV Plotter: Graphing engine enabling users to upload and compare custom training logs.
  • Quiz: Assessment module verifying understanding of data skews, Dirichlet splits, and FedAvg math.

Experimental Results

Runs of 10 communication rounds on 5 simulated clients yielded a clear convergence penalty for Non-IID data:

  • Round 1 Deficit: The Non-IID split starts with a -20.12% accuracy penalty compared to IID (57.63% vs 77.75%).
  • Convergence Lag: The IID simulation crossed the 88% accuracy threshold at Round 4, whereas the Non-IID split took 7 rounds to reach the same performance level.
  • Round 10 Final Deficit: The final IID model finished at 90.58% accuracy, while the Non-IID model finished at 89.27% accuracy.

How to Verify Locally

1. Run the Simulations & Plot

cd week-3
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python main.py

Verify that iid_results.csv, noniid_results.csv, and convergence_comparison.png are correctly generated in the week-3 folder.

2. Run the Interactive Dashboard

python3 -m http.server 8000

Open your browser and visit http://localhost:8000/walkthrough/ to interact with the Dirichlet slider, the vector field simulator, and the quiz.

Summary by CodeRabbit

  • New Features

    • Added a federated learning tutorial covering IID and Non-IID data, client drift, and FedAvg.
    • Added PyTorch and Flower-based MNIST simulations with configurable data distribution settings.
    • Added interactive visualizations for data splits, client drift, convergence results, and a knowledge-check quiz.
    • Added CSV-based results logging and convergence chart generation.
  • Documentation

    • Added setup instructions, experiment commands, research observations, and learning resources.
  • Chores

    • Added dependency specifications and exclusions for generated files, datasets, environments, and editor artifacts.

@koleajeolayinka
koleajeolayinka requested a review from D-Lite July 15, 2026 16:24
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@koleajeolayinka, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 18 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2490b32e-69fe-4d15-ba74-98b4497f26e2

📥 Commits

Reviewing files that changed from the base of the PR and between 00ce566 and b8b358f.

📒 Files selected for processing (12)
  • week-3/MEMO.md
  • week-3/README.md
  • week-3/fed/_compat.py
  • week-3/fed/client.py
  • week-3/fed/data.py
  • week-3/main.py
  • week-3/main_flower.py
  • week-3/plot.py
  • week-3/requirements.txt
  • week-3/walkthrough/app.js
  • week-3/walkthrough/index.html
  • week-3/walkthrough/style.css
📝 Walkthrough

Walkthrough

Changes

Federated Learning Week 3

Layer / File(s) Summary
Learning materials and environment setup
week-3/.gitignore, week-3/README.md, week-3/MEMO.md, week-3/requirements.txt
Adds Week 3 concepts, experiment notes, setup commands, dependency constraints, and ignored generated artifacts.
Federated data and client foundations
week-3/fed/*
Defines the MNIST MLP, IID and Dirichlet client partitions, Flower client hooks, and TensorFlow compatibility handling.
Direct FedAvg simulation
week-3/main.py
Runs local client training, weighted FedAvg aggregation, global evaluation, CSV logging, and IID/Non-IID CLI modes.
Flower orchestration and result plotting
week-3/main_flower.py, week-3/fed/strategy.py, week-3/plot.py
Starts Ray-backed Flower simulations, aggregates evaluation metrics into CSV files, and renders convergence plots with Pillow.
Walkthrough page structure and styling
week-3/walkthrough/index.html, week-3/walkthrough/style.css
Adds five walkthrough tabs covering Dirichlet splits, client drift, terminal commands, results plotting, and a quiz, with their visual styling.
Walkthrough interactions
week-3/walkthrough/app.js
Implements tab switching, visualizer calculations and animation, CSV charting, clipboard actions, and quiz state management.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant main.py
  participant load_data
  participant LocalClient
  participant FedAvg
  participant ResultsCSV
  main.py->>load_data: load IID or Non-IID client data
  main.py->>LocalClient: send global model parameters
  LocalClient->>FedAvg: return locally trained parameters and sample counts
  FedAvg->>main.py: compute weighted global parameters
  main.py->>ResultsCSV: record round accuracy and loss
Loading

Suggested reviewers: d-lite

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.32% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: Non-IID Dirichlet simulation, supporting documentation, and the interactive dashboard.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/week-3-non-iid

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (12)
week-3/walkthrough/index.html-149-153 (1)

149-153: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Represent Client 3 with a distinct legend color.

The simulator renders three client minima, but this legend lists only Clients 1 and 2. Client 3 also uses the same green as the global optimum, making the visualization ambiguous.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@week-3/walkthrough/index.html` around lines 149 - 153, Update the
landscape-legend markup to add a Client 3 Min legend item with a distinct color
class matching Client 3’s rendered minimum, and ensure it does not reuse the
global-min color. Preserve the existing Global Optimum and Client 1/2 entries.
week-3/walkthrough/app.js-622-630 (1)

622-630: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Handle charts containing only round 1.

When both uploads contain one row at round 1, maxR - 1 is zero and all x-coordinates become NaN.

 const maxR = Math.max(/* ... */);
+const roundSpan = Math.max(maxR - 1, 1);

-const x = paddingLeft + (chartW * (r - 1) / (maxR - 1));
+const x = paddingLeft + (chartW * (r - 1) / roundSpan);

Apply the same denominator in mapCoords.

Also applies to: 650-653

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@week-3/walkthrough/app.js` around lines 622 - 630, Update the round-label
coordinate calculation in the max-round drawing loop and the corresponding
mapCoords logic to handle maxR equal to 1 without dividing by zero. Use the same
safe denominator in both locations, while preserving normal spacing for charts
with multiple rounds.
week-3/walkthrough/app.js-114-118 (1)

114-118: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve the selected alpha preset state.

setAlphaPreset adds active, but updateDirichletSplit immediately removes it and the empty conditional never restores it. The default preset is also cleared during initialization.

Proposed fix
 document.querySelectorAll('.preset-btn').forEach(btn => {
-    btn.classList.remove('active');
+    btn.classList.toggle('active', parseFloat(btn.innerText) === alpha);
 });
-if (alpha === 0.10) {
-    // match preset 0.1
-}

Also applies to: 180-188

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@week-3/walkthrough/app.js` around lines 114 - 118, Update
updateDirichletSplit and the related setAlphaPreset flow so updateDirichletSplit
does not unconditionally remove the active class from preset buttons. Preserve
the selected alpha preset, including the default alpha === 0.10 state during
initialization, by restoring or maintaining the matching .preset-btn active
state in the existing conditional.
week-3/walkthrough/style.css-90-93 (1)

90-93: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Resolve the reported Stylelint errors.

Rename the keyframes to kebab-case and update their uses, change currentColor to currentcolor, and remove the redundant display: inline-block from .option-marker.

Also applies to: 138-138, 155-162, 884-893, 926-929

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@week-3/walkthrough/style.css` around lines 90 - 93, Resolve the Stylelint
issues in style.css: rename the rotate🍭 keyframes identifier to kebab-case and
update its animation use, change currentColor declarations to currentcolor, and
remove the redundant display: inline-block from .option-marker. Apply these
changes consistently to all referenced locations.

Source: Linters/SAST tools

week-3/walkthrough/app.js-457-461 (1)

457-461: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clear the simulation state when the interval finishes.

The button text resets, but isSimulating remains true. Consequently, the next click only resets the simulation instead of starting another round.

 clearInterval(driftSimInterval);
+driftSimInterval = null;
+driftState.isSimulating = false;
 document.getElementById('drift-play-text').innerText = 'Simulate Round';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@week-3/walkthrough/app.js` around lines 457 - 461, Update the
simulation-finished branch that clears driftSimInterval and resets
drift-play-text to also set isSimulating to false, allowing the next button
click to start a new round.
week-3/walkthrough/app.js-615-619 (1)

615-619: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Resolve the CSS custom property before assigning fillStyle. chartCtx.fillStyle = 'var(--text-secondary)' won’t apply in canvas, so both label blocks should use a computed color string instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@week-3/walkthrough/app.js` around lines 615 - 619, Update both canvas label
blocks around the Acc labels to resolve the --text-secondary CSS custom property
to a computed color string before assigning chartCtx.fillStyle; replace the
direct var(--text-secondary) assignment in each block while preserving the
existing label rendering behavior.
week-3/fed/client.py-39-52 (1)

39-52: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Compute evaluation loss as a true per-example mean.

Both runners average batch means, which overweights partial batches.

  • week-3/fed/client.py#L39-L52: accumulate loss.item() * labels.size(0) and divide by total.
  • week-3/main.py#L99-L119: apply the same calculation before weighting client losses.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@week-3/fed/client.py` around lines 39 - 52, Compute evaluation loss as a
per-example mean in evaluate: accumulate each batch loss multiplied by
labels.size(0), then divide loss_sum by total instead of len(self.trainloader).
Apply the same loss accumulation and normalization in week-3/main.py lines
99-119 before client-loss weighting; no direct change is required elsewhere.
week-3/main.py-158-172 (1)

158-172: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Report single-mode plot failures.

Both except blocks silently hide unexpected plotting failures. Print the exception as done in the both branch so local verification remains diagnosable.

Proposed fix
-        except Exception as e:
-            pass
+        except Exception as e:
+            print(f"Could not generate plot automatically: {e}")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@week-3/main.py` around lines 158 - 172, Update the exception handlers in the
single-mode branches of the main argument dispatch to report plotting failures
instead of silently passing. In both the args.mode == "iid" and args.mode ==
"noniid" blocks, print the caught exception, matching the existing behavior in
the "both" branch.

Source: Linters/SAST tools

week-3/MEMO.md-11-11 (1)

11-11: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Report the accuracy gap in percentage points.

77.75% - 57.63% is a 20.12 percentage-point gap. Calling it 20.12% incorrectly implies a relative difference.

-—representing a performance gap of **20.12%**.
+—representing a performance gap of **20.12 percentage points**.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@week-3/MEMO.md` at line 11, Update the “Initial Round Contrast” statement in
the Round 1 comparison to label the 20.12 difference between 77.75% and 57.63%
as percentage points, not percent; leave the reported accuracy and loss values
unchanged.
week-3/plot.py-82-99 (1)

82-99: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Support one-round and partial simulation logs.

When the only available log contains Round 1, max_round - 1 is zero at Lines 85 and 98, causing plot generation to crash.

     max_round = max((iid_rounds or [10]) + (noniid_rounds or [10]))
+    round_span = max(max_round - 1, 1)
     for r in range(1, max_round + 1):
-        x = pad_left + int(chart_w * (r - 1) / (max_round - 1))
+        x = pad_left + int(chart_w * (r - 1) / round_span)
 
     def map_coords(round_num, acc):
-        x = pad_left + int(chart_w * (round_num - 1) / (max_round - 1))
+        x = pad_left + int(chart_w * (round_num - 1) / round_span)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@week-3/plot.py` around lines 82 - 99, Update the round-to-x-coordinate
calculations in the plotting loop and map_coords so a max_round of 1 does not
divide by zero. Use a zero horizontal offset for the single-round case while
preserving the existing scaling for multi-round logs, including partial
simulation data.
week-3/main_flower.py-86-92 (1)

86-92: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject non-positive Dirichlet alpha values at the CLI boundary.

Dirichlet concentration parameters must be positive; values such as --alpha 0 currently propagate into partitioning and fail during execution.

     args = parser.parse_args()
+    if args.mode in {"noniid", "both"} and args.alpha <= 0:
+        parser.error("--alpha must be greater than zero")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@week-3/main_flower.py` around lines 86 - 92, Validate the --alpha argument in
the argument parser before execution, rejecting zero and negative values while
retaining the existing default and float parsing. Update the parser
configuration around parser.add_argument and ensure invalid values produce a
clear CLI error instead of reaching partitioning.
week-3/README.md-87-108 (1)

87-108: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Point the Flower/Ray instructions to main_flower.py.

The isolated subprocesses, Ray handling, CSV logging, and automatic plotting shown here are implemented by main_flower.py, not the standalone PyTorch runner described for main.py.

Proposed documentation correction
-The simulation runner in `main.py` is configured to run both IID and Non-IID setups sequentially inside isolated subprocesses.
+The Flower runner in `main_flower.py` runs both setups sequentially inside isolated subprocesses.

-python main.py
+python main_flower.py

-python main.py --mode iid
+python main_flower.py --mode iid

-python main.py --mode noniid --alpha 0.1
+python main_flower.py --mode noniid --alpha 0.1
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@week-3/README.md` around lines 87 - 108, Update the Step 2 experiment
commands and descriptions to reference main_flower.py instead of main.py. Ensure
the IID, Non-IID, custom-alpha, and automatic plotting instructions match the
Flower/Ray runner implemented by main_flower.py, while keeping standalone
main.py usage separate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@week-3/fed/_compat.py`:
- Around line 27-39: Update the TensorFlow import handling in the compatibility
initialization so only a missing top-level TensorFlow package returns normally;
treat a ModuleNotFoundError raised by TensorFlow’s internal dependencies like
other broken-installation exceptions. Preserve the existing cleanup and no-op
stub setup for that failure path, using the import exception context to
distinguish the cases.

In `@week-3/fed/data.py`:
- Around line 56-78: Update load_data to return both the client’s training
DataLoader and a distinct evaluation DataLoader backed by held-out MNIST test
data, rather than reusing the training partition. Preserve the existing
IID/non-IID partitioning for training, then update the runner call sites to
consume the separate loader for accuracy and loss evaluation.

In `@week-3/main_flower.py`:
- Around line 9-13: Replace the hard-coded /private/tmp Ray temporary directory
configuration in the startup setup with a platform-native temporary-directory
value from the standard library, and append a unique subdirectory for this run.
Apply the same change to the additional configuration block so Ray uses a
writable, unique path consistently across macOS, Linux, and Windows.

In `@week-3/plot.py`:
- Line 25: Update generate_plot to accept a noniid_alpha argument and use it in
the Non-IID plot legend instead of a hard-coded value. In main_flower.py, pass
args.alpha as noniid_alpha when calling plot.generate_plot, preserving the
existing file and output arguments.

In `@week-3/requirements.txt`:
- Around line 4-5: Update week-3/requirements.txt by removing the matplotlib
dependency and adding Pillow, matching the PIL import used by week-3/plot.py
while preserving the existing numpy constraint.

In `@week-3/walkthrough/app.js`:
- Around line 790-805: Update the quiz answer markup generated in the
answersHTML map to use button elements with type="button" and the existing
quiz-option class instead of clickable divs, preserving the current onclick
handler, IDs, option markers, and answer text.
- Around line 572-583: Update updateDiscrepancyMetric to compare IID and Non-IID
entries from the latest round present in both datasets, rather than blindly
using each array’s final entry. Use each selected row’s round property for the
displayed round labels, and calculate the penalty from those matched accuracies
while preserving the existing metric formatting.
- Around line 158-170: Update the barContainer created in the client
distribution rendering loop to expose an accessible text alternative: assign an
appropriate image role and build an aria-label summarizing every digit’s
percentage from clientProfiles[client], including values for segments omitted
visually because of the pct threshold.

In `@week-3/walkthrough/index.html`:
- Around line 185-190: Update the “Run Both Simulations” section to invoke the
Flower orchestration entry point main_flower.py, or revise the surrounding
description to accurately identify main.py as the direct PyTorch runner; ensure
the command and promised execution flow consistently refer to the same runner.

In `@week-3/walkthrough/style.css`:
- Around line 32-38: Update the responsive CSS for the body and the referenced
grid, header-navigation, and canvas rules so layouts adapt to narrow viewports
before horizontal overflow is clipped. Add appropriate small-screen breakpoints
and responsive sizing/wrapping for those elements, while preserving the existing
desktop layout and avoiding reliance on body overflow-x hiding as the primary
solution.
- Around line 751-771: Update the .upload-btn input[type="file"] styling to
visually hide the file input without using display: none, preserving keyboard
focusability. Add a :focus or :focus-visible style on the associated .upload-btn
label to expose the focused state while retaining the existing upload button
appearance.

---

Minor comments:
In `@week-3/fed/client.py`:
- Around line 39-52: Compute evaluation loss as a per-example mean in evaluate:
accumulate each batch loss multiplied by labels.size(0), then divide loss_sum by
total instead of len(self.trainloader). Apply the same loss accumulation and
normalization in week-3/main.py lines 99-119 before client-loss weighting; no
direct change is required elsewhere.

In `@week-3/main_flower.py`:
- Around line 86-92: Validate the --alpha argument in the argument parser before
execution, rejecting zero and negative values while retaining the existing
default and float parsing. Update the parser configuration around
parser.add_argument and ensure invalid values produce a clear CLI error instead
of reaching partitioning.

In `@week-3/main.py`:
- Around line 158-172: Update the exception handlers in the single-mode branches
of the main argument dispatch to report plotting failures instead of silently
passing. In both the args.mode == "iid" and args.mode == "noniid" blocks, print
the caught exception, matching the existing behavior in the "both" branch.

In `@week-3/MEMO.md`:
- Line 11: Update the “Initial Round Contrast” statement in the Round 1
comparison to label the 20.12 difference between 77.75% and 57.63% as percentage
points, not percent; leave the reported accuracy and loss values unchanged.

In `@week-3/plot.py`:
- Around line 82-99: Update the round-to-x-coordinate calculations in the
plotting loop and map_coords so a max_round of 1 does not divide by zero. Use a
zero horizontal offset for the single-round case while preserving the existing
scaling for multi-round logs, including partial simulation data.

In `@week-3/README.md`:
- Around line 87-108: Update the Step 2 experiment commands and descriptions to
reference main_flower.py instead of main.py. Ensure the IID, Non-IID,
custom-alpha, and automatic plotting instructions match the Flower/Ray runner
implemented by main_flower.py, while keeping standalone main.py usage separate.

In `@week-3/walkthrough/app.js`:
- Around line 622-630: Update the round-label coordinate calculation in the
max-round drawing loop and the corresponding mapCoords logic to handle maxR
equal to 1 without dividing by zero. Use the same safe denominator in both
locations, while preserving normal spacing for charts with multiple rounds.
- Around line 114-118: Update updateDirichletSplit and the related
setAlphaPreset flow so updateDirichletSplit does not unconditionally remove the
active class from preset buttons. Preserve the selected alpha preset, including
the default alpha === 0.10 state during initialization, by restoring or
maintaining the matching .preset-btn active state in the existing conditional.
- Around line 457-461: Update the simulation-finished branch that clears
driftSimInterval and resets drift-play-text to also set isSimulating to false,
allowing the next button click to start a new round.
- Around line 615-619: Update both canvas label blocks around the Acc labels to
resolve the --text-secondary CSS custom property to a computed color string
before assigning chartCtx.fillStyle; replace the direct var(--text-secondary)
assignment in each block while preserving the existing label rendering behavior.

In `@week-3/walkthrough/index.html`:
- Around line 149-153: Update the landscape-legend markup to add a Client 3 Min
legend item with a distinct color class matching Client 3’s rendered minimum,
and ensure it does not reuse the global-min color. Preserve the existing Global
Optimum and Client 1/2 entries.

In `@week-3/walkthrough/style.css`:
- Around line 90-93: Resolve the Stylelint issues in style.css: rename the
rotate🍭 keyframes identifier to kebab-case and update its animation use, change
currentColor declarations to currentcolor, and remove the redundant display:
inline-block from .option-marker. Apply these changes consistently to all
referenced locations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c1baf577-4e75-49f6-89c6-1eb820e54e6e

📥 Commits

Reviewing files that changed from the base of the PR and between 6b5897c and 00ce566.

📒 Files selected for processing (16)
  • week-3/.gitignore
  • week-3/MEMO.md
  • week-3/README.md
  • week-3/fed/__init__.py
  • week-3/fed/_compat.py
  • week-3/fed/client.py
  • week-3/fed/data.py
  • week-3/fed/model.py
  • week-3/fed/strategy.py
  • week-3/main.py
  • week-3/main_flower.py
  • week-3/plot.py
  • week-3/requirements.txt
  • week-3/walkthrough/app.js
  • week-3/walkthrough/index.html
  • week-3/walkthrough/style.css

Comment thread week-3/fed/_compat.py Outdated
Comment thread week-3/fed/data.py Outdated
Comment thread week-3/main_flower.py
Comment thread week-3/plot.py Outdated
Comment thread week-3/requirements.txt Outdated
Comment thread week-3/walkthrough/app.js Outdated
Comment thread week-3/walkthrough/app.js
Comment thread week-3/walkthrough/index.html Outdated
Comment thread week-3/walkthrough/style.css
Comment thread week-3/walkthrough/style.css
@koleajeolayinka

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant