{ "cells": [ { "cell_type": "markdown", "id": "d0c62ff2-28be-4b58-ad5c-fbbe22dc8f65", "metadata": {}, "source": [ "# Unit Test for calculate_diversity_index" ] }, { "cell_type": "code", "execution_count": 1, "id": "66bee91f-e73b-4692-9060-836cb6bc331f", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/opt/miniconda3/envs/mesa/lib/python3.11/site-packages/geopandas/_compat.py:106: UserWarning: The Shapely GEOS version (3.8.0-CAPI-1.13.1) is incompatible with the GEOS version PyGEOS was compiled with (3.10.4-CAPI-1.16.2). Conversions between both will be slow.\n", " warnings.warn(\n", "OMP: Info #276: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.\n", "/opt/miniconda3/envs/mesa/lib/python3.11/site-packages/spaghetti/network.py:41: FutureWarning: The next major release of pysal/spaghetti (2.0.0) will drop support for all ``libpysal.cg`` geometries. This change is a first step in refactoring ``spaghetti`` that is expected to result in dramatically reduced runtimes for network instantiation and operations. Users currently requiring network and point pattern input as ``libpysal.cg`` geometries should prepare for this simply by converting to ``shapely`` geometries.\n", " warnings.warn(dep_msg, FutureWarning, stacklevel=1)\n" ] } ], "source": [ "import unittest\n", "import numpy as np\n", "import pandas as pd\n", "import anndata as ad\n", "from unittest.mock import patch\n", "import os\n", "os.sys.path.append('../../../')\n", " \n", "from mesa import ecospatial as eco" ] }, { "cell_type": "code", "execution_count": 2, "id": "903af872-5da4-470c-9bb9-bcedfde0a4c6", "metadata": {}, "outputs": [], "source": [ "class TestCalculateDiversityIndex(unittest.TestCase):\n", "\n", " @classmethod\n", " def setUpClass(cls):\n", " # Create sample data for testing, shared among all tests\n", " print(\"Setting up test data...\")\n", " # For AnnData\n", " obs = pd.DataFrame({\n", " 'library_key': ['sample_1', 'sample_1', 'sample_2', 'sample_2', 'sample_1'],\n", " 'cluster_key': ['A', 'B', 'A', 'B', 'A']\n", " }, index=['cell1', 'cell2', 'cell3', 'cell4', 'cell5'])\n", " obsm = {'spatial_key': np.array([[0, 0], [1, 1], [2, 2], [3, 3], [0.5, 0.5]])}\n", " cls.adata = ad.AnnData(obs=obs)\n", " cls.adata.obsm = obsm\n", "\n", " # For DataFrame\n", " cls.df = pd.DataFrame({\n", " 'library_key': ['sample_1', 'sample_1', 'sample_2', 'sample_2', 'sample_1'],\n", " 'cluster_key': ['A', 'B', 'A', 'B', 'A'],\n", " 'x_coord': [0, 1, 2, 3, 0.5],\n", " 'y_coord': [0, 1, 2, 3, 0.5]\n", " }, index=['cell1', 'cell2', 'cell3', 'cell4', 'cell5'])\n", "\n", " # Patches: [(x0, y0, x1, y1), ...]\n", " cls.patches = [(0, 0, 1, 1), (2, 2, 3, 3), (0, 0, 0.6, 0.6)]\n", "\n", " def test_calculate_diversity_index_with_adata(self):\n", " # Test with AnnData input\n", " result = eco.calculate_diversity_index(\n", " spatial_data=self.adata,\n", " library_key='library_key',\n", " library_id='sample_1',\n", " spatial_key='spatial_key',\n", " patches=self.patches,\n", " cluster_key='cluster_key',\n", " metric='Shannon Diversity'\n", " )\n", "\n", " # Assert that result is a pandas Series\n", " self.assertIsInstance(result, pd.Series)\n", " # Expected indices\n", " expected_entropy_patch0 = eco.calculate_shannon_entropy([2, 1])\n", " self.assertAlmostEqual(result[0], expected_entropy_patch0)\n", " self.assertNotIn(1, result.index)\n", " expected_entropy_patch2 = eco.calculate_shannon_entropy([2])\n", " self.assertAlmostEqual(result[2], expected_entropy_patch2)\n", " self.assertEqual(len(result), 2)\n", "\n", " def test_calculate_diversity_index_with_dataframe(self):\n", " # Test with DataFrame input\n", " result = eco.calculate_diversity_index(\n", " spatial_data=self.df,\n", " library_key='library_key',\n", " library_id='sample_1',\n", " spatial_key=['x_coord', 'y_coord'],\n", " patches=self.patches,\n", " cluster_key='cluster_key',\n", " metric='Shannon Diversity'\n", " )\n", " self.assertIsInstance(result, pd.Series)\n", " expected_entropy_patch0 = eco.calculate_shannon_entropy([2, 1])\n", " self.assertAlmostEqual(result[0], expected_entropy_patch0)\n", " expected_entropy_patch2 = eco.calculate_shannon_entropy([2])\n", " self.assertAlmostEqual(result[2], expected_entropy_patch2)\n", " self.assertEqual(len(result), 2)\n", "\n", " def test_invalid_metric(self):\n", " # Test with invalid metric\n", " with self.assertRaises(ValueError) as context:\n", " eco.calculate_diversity_index(\n", " spatial_data=self.adata,\n", " library_key='library_key',\n", " library_id='sample_1',\n", " spatial_key='spatial_key',\n", " patches=self.patches,\n", " cluster_key='cluster_key',\n", " metric='Invalid Metric'\n", " )\n", " self.assertIn(\"Unknown metric\", str(context.exception))\n", "\n", " def test_invalid_spatial_data(self):\n", " # Test with invalid spatial_data type\n", " with self.assertRaises(ValueError) as context:\n", " eco.calculate_diversity_index(\n", " spatial_data='invalid_data',\n", " library_key='library_key',\n", " library_id='sample_1',\n", " spatial_key='spatial_key',\n", " patches=self.patches,\n", " cluster_key='cluster_key',\n", " metric='Shannon Diversity'\n", " )\n", " self.assertIn(\"spatial_data should be either an AnnData object or a pandas DataFrame\", str(context.exception))\n", "\n", " def test_missing_cluster_key(self):\n", " # Test with missing cluster_key in obs\n", " adata_missing_cluster = self.adata.copy()\n", " adata_missing_cluster.obs.drop('cluster_key', axis=1, inplace=True)\n", " with self.assertRaises(ValueError) as context:\n", " eco.calculate_diversity_index(\n", " spatial_data=adata_missing_cluster,\n", " library_key='library_key',\n", " library_id='sample_1',\n", " spatial_key='spatial_key',\n", " patches=self.patches,\n", " cluster_key='cluster_key',\n", " metric='Shannon Diversity'\n", " )\n", " self.assertIn(\"cluster_key 'cluster_key' not found\", str(context.exception))\n", "\n", " def test_empty_patches(self):\n", " # Test patches that are empty\n", " empty_patches = [(10, 10, 11, 11)]\n", " result = eco.calculate_diversity_index(\n", " spatial_data=self.adata,\n", " library_key='library_key',\n", " library_id='sample_1',\n", " spatial_key='spatial_key',\n", " patches=empty_patches,\n", " cluster_key='cluster_key',\n", " metric='Shannon Diversity'\n", " )\n", " # Result should be empty\n", " self.assertEqual(len(result), 0)\n", "\n", " def test_return_comp_true(self):\n", " # Test with return_comp=True\n", " result_series, patches_comp = eco.calculate_diversity_index(\n", " spatial_data=self.adata,\n", " library_key='library_key',\n", " library_id='sample_1',\n", " spatial_key='spatial_key',\n", " patches=self.patches,\n", " cluster_key='cluster_key',\n", " metric='Shannon Diversity',\n", " return_comp=True\n", " )\n", " self.assertIsInstance(result_series, pd.Series)\n", " self.assertIsInstance(patches_comp, list)\n", " self.assertEqual(patches_comp[0].to_dict(), {'A': 2, 'B': 1})\n", " self.assertIsNone(patches_comp[1])\n", " self.assertEqual(patches_comp[2].to_dict(), {'A': 2})\n", "\n", " def test_metric_simpson(self):\n", " # Test with metric 'Simpson'\n", " result = eco.calculate_diversity_index(\n", " spatial_data=self.adata,\n", " library_key='library_key',\n", " library_id='sample_1',\n", " spatial_key='spatial_key',\n", " patches=self.patches,\n", " cluster_key='cluster_key',\n", " metric='Simpson'\n", " )\n", " expected_simpson_patch0 = eco.calculate_simpson_index([2, 1])\n", " self.assertAlmostEqual(result[0], expected_simpson_patch0)\n", " expected_simpson_patch2 = eco.calculate_simpson_index([2])\n", " self.assertAlmostEqual(result[2], expected_simpson_patch2)\n", "\n", " def test_metric_simpson_diversity(self):\n", " # Test with metric 'Simpson Diversity'\n", " result = eco.calculate_diversity_index(\n", " spatial_data=self.adata,\n", " library_key='library_key',\n", " library_id='sample_1',\n", " spatial_key='spatial_key',\n", " patches=self.patches,\n", " cluster_key='cluster_key',\n", " metric='Simpson Diversity'\n", " )\n", " expected_simpson_diversity_patch0 = eco.calculate_simpsonDiversity_index([2, 1])\n", " self.assertAlmostEqual(result[0], expected_simpson_diversity_patch0)\n", " expected_simpson_diversity_patch2 = eco.calculate_simpsonDiversity_index([2])\n", " self.assertAlmostEqual(result[2], expected_simpson_diversity_patch2)" ] }, { "cell_type": "code", "execution_count": 3, "id": "9870f687-dd1b-4a82-9759-5cb935d0b65b", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "......./opt/miniconda3/envs/mesa/lib/python3.11/site-packages/anndata/_core/anndata.py:183: ImplicitModificationWarning: Transforming to str index.\n", " warnings.warn(\"Transforming to str index.\", ImplicitModificationWarning)\n", "..\n", "----------------------------------------------------------------------\n", "Ran 9 tests in 0.082s\n", "\n", "OK\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Setting up test data...\n", "33.333 per cent patches are empty\n", "33.333 per cent patches are empty\n", "100.000 per cent patches are empty\n", "33.333 per cent patches are empty\n", "33.333 per cent patches are empty\n", "33.333 per cent patches are empty\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Run the tests in the notebook\n", "unittest.main(argv=['first-arg-is-ignored'], exit=False)" ] } ], "metadata": { "kernelspec": { "display_name": "Python3.11 (mesa)", "language": "python", "name": "python311_mesa" }, "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.11.3" } }, "nbformat": 4, "nbformat_minor": 5 }