Skip to content

Initial Dash app scaffold with CSV multi-project repo, normalization, scoring, ingestion, UI and tests#1

Open
yainge wants to merge 1 commit intomainfrom
codex/build-market-evaluation-dashboard-with-dash
Open

Initial Dash app scaffold with CSV multi-project repo, normalization, scoring, ingestion, UI and tests#1
yainge wants to merge 1 commit intomainfrom
codex/build-market-evaluation-dashboard-with-dash

Conversation

@yainge
Copy link
Copy Markdown
Owner

@yainge yainge commented Feb 23, 2026

Motivation

  • Provide a local-first, deployable Dash + Plotly market-evaluation dashboard implementing the specified criteria tree, normalization, direction handling, completeness rules, weight profiles, and max-5 country UI constraint.
  • Support multi-project workflows stored under data/projects/<project_slug> with CSV-backed persistence and tooling to create, duplicate, import, and export projects.
  • Add a matrix ingestion path that converts the provided scoring matrix CSV into the long observations table and canonical weights.csv for a project.

Description

  • Added theme and UI scaffolding under src/app/theme.py and src/app/ui/ with pages for projects, data_editor, weights, and viz, plus the app entry src/app/main.py wiring Dash callbacks and controls (country limit, raw vs normalized toggle, profile selector, snapshot/project export/import).
  • Implemented domain logic in src/app/domain/ including normalization.py (min-max per subcriterion with direction inversion and completeness exclusion), scoring.py (sub -> category -> overall aggregation and percentage weight normalization), and validation.py (schema and sum-to-1 checks).
  • Implemented CSV-backed repository CSVProjectRepository in src/app/data/csv_repo.py plus a repository interface ProjectRepository, default project seeding under data/projects/default, and a skeleton sqlite_repo.py for V2.
  • Added services src/app/services/ingest_matrix.py to parse the matrix CSV into long observations.csv and weights.csv, and src/app/services/snapshot_export.py to build the snapshot CSV used by the Visualizations page.
  • Included scripts/start.py to launch the server and open a browser, README and ARCHITECTURE docs, and unit tests in tests/ for normalization, scoring/weights, and ingestion.

Testing

  • Ran python -m compileall src tests which completed successfully and verified modules compile without syntax errors.
  • Ran pytest -q in this environment but collection/execution failed because runtime dependency pandas (and other packages) were not installed, so unit tests could not execute here.
  • Attempted pip install -e .[dev] to install dependencies but the environment blocked network access (proxy error) so dependency installation failed and prevented running the test suite in this run.

Codex Task

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 332bab8500

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/app/main.py
p = repo.project_path(active)
if filename.endswith(".zip"):
with zipfile.ZipFile(io.BytesIO(decoded), "r") as zf:
zf.extractall(p)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Import ZIP contents into the active project files

The import callback extracts uploaded ZIPs directly into project_path(active), but the export callback stores files under a top-level <project>/... prefix. Importing an exported archive therefore creates .../<active>/<active>/observations.csv instead of replacing .../<active>/observations.csv, so the UI reports success while subsequent reads still use the old project data.

Useful? React with 👍 / 👎.

if selected.empty:
return selected

counts = selected.groupby("subcriterion_id")["country"].nunique()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Require non-null values in completeness filtering

Completeness is currently based only on whether each selected country has a row for a subcriterion, not whether each row has a numeric raw_value. If one selected country has a blank value, that subcriterion remains eligible, produces NaN normalized values, and later score aggregation silently drops those NaNs, so countries are compared using different effective criteria.

Useful? React with 👍 / 👎.

"level": "category",
"category_id": cid,
"subcriterion_id": "",
"weight_value": float(cweight),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Normalize category weights during matrix ingestion

Ingestion normalizes subcriterion weights from percentages (>1) to fractions, but category weights are written as-is. When category rows are percentages (for example 33), later global normalization divides all weights by 100, including already-normalized subcriterion weights, which scales them down a second time and distorts score magnitudes.

Useful? React with 👍 / 👎.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant