{"spec_id":"kagi-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nkagi-basic: Basic Kagi Chart\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 94/100 | Updated: 2026-05-17\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\n\n# Configure seaborn theme with theme-adaptive chrome\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"grid.color\": INK,\n        \"grid.alpha\": 0.10,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Generate synthetic cryptocurrency price data (different domain from altair)\nnp.random.seed(42)\nn_periods = 180\n\n# Create mean-reverting cryptocurrency price movements (different volatility regime from stock data)\n# Simulates crypto volatility with price oscillations around a trend\nprices = [10000]\nfor _ in range(n_periods - 1):\n    # Mean reversion toward 11000 with higher volatility\n    drift = 0.0002 * (11000 - prices[-1]) / 11000\n    volatility = np.random.normal(drift, 0.035, 1)[0]\n    new_price = prices[-1] * (1 + volatility)\n    prices.append(max(new_price, 1000))  # Prevent negative prices\n\nprices = np.array(prices)\n\n# Kagi chart parameters\nreversal_threshold = 0.05  # 5% reversal (crypto-appropriate)\n\n# Build Kagi chart segments from price data\nsegments = []\ndirection = None\ncurrent_price = prices[0]\nlast_high = prices[0]\nlast_low = prices[0]\n\nfor price in prices[1:]:\n    if direction is None:\n        if price > current_price * (1 + reversal_threshold):\n            direction = 1\n            segments.append({\"start\": current_price, \"end\": price, \"yang\": True})\n            last_high = max(last_high, price)\n            current_price = price\n        elif price < current_price * (1 - reversal_threshold):\n            direction = -1\n            segments.append({\"start\": current_price, \"end\": price, \"yang\": False})\n            last_low = min(last_low, price)\n            current_price = price\n    elif direction == 1:\n        if price > current_price:\n            if segments:\n                segments[-1][\"end\"] = price\n                segments[-1][\"yang\"] = price > last_high\n            current_price = price\n            last_high = max(last_high, price)\n        elif price < current_price * (1 - reversal_threshold):\n            direction = -1\n            segments.append({\"start\": current_price, \"end\": price, \"yang\": False})\n            current_price = price\n            if price < last_low:\n                last_low = price\n    else:\n        if price < current_price:\n            if segments:\n                segments[-1][\"end\"] = price\n                segments[-1][\"yang\"] = False\n            current_price = price\n            last_low = min(last_low, price)\n        elif price > current_price * (1 + reversal_threshold):\n            direction = 1\n            segments.append({\"start\": current_price, \"end\": price, \"yang\": True})\n            current_price = price\n            if price > last_high:\n                last_high = price\n\n# Build data for plotting\nline_data = []\nline_id = 0\n\nfor i, seg in enumerate(segments):\n    segment_type = \"Yang\" if seg[\"yang\"] else \"Yin\"\n\n    # Vertical line segment\n    line_data.append({\"x\": i, \"y\": seg[\"start\"], \"segment\": line_id, \"type\": segment_type})\n    line_data.append({\"x\": i, \"y\": seg[\"end\"], \"segment\": line_id, \"type\": segment_type})\n    line_id += 1\n\n    # Horizontal connector to next segment\n    if i < len(segments) - 1:\n        line_data.append({\"x\": i, \"y\": seg[\"end\"], \"segment\": line_id, \"type\": segment_type})\n        line_data.append({\"x\": i + 1, \"y\": seg[\"end\"], \"segment\": line_id, \"type\": segment_type})\n        line_id += 1\n\ndf = pd.DataFrame(line_data)\n\n# Create figure\nfig, ax = plt.subplots(figsize=(16, 9))\n\n# imprint semantic anchors (green for bullish, red for bearish)\ncolor_yang = \"#009E73\"  # imprint green — bullish\ncolor_yin = \"#AE3030\"  # imprint red — bearish\n\n# Plot Yang (bullish) and Yin (bearish) segments with different line widths\nfor segment_type, color, linewidth in [(\"Yang\", color_yang, 4.5), (\"Yin\", color_yin, 1.5)]:\n    type_df = df[df[\"type\"] == segment_type]\n    for seg_id in type_df[\"segment\"].unique():\n        seg_df = type_df[type_df[\"segment\"] == seg_id]\n        ax.plot(seg_df[\"x\"], seg_df[\"y\"], color=color, linewidth=linewidth, solid_capstyle=\"butt\")\n\n# Create legend with manual line artists\nyang_line = plt.Line2D([0], [0], color=color_yang, linewidth=4.5, label=\"Yang (Bullish)\")\nyin_line = plt.Line2D([0], [0], color=color_yin, linewidth=1.5, label=\"Yin (Bearish)\")\nax.legend(handles=[yang_line, yin_line], loc=\"upper left\", fontsize=16, framealpha=0.95, frameon=True)\n\n# Labels and styling\nax.set_xlabel(\"Kagi Line Index\", fontsize=20, color=INK)\nax.set_ylabel(\"Price ($)\", fontsize=20, color=INK)\nax.set_title(\"kagi-basic · seaborn · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT)\n\n# Grid: solid lines with very low opacity\nax.yaxis.grid(True, alpha=0.10, linewidth=0.8, linestyle=\"-\", color=INK)\nax.set_axisbelow(True)\n\n# Remove top and right spines\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.spines[\"left\"].set_color(INK_SOFT)\nax.spines[\"bottom\"].set_color(INK_SOFT)\n\n# Set axis limits with padding\ny_min = min(min(seg[\"start\"], seg[\"end\"]) for seg in segments)\ny_max = max(max(seg[\"start\"], seg[\"end\"]) for seg in segments)\npadding = (y_max - y_min) * 0.1\nax.set_ylim(y_min - padding, y_max + padding)\nax.set_xlim(-1, len(segments))\n\nplt.tight_layout()\n\n# Save to the script's directory\nscript_dir = os.path.dirname(os.path.abspath(__file__))\noutput_path = os.path.join(script_dir, f\"plot-{THEME}.png\")\nplt.savefig(output_path, dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\nplt.close()\n"}