{ "cells": [ { "cell_type": "markdown", "id": "6f013234", "metadata": {}, "source": [ "# Manipulating coordinate values" ] }, { "cell_type": "code", "execution_count": null, "id": "0aa9e4ac", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import scipy as sp\n", "\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "\n", "from ktch.datasets import load_outline_mosquito_wings" ] }, { "cell_type": "code", "execution_count": null, "id": "8071f111", "metadata": {}, "outputs": [], "source": [ "data_outline_mosquito_wings = load_outline_mosquito_wings(as_frame=True)\n", "coords = data_outline_mosquito_wings.coords.to_numpy().reshape(-1,100,2)" ] }, { "cell_type": "markdown", "id": "8bd3de90", "metadata": {}, "source": [ "## Translation\n", "\n", "You can translate the coordinate values of outline data using list comprehension." ] }, { "cell_type": "code", "execution_count": null, "id": "e714d214", "metadata": {}, "outputs": [], "source": [ "rng = np.random.default_rng()\n", "dx = rng.normal(0, 1, size=coords.shape[0::2])\n", "coords_translated = [coords[i] + dx[i] for i in range(len(coords))]" ] }, { "cell_type": "code", "execution_count": null, "id": "3c050484", "metadata": {}, "outputs": [], "source": [ "idx = 0\n", "\n", "fig, ax = plt.subplots()\n", "sns.lineplot(x=coords[idx][:,0], y=coords[idx][:,1], sort= False,estimator=None,ax=ax)\n", "sns.lineplot(x=coords_translated[idx][:,0], y=coords_translated[idx][:,1], sort= False,estimator=None,ax=ax)\n", "ax.set_aspect('equal')\n", "print(\"displacement: \", dx[idx])" ] }, { "cell_type": "markdown", "id": "49f3fe93", "metadata": {}, "source": [ "If the coordinate values are stored as `np.ndarray`, \n", "you can simply add the displacement vectors after `reshape(n_spesimens, 1, n_dim)`." ] }, { "cell_type": "code", "execution_count": null, "id": "a1c2a759", "metadata": {}, "outputs": [], "source": [ "coords_translated_array = coords + dx.reshape(dx.shape[0], 1, dx.shape[1])\n", "\n", "idx = 0\n", "\n", "fig, ax = plt.subplots()\n", "sns.lineplot(x=coords[idx][:,0], y=coords[idx][:,1], sort= False,estimator=None,ax=ax)\n", "sns.lineplot(x=coords_translated_array[idx][:,0], y=coords_translated_array[idx][:,1], sort= False,estimator=None,ax=ax)\n", "ax.set_aspect('equal')\n", "print(\"displacement: \", dx[idx])" ] }, { "cell_type": "markdown", "id": "93ea6ae7", "metadata": {}, "source": [ "## Scaling" ] }, { "cell_type": "code", "execution_count": null, "id": "5fd4e7c7", "metadata": {}, "outputs": [], "source": [ "s = rng.uniform(0.5,1.5, size=coords.shape[0])\n", "coords_scaled = [s[i]*coords[i] for i in range(len(coords))]" ] }, { "cell_type": "code", "execution_count": null, "id": "ba30cfc7", "metadata": {}, "outputs": [], "source": [ "idx = 0\n", "\n", "fig, ax = plt.subplots()\n", "sns.lineplot(x=coords[idx][:,0], y=coords[idx][:,1], sort= False,estimator=None,ax=ax)\n", "sns.lineplot(x=coords_scaled[idx][:,0], y=coords_scaled[idx][:,1], sort= False,estimator=None,ax=ax)\n", "ax.set_aspect('equal')\n", "print(\"scale: \", s[idx])" ] }, { "cell_type": "markdown", "id": "1f202dfe", "metadata": {}, "source": [ "If the coordinate values are stored as `np.ndarray`, \n", "you can simply add the displacement vectors after `reshape(n_spesimens, 1, 1)`." ] }, { "cell_type": "code", "execution_count": null, "id": "9d72afba", "metadata": {}, "outputs": [], "source": [ "coords_scaled_arr = s.reshape(s.shape[0], 1, 1)*coords\n", "\n", "idx = 0\n", "\n", "fig, ax = plt.subplots()\n", "sns.lineplot(x=coords[idx][:,0], y=coords[idx][:,1], sort= False,estimator=None,ax=ax)\n", "sns.lineplot(x=coords_scaled_arr[idx][:,0], y=coords_scaled_arr[idx][:,1], sort= False,estimator=None,ax=ax)\n", "ax.set_aspect('equal')\n", "print(\"scale: \", s[idx])" ] }, { "cell_type": "markdown", "id": "869c26ee", "metadata": {}, "source": [ "## Rotation\n", "We provide `rotation_matrix_2d` helper function to generate the rotation matrix.\n", "\n", "Alternatively, you can use `scipy.spatial.transform.Rotation` or define by yourself." ] }, { "cell_type": "code", "execution_count": null, "id": "bc8edaa5", "metadata": {}, "outputs": [], "source": [ "from ktch.outline import rotation_matrix_2d\n", "from scipy.spatial.transform import Rotation as R" ] }, { "cell_type": "code", "execution_count": null, "id": "2a05a232", "metadata": {}, "outputs": [], "source": [ "theta = np.pi/4\n", "print(rotation_matrix_2d(theta))\n", "print(R.from_rotvec(theta*np.array([0,0,1])).as_matrix()[0:2,0:2])\n", "print(np.array([[np.cos(theta),-np.sin(theta)],[np.sin(theta), np.cos(theta)]]))" ] }, { "cell_type": "code", "execution_count": null, "id": "e61b3d21", "metadata": {}, "outputs": [], "source": [ "theta = rng.uniform(0, 2*np.pi, size=coords.shape[0])\n", "coords_rotated = [(rotation_matrix_2d(theta[i]) @ coords[i].T).T for i in range(len(coords))]" ] }, { "cell_type": "code", "execution_count": null, "id": "78c3db02", "metadata": {}, "outputs": [], "source": [ "idx = 0\n", "\n", "fig, ax = plt.subplots()\n", "sns.lineplot(x=coords[idx][:,0], y=coords[idx][:,1], sort= False,estimator=None,ax=ax)\n", "sns.lineplot(x=coords_rotated[idx][:,0], y=coords_rotated[idx][:,1], sort= False,estimator=None,ax=ax)\n", "ax.set_aspect('equal')\n", "print(\"theta: \", theta[idx])" ] }, { "cell_type": "markdown", "id": "3b6004cb", "metadata": {}, "source": [ "When the coordinate values are stored as `np.ndarray`, \n", "the rotated array is calculated by applying the `matmul (@)` operator on the array of rotation matrixes transposed to `n_samples x n_dim x n_dim` and the array of the coordinate values transposed to `n_samples x n_dim x n_coordinates`." ] }, { "cell_type": "code", "execution_count": null, "id": "fc1daaf7", "metadata": {}, "outputs": [], "source": [ "coords_rotated_arr = (rotation_matrix_2d(theta).transpose(2, 0, 1) @ coords.transpose(0, 2, 1)).transpose(0, 2, 1)\n", "\n", "idx = 0\n", "\n", "fig, ax = plt.subplots()\n", "sns.lineplot(x=coords[idx][:,0], y=coords[idx][:,1], sort= False,estimator=None,ax=ax)\n", "sns.lineplot(x=coords_rotated_arr[idx][:,0], y=coords_rotated_arr[idx][:,1], sort= False,estimator=None,ax=ax)\n", "ax.set_aspect('equal')\n", "print(\"scale: \", s[idx])" ] }, { "cell_type": "markdown", "id": "30e8e2b0", "metadata": {}, "source": [ "## Changing the starting point\n", "The starting point (arclength parameter $t = 0$) is often adjusted for aligning the outlines.\n", "\n", "You can use the `numpy.roll` function for the purpose." ] }, { "cell_type": "code", "execution_count": null, "id": "bbd1a58d", "metadata": {}, "outputs": [], "source": [ "new_staring_points = np.array([rng.integers(0,len(coord)) for coord in coords], dtype=int)\n", "coords_changed_start = [np.roll(coords[i], -new_staring_points[i], axis=0) for i in range(len(coords))]" ] }, { "cell_type": "code", "execution_count": null, "id": "8f2b86c5", "metadata": {}, "outputs": [], "source": [ "idx = 0\n", "\n", "fig, ax = plt.subplots(1,2, figsize=(12,7))\n", "sns.lineplot(x=coords[idx][:,0], y=coords[idx][:,1], sort= False,estimator=None,ax=ax[0])\n", "sns.lineplot(x=coords_changed_start[idx][:,0], y=coords_changed_start[idx][:,1], \n", " sort= False,color=\"C1\",estimator=None,ax=ax[1])\n", "ax[0].set_aspect('equal')\n", "ax[1].set_aspect('equal')\n", "print(\"starting point: \", new_staring_points[idx])" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 5 }