{ "cells": [ { "cell_type": "markdown", "id": "ed842c00", "metadata": {}, "source": [ "# Comparative Plots\n", "\n", "Comparative EDA addresses questions that arise in interlaboratory studies,\n", "block designs, and multivariate profiling:\n", "\n", "- **Block plot** \u2014 do treatment effects replicate across blocks (labs, operators)?\n", "- **Youden plot** \u2014 do two labs agree, and is any disagreement a shift or a scale change?\n", "- **Star plot** \u2014 what is the multivariate profile of each specimen?\n", "\n", "Reference: [NIST Handbook Chapter 2.5](https://www.itl.nist.gov/div898/handbook/mpc/mpc.htm)" ] }, { "cell_type": "code", "execution_count": null, "id": "2f3be1d0", "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "from drippy import EDAData\n", "from drippy import block_plot, youden_plot, star_plot\n", "\n", "rng = np.random.default_rng(42)" ] }, { "cell_type": "markdown", "id": "ca061695", "metadata": {}, "source": [ "## Block Plot (NIST 1.3.3.3)\n", "\n", "Shows treatment effects within each block as connected lines \u2014 one\n", "line per block. If lines are parallel, the treatment effect is\n", "consistent across blocks (no block \u00d7 treatment interaction).\n", "\n", "Requires `factors` with keys `\"treatment\"` and `\"block\"`." ] }, { "cell_type": "code", "execution_count": null, "id": "01238bc7", "metadata": {}, "outputs": [], "source": [ "# 8 blocks (labs), 2 treatments per block\n", "treatments = np.tile([\"T1\", \"T2\"], 8)\n", "blocks = np.repeat([f\"Lab{i}\" for i in range(1, 9)], 2)\n", "y_block = rng.normal(size=16) + (treatments == \"T2\") * 0.8\n", "data_block = EDAData(\n", " y=y_block,\n", " factors={\"treatment\": treatments, \"block\": blocks},\n", ")\n", "\n", "fig, ax = block_plot(data_block)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "c838043e", "metadata": {}, "source": [ "In this simulated run, T2 generally scores higher than T1 across most labs \u2014 the lines\nare approximately parallel, suggesting limited lab \u00d7 treatment interaction.\n\n## Youden Plot (NIST 1.3.3.31)\n\nCompares measurements from two labs on the same set of specimens.\nPass Lab 1 as `y` and Lab 2 as `x`.\n\n- Points on the diagonal: labs agree\n- Vertical shift from diagonal: Lab 1 bias\n- Points scattered off diagonal: random lab-to-lab variability" ] }, { "cell_type": "code", "execution_count": null, "id": "712ebcba", "metadata": {}, "outputs": [], "source": [ "# 20 specimens measured by two labs\n", "lab1 = rng.normal(loc=10.0, scale=0.5, size=20)\n", "lab2 = lab1 + rng.normal(loc=0.2, scale=0.3, size=20) # Lab 2 has a slight bias\n", "data_youden = EDAData(y=lab1, x=lab2)\n", "\n", "fig, ax = youden_plot(data_youden)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "fff9dfab", "metadata": {}, "source": [ "The median lines reveal a small positive bias in Lab 2 relative to Lab 1.\n", "\n", "## Star Plot (NIST 1.3.3.29)\n", "\n", "Radar / spider chart for multivariate data. Each spoke represents\n", "one variable (normalised 0\u20131); each polygon represents one observation.\n", "\n", "Pass additional variables via `factors`. The response variable `y`\n", "appears automatically as the first spoke." ] }, { "cell_type": "code", "execution_count": null, "id": "5b55ba72", "metadata": {}, "outputs": [], "source": [ "# 5 specimens characterised by 4 material properties\n", "n = 5\n", "hardness = rng.uniform(0.4, 1.0, n)\n", "toughness = rng.uniform(0.3, 0.9, n)\n", "conductivity = rng.uniform(0.1, 0.8, n)\n", "strength = rng.uniform(0.5, 1.0, n)\n", "data_star = EDAData(\n", " y=strength,\n", " factors={\n", " \"Hardness\": hardness,\n", " \"Toughness\": toughness,\n", " \"Conductivity\": conductivity,\n", " },\n", ")\n", "\n", "fig, ax = star_plot(data_star)\n", "plt.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.12.0" } }, "nbformat": 4, "nbformat_minor": 5 }