{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "e7f2dbbd", "metadata": {}, "outputs": [], "source": [ "# This script generates a sample \"Monsoon Mandala\" artwork using placeholder data. \n", "# Replace the synthetic data block with your real pandas DataFrame columns to recreate the piece with your tea farm data.\n", "\n", "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "weatherdata_df = pd.read_csv(\"data/kit_1001_2025-09-22.csv\", index_col=2)\n", "weatherdata_df.drop(columns=['kit_id', \"unit\",\"_raw\"], inplace=True)\n", "weatherdata_df.dropna(inplace=True)\n", "weatherdata_df.index = pd.to_datetime(weatherdata_df.index)\n", "weatherdata_df = weatherdata_df.pivot(columns='sensor', values='value')\n", "weatherdata_df.columns" ] }, { "cell_type": "code", "execution_count": null, "id": "18a06b7d", "metadata": {}, "outputs": [], "source": [ "weatherdata_df.columns" ] }, { "cell_type": "code", "execution_count": null, "id": "4dadce7a", "metadata": {}, "outputs": [], "source": [ "# ---- Mapping to polar \"Monsoon Mandala\" ----\n", "# Angles map to time; radii encode a blended metric; thickness & dot size encode other variables.\n", "\n", "df = weatherdata_df\n", "theta = np.linspace(0, 2*np.pi, len(df), endpoint=False)\n", "\n", "# Normalize helpers (avoid specifying colors, per instructions).\n", "def norm(x):\n", " x = np.asarray(x)\n", " if np.nanmax(x) - np.nanmin(x) == 0:\n", " return np.zeros_like(x)\n", " return (x - np.nanmin(x)) / (np.nanmax(x) - np.nanmin(x))\n", "\n", "T = norm(df['ftTemp'].values)\n", "H = norm(df['gbHum'].values)\n", "R = norm(df['NH3'].values)\n", "W = norm(df['C3H8'].values)\n", "L = norm(df['CO'].values)\n", "\n", "# Radius combines temp (outer breathing), humidity (inner swell), light (diurnal bloom)\n", "radius = 0.45 + 0.35*(0.5*T + 0.3*H + 0.2*L)\n", "\n", "# Stroke width from wind; point size from rainfall intensity\n", "stroke = 0.3 + 3.2*W\n", "dots = 5 + 60*R\n", "\n", "# Rolling medians for smooth rings\n", "def smooth(x, k=21):\n", " if k < 3: \n", " return x\n", " w = np.ones(k)/k\n", " return np.convolve(x, w, mode=\"same\")\n", "\n", "radius_smooth = smooth(radius, k=31)\n", "\n", "# ---- Plot (no explicit colors; uses matplotlib defaults) ----\n", "plt.figure(figsize=(8, 8))\n", "ax = plt.subplot(111, projection=\"polar\")\n", "ax.set_theta_direction(-1) # clockwise\n", "ax.set_theta_offset(np.pi/2.0) # start at top\n", "ax.set_axis_off()\n", "\n", "# Outer ribbon\n", "ax.plot(theta, radius_smooth, linewidth=2.0)\n", "\n", "# Inner filigree rings\n", "for k in [3, 7, 13]:\n", " ax.plot(theta, smooth(radius * (0.85 + 0.05*np.sin(k*theta)), k=15), linewidth=0.8)\n", "\n", "# Rainfall pearls\n", "ax.scatter(theta[::3], (radius_smooth*0.92)[::3], s=dots[::3], alpha=0.6)\n", "\n", "# Wind tick marks (radial sticks)\n", "for th, rr, sw in zip(theta[::12], radius_smooth[::12], stroke[::12]):\n", " ax.plot([th, th], [rr*0.75, rr*0.98], linewidth=sw*0.12, alpha=0.8)\n", "\n", "plt.tight_layout()\n", "png_path = \"output/monsoon_mandala_example.png\"\n", "svg_path = \"output/monsoon_mandala_example.svg\"\n", "plt.savefig(png_path, dpi=300, bbox_inches=\"tight\", pad_inches=0.05)\n", "plt.savefig(svg_path, bbox_inches=\"tight\", pad_inches=0.05)\n", "png_path, svg_path\n" ] } ], "metadata": { "kernelspec": { "display_name": "datascience", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.4" } }, "nbformat": 4, "nbformat_minor": 5 }