"""Dataset E viewer — browse images with labels and filters.""" import os, io, math, pyarrow.parquet as pq from flask import Flask, send_file, request, render_template_string from PIL import Image from collections import Counter ROOT = "/home/kccitadmin/jupyterlab/sandbox/data/E" app = Flask(__name__) # Load parquet once table = pq.read_table(os.path.join(ROOT, "data", "data-00000-of-00001.parquet")) N = table.num_rows DATA = { "cancer": table.column("cancer_label").to_pylist(), "grade": table.column("grade_label").to_pylist(), "subclass": table.column("subclass_label").to_pylist(), "source": table.column("source_dataset").to_pylist(), "filename": table.column("original_filename").to_pylist(), "pid": table.column("patient_id").to_pylist(), "imaging": table.column("imaging_type").to_pylist(), "img_paths": [v["path"] for v in table.column("image").to_pylist()], } LABELS = { "cancer": {0: "non_cancer", 1: "cancer"}, "grade": {0: "low_grade", 1: "high_grade", 2: "not_applicable"}, "subclass": {0: "malignant", 1: "non_malignant", 2: "normal", 3: "landmark", 4: "foreign_body"}, "imaging": {0: "WLI", 1: "NBI", 2: "BLC"}, } HTML = """ Dataset E Viewer

Dataset E Viewer

Total: {{ total }} Showing: {{ filtered_count }} Page: {{ page }}/{{ pages }} Cancer: {{ stats.cancer }} | Non-cancer: {{ stats.non_cancer }} WLI: {{ stats.wli }} | NBI: {{ stats.nbi }} | BLC: {{ stats.blc }}
Reset
{% for i in indices %}
{{ items[loop.index0].source }} pid={{ items[loop.index0].pid }}
{{ items[loop.index0].cancer_label }} {{ items[loop.index0].grade_label }} {{ items[loop.index0].subclass_label }} {{ items[loop.index0].imaging_label }}
{{ items[loop.index0].filename }}
{% endfor %}
""" PER_PAGE = 48 @app.route("/") def index(): # Parse filters f = { "source": request.args.get("source", ""), "cancer": request.args.get("cancer", ""), "grade": request.args.get("grade", ""), "subclass": request.args.get("subclass", ""), "imaging": request.args.get("imaging", ""), "pid": request.args.get("pid", ""), } page = max(1, int(request.args.get("page", 1))) # Filter indices indices = list(range(N)) if f["source"]: indices = [i for i in indices if DATA["source"][i] == f["source"]] if f["cancer"] != "": indices = [i for i in indices if DATA["cancer"][i] == int(f["cancer"])] if f["grade"] != "": indices = [i for i in indices if DATA["grade"][i] == int(f["grade"])] if f["subclass"] != "": indices = [i for i in indices if DATA["subclass"][i] == int(f["subclass"])] if f["imaging"] != "": indices = [i for i in indices if DATA["imaging"][i] == int(f["imaging"])] if f["pid"]: indices = [i for i in indices if str(DATA["pid"][i]) == f["pid"]] filtered_count = len(indices) pages = max(1, math.ceil(filtered_count / PER_PAGE)) page = min(page, pages) start = (page - 1) * PER_PAGE page_indices = indices[start:start + PER_PAGE] # Build item data for template items = [] for i in page_indices: items.append({ "source": DATA["source"][i], "pid": DATA["pid"][i], "cancer": DATA["cancer"][i], "cancer_label": LABELS["cancer"][DATA["cancer"][i]], "grade": DATA["grade"][i], "grade_label": LABELS["grade"][DATA["grade"][i]], "subclass": DATA["subclass"][i], "subclass_label": LABELS["subclass"][DATA["subclass"][i]], "imaging": DATA["imaging"][i], "imaging_label": LABELS["imaging"][DATA["imaging"][i]], "filename": DATA["filename"][i], }) # Build all_data for JS modal (all filtered indices on this page) all_data = {} for idx, i in enumerate(page_indices): all_data[str(i)] = { "index": str(i), "source": DATA["source"][i], "patient_id": str(DATA["pid"][i]), "cancer_label": LABELS["cancer"][DATA["cancer"][i]], "grade_label": LABELS["grade"][DATA["grade"][i]], "subclass_label": LABELS["subclass"][DATA["subclass"][i]], "imaging_type": LABELS["imaging"][DATA["imaging"][i]], "original_filename": DATA["filename"][i], "image_path": DATA["img_paths"][i].split("data/E/")[-1], } # Stats for filtered set fc = Counter(DATA["cancer"][i] for i in indices) fi = Counter(DATA["imaging"][i] for i in indices) # Query string for pagination links qs_parts = [] for k, v in f.items(): if v: qs_parts.append(f"{k}={v}") qs = "&".join(qs_parts) return render_template_string(HTML, total=N, filtered_count=filtered_count, page=page, pages=pages, indices=page_indices, items=items, all_data=all_data, sources=["B", "C", "D"], filters=f, stats={"cancer": fc[1], "non_cancer": fc[0], "wli": fi[0], "nbi": fi[1], "blc": fi[2]}, qs=qs) @app.route("/img//") def serve_img(i, size): path = DATA["img_paths"][i] img = Image.open(path) if img.mode in ("RGBA", "P"): img = img.convert("RGB") if size == "thumb": img.thumbnail((300, 300)) else: img.thumbnail((1000, 1000)) buf = io.BytesIO() img.save(buf, format="JPEG", quality=85) buf.seek(0) return send_file(buf, mimetype="image/jpeg") if __name__ == "__main__": print(f"Dataset E viewer: {N} images loaded") print("Starting server at http://localhost:5173") app.run(host="0.0.0.0", port=5173, debug=False)