{ "cells": [ { "cell_type": "markdown", "id": "f88c95dc", "metadata": {}, "source": [ "# `geomSpoke()`" ] }, { "cell_type": "code", "execution_count": 1, "id": "e0c1ea2b", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%useLatestDescriptors\n", "%use lets-plot" ] }, { "cell_type": "code", "execution_count": 2, "id": "fa88b440", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Lets-Plot Kotlin API v.4.6.0. Frontend: Notebook with dynamically loaded JS. Lets-Plot JS v.4.2.0." ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "LetsPlot.getInfo()" ] }, { "cell_type": "code", "execution_count": 3, "id": "contrary-baltimore", "metadata": {}, "outputs": [], "source": [ "fun linspace(start: Double, stop: Double, num: Int): DoubleArray {\n", " return DoubleArray(num) { i -> start + i * (stop - start) / (num - 1) }\n", "}\n", "\n", "fun meshgrid(x: DoubleArray, y: DoubleArray): Pair {\n", " val X = DoubleArray(x.size * y.size) { i -> x[i % x.size] }\n", " val Y = DoubleArray(x.size * y.size) { i -> y[i / x.size] }\n", " return Pair(X, Y)\n", "}\n", " \n", "fun gradient(Z: DoubleArray, d: Double, n: Int): Pair {\n", " val matrix = Z.toList().chunked(n)\n", " val dY = mutableListOf()\n", " val dX = mutableListOf()\n", " for (i in 0 until n) {\n", " for (j in 0 until n) {\n", " val y = if (i > 0) (matrix[i][j] - matrix[i - 1][j]) / d else 0.0\n", " val x = if (j > 0) (matrix[i][j] - matrix[i][j - 1]) / d else 0.0\n", " dY += y\n", " dX += x\n", " }\n", " }\n", " return Pair(dY.toDoubleArray(), dX.toDoubleArray())\n", "}\n", "\n", "fun getData(n: Int, a: Double, b: Double, f: (DoubleArray, DoubleArray) -> DoubleArray): Map {\n", " val d = (b - a) / (n - 1)\n", " \n", " val xrange = linspace(a, b, n)\n", " val yrange = linspace(a, b, n)\n", " \n", " val (x, y) = meshgrid(xrange, yrange)\n", " val z = f(x, y)\n", "\n", " val (dY, dX) = gradient(z, d, n)\n", " val r = DoubleArray(dX.size) { index -> sqrt(dX[index].pow(2) + dY[index].pow(2)) }\n", " val rMax = r.max()\n", " val radius = DoubleArray(r.size) { index -> r[index] / rMax * d }\n", " val angle = DoubleArray(dY.size) { index -> atan2(dY[index], dX[index]) }\n", " \n", " return mapOf(\n", " \"x\" to x, \n", " \"y\" to y, \n", " \"z\" to z, \n", " \"radius\" to radius, \n", " \"angle\" to angle\n", " )\n", "}" ] }, { "cell_type": "code", "execution_count": 4, "id": "likely-samba", "metadata": {}, "outputs": [], "source": [ "val data = getData(n = 21, a = -2*PI, b = 2*PI) { xArray, yArray ->\n", " DoubleArray(xArray.size) { index -> sin(xArray[index]) + cos(yArray[index]) }\n", "}" ] }, { "cell_type": "code", "execution_count": 5, "id": "absent-blame", "metadata": {}, "outputs": [], "source": [ "val p = letsPlot(data) { x = \"x\"; y = \"y\" } + \n", " coordFixed() + themeVoid() +\n", " scaleViridis(listOf(\"fill\", \"color\"))" ] }, { "cell_type": "code", "execution_count": 6, "id": "54a0a66d", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p + geomBin2D(stat = Stat.identity) { fill = \"z\" }" ] }, { "cell_type": "markdown", "id": "twenty-watershed", "metadata": {}, "source": [ "#### 1. Use `geomSpoke()` to Indicate the Direction and Distance (or Speed)" ] }, { "cell_type": "code", "execution_count": 7, "id": "58ae9962", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p + geomPoint(size = 1.5) + geomSpoke { angle = \"angle\"; radius = \"radius\"; color = \"z\" }" ] }, { "cell_type": "markdown", "id": "6d4a96a5", "metadata": {}, "source": [ "#### 2. Parameter `pivot`" ] }, { "cell_type": "code", "execution_count": 8, "id": "c1e815fa", "metadata": {}, "outputs": [], "source": [ "fun getPlot(pivot: String): org.jetbrains.letsPlot.intern.Plot {\n", " val a = -3.0\n", " val b = 3.0 \n", " val r = 0.75\n", " val pivotData = getData(\n", " n = 4, \n", " a = a,\n", " b = b\n", " ) { xArray, yArray -> DoubleArray(xArray.size) { index -> xArray[index].pow(2) + yArray[index].pow(2) } }\n", " val title = \"pivot=${pivot}\" + (\" (default)\".takeIf { pivot == \"tail\" } ?: \"\")\n", " return ggplot(pivotData) { x = \"x\"; y = \"y\" } +\n", " geomPoint() +\n", " geomSpoke(radius = r, pivot = pivot) { angle = \"angle\" } +\n", " coordFixed() +\n", " xlim(a - r to b + r) + ylim(a - r to b + r) +\n", " ggtitle(title) +\n", " themeVoid() + theme(plotTitle = elementText(hjust = 0.5))\n", "}" ] }, { "cell_type": "code", "execution_count": 9, "id": "3ea5cdc0", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gggrid(\n", " listOf(getPlot(\"tail\"), getPlot(\"mid\"), getPlot(\"tip\")),\n", " ncol=3\n", ")" ] } ], "metadata": { "kernelspec": { "display_name": "Kotlin", "language": "kotlin", "name": "kotlin" }, "language_info": { "codemirror_mode": "text/x-kotlin", "file_extension": ".kt", "mimetype": "text/x-kotlin", "name": "kotlin", "nbconvert_exporter": "", "pygments_lexer": "kotlin", "version": "1.8.20" } }, "nbformat": 4, "nbformat_minor": 5 }