{"spec_id":"chernoff-basic","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nchernoff-basic: Chernoff Faces for Multivariate Data\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 88/100 | Updated: 2026-05-15\n\"\"\"\n\nimport matplotlib.patches as patches\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n\n# Data - Car performance metrics (9 vehicles with 4 attributes)\n# Attributes: fuel efficiency, power, reliability, comfort (all 0-1 normalized)\nnp.random.seed(42)\n\n# Create 3 categories of cars with distinct characteristics\n# Economy cars: high efficiency, low power, medium reliability, medium comfort\n# Sports cars: low efficiency, high power, medium reliability, low comfort\n# Luxury cars: medium efficiency, medium power, high reliability, high comfort\ncategories = [\"Economy\", \"Sports\", \"Luxury\"]\nn_per_category = 3\n\n# Generate synthetic data with category-specific distributions\ndata = []\nlabels = []\ncategory_ids = []\n\n# Economy cars - high efficiency, low power\nfor i in range(n_per_category):\n    data.append(\n        [\n            0.7 + np.random.rand() * 0.25,  # fuel_efficiency: 0.7-0.95\n            0.2 + np.random.rand() * 0.2,  # power: 0.2-0.4\n            0.4 + np.random.rand() * 0.3,  # reliability: 0.4-0.7\n            0.3 + np.random.rand() * 0.3,  # comfort: 0.3-0.6\n        ]\n    )\n    labels.append(f\"Economy {i + 1}\")\n    category_ids.append(0)\n\n# Sports cars - low efficiency, high power\nfor i in range(n_per_category):\n    data.append(\n        [\n            0.15 + np.random.rand() * 0.2,  # fuel_efficiency: 0.15-0.35\n            0.75 + np.random.rand() * 0.2,  # power: 0.75-0.95\n            0.4 + np.random.rand() * 0.25,  # reliability: 0.4-0.65\n            0.25 + np.random.rand() * 0.25,  # comfort: 0.25-0.5\n        ]\n    )\n    labels.append(f\"Sports {i + 1}\")\n    category_ids.append(1)\n\n# Luxury cars - high reliability and comfort\nfor i in range(n_per_category):\n    data.append(\n        [\n            0.35 + np.random.rand() * 0.25,  # fuel_efficiency: 0.35-0.6\n            0.5 + np.random.rand() * 0.25,  # power: 0.5-0.75\n            0.7 + np.random.rand() * 0.25,  # reliability: 0.7-0.95\n            0.7 + np.random.rand() * 0.25,  # comfort: 0.7-0.95\n        ]\n    )\n    labels.append(f\"Luxury {i + 1}\")\n    category_ids.append(2)\n\nX_norm = np.array(data)\ncolors = [\"#306998\", \"#FFD43B\", \"#4CAF50\"]  # Python Blue, Yellow, Green\n\n# Create figure - 3x3 grid of faces (square format for symmetric grid)\nfig, ax = plt.subplots(figsize=(12, 12))\n\n# Calculate grid positions with better spacing\nn_cols = 3\nn_rows = 3\nx_positions = np.linspace(0.22, 0.78, n_cols)\ny_positions = np.linspace(0.76, 0.28, n_rows)  # More space between rows\n\n# Draw each Chernoff face\nfor idx in range(len(X_norm)):\n    row = idx // n_cols\n    col = idx % n_cols\n    x_center = x_positions[col]\n    y_center = y_positions[row]\n    features = X_norm[idx]\n    color = colors[category_ids[idx]]\n    label = labels[idx]\n\n    # Feature mappings (all features in 0-1 range):\n    # - features[0]: face width (fuel efficiency)\n    # - features[1]: face height (power)\n    # - features[2]: eye size (reliability)\n    # - features[3]: mouth curvature (comfort) - happy = high comfort\n\n    # Scale down faces to prevent overlap\n    face_width = 0.12 + features[0] * 0.06  # 0.12-0.18\n    face_height = 0.14 + features[1] * 0.06  # 0.14-0.20\n    eye_size = 0.015 + features[2] * 0.015  # 0.015-0.03\n    mouth_curve = -0.05 + features[3] * 0.10  # -0.05 to 0.05 (sad to happy)\n\n    # Face ellipse\n    face = patches.Ellipse(\n        (x_center, y_center), face_width, face_height, facecolor=color, edgecolor=\"black\", linewidth=2.5, alpha=0.75\n    )\n    ax.add_patch(face)\n\n    # Eyes - position relative to face\n    eye_y = y_center + face_height * 0.18\n    eye_x_offset = face_width * 0.22\n\n    # Left eye (white with pupil)\n    left_eye = patches.Ellipse(\n        (x_center - eye_x_offset, eye_y), eye_size * 1.6, eye_size, facecolor=\"white\", edgecolor=\"black\", linewidth=1.5\n    )\n    ax.add_patch(left_eye)\n    left_pupil = patches.Circle((x_center - eye_x_offset, eye_y), eye_size * 0.35, facecolor=\"black\")\n    ax.add_patch(left_pupil)\n\n    # Right eye\n    right_eye = patches.Ellipse(\n        (x_center + eye_x_offset, eye_y), eye_size * 1.6, eye_size, facecolor=\"white\", edgecolor=\"black\", linewidth=1.5\n    )\n    ax.add_patch(right_eye)\n    right_pupil = patches.Circle((x_center + eye_x_offset, eye_y), eye_size * 0.35, facecolor=\"black\")\n    ax.add_patch(right_pupil)\n\n    # Eyebrows - angle based on power (higher power = more intense)\n    brow_y = eye_y + eye_size * 1.4\n    brow_length = eye_size * 1.3\n    brow_angle = (features[1] - 0.5) * 0.015  # Angle variation\n\n    ax.plot(\n        [x_center - eye_x_offset - brow_length / 2, x_center - eye_x_offset + brow_length / 2],\n        [brow_y + brow_angle, brow_y - brow_angle],\n        color=\"black\",\n        linewidth=2.5,\n        solid_capstyle=\"round\",\n    )\n    ax.plot(\n        [x_center + eye_x_offset - brow_length / 2, x_center + eye_x_offset + brow_length / 2],\n        [brow_y - brow_angle, brow_y + brow_angle],\n        color=\"black\",\n        linewidth=2.5,\n        solid_capstyle=\"round\",\n    )\n\n    # Nose - simple vertical line with base\n    nose_height = 0.015 + features[1] * 0.01\n    nose_y_top = y_center + nose_height * 0.3\n    nose_y_bottom = y_center - nose_height * 0.7\n    ax.plot([x_center, x_center], [nose_y_top, nose_y_bottom], color=\"black\", linewidth=2)\n    # Nose base\n    ax.plot([x_center - 0.005, x_center + 0.005], [nose_y_bottom, nose_y_bottom], color=\"black\", linewidth=2)\n\n    # Mouth - curved based on comfort\n    mouth_y = y_center - face_height * 0.28\n    mouth_width_val = 0.02 + features[0] * 0.015\n\n    mouth_x = np.linspace(-mouth_width_val / 2, mouth_width_val / 2, 30)\n    mouth_y_curve = mouth_y + mouth_curve * (1 - (2 * mouth_x / mouth_width_val) ** 2)\n    ax.plot(x_center + mouth_x, mouth_y_curve, color=\"black\", linewidth=3, solid_capstyle=\"round\")\n\n    # Label below face (positioned further down to avoid overlap)\n    ax.text(\n        x_center, y_center - face_height * 0.65 - 0.02, label, ha=\"center\", va=\"top\", fontsize=13, fontweight=\"bold\"\n    )\n\n# Styling\nax.set_xlim(0, 1)\nax.set_ylim(0, 1)\nax.set_aspect(\"equal\")\nax.axis(\"off\")\n\n# Title\nax.set_title(\"Car Ratings · chernoff-basic · matplotlib · pyplots.ai\", fontsize=24, fontweight=\"bold\", pad=20)\n\n# Feature mapping legend (bottom left, moved down to avoid overlap)\nlegend_text = (\n    \"Feature Mapping:\\nFace Width = Fuel Efficiency\\nFace Height = Power\\nEye Size = Reliability\\nMouth Curve = Comfort\"\n)\nax.text(\n    0.02,\n    0.01,\n    legend_text,\n    transform=ax.transAxes,\n    fontsize=11,\n    verticalalignment=\"bottom\",\n    fontfamily=\"monospace\",\n    bbox={\"boxstyle\": \"round\", \"facecolor\": \"white\", \"alpha\": 0.95, \"edgecolor\": \"gray\"},\n)\n\n# Category legend (upper right)\nfor i, category in enumerate(categories):\n    ax.scatter([], [], c=colors[i], s=250, label=category, alpha=0.75, edgecolors=\"black\")\nax.legend(loc=\"upper right\", fontsize=14, title=\"Category\", title_fontsize=16, framealpha=0.95, edgecolor=\"gray\")\n\nplt.tight_layout()\nplt.savefig(\"plot.png\", dpi=300, bbox_inches=\"tight\", facecolor=\"white\")\n"}