From b240b3bf75dbf8242beb8d020067b3baadfb6f1c Mon Sep 17 00:00:00 2001 From: Jeremy Kubica <104161096+jeremykubica@users.noreply.github.com> Date: Mon, 26 Feb 2024 11:50:08 -0500 Subject: [PATCH 1/3] Create a function to extract attributes from ResultRows --- notebooks/kbmod_results_and_filtering.ipynb | 23 +++++++++++-- src/kbmod/result_list.py | 34 +++++++++++++++++++ tests/test_result_list.py | 36 +++++++++++++++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) diff --git a/notebooks/kbmod_results_and_filtering.ipynb b/notebooks/kbmod_results_and_filtering.ipynb index 2ab71c519..af311af79 100644 --- a/notebooks/kbmod_results_and_filtering.ipynb +++ b/notebooks/kbmod_results_and_filtering.ipynb @@ -85,6 +85,25 @@ "results.sort(key=\"final_likelihood\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Extracting Individual Attributes\n", + "\n", + "The `ResultList`class provides a helper function `get_result_values()` that allows a user to extract all of the values for a given attribute of the results. For example we could extract all of the flux values and create a histogram." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "flux_values = results.get_result_values(\"trajectory.flux\")\n", + "plt.hist(flux_values)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -300,9 +319,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.12.1" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/src/kbmod/result_list.py b/src/kbmod/result_list.py index 5c842a376..58beeed77 100644 --- a/src/kbmod/result_list.py +++ b/src/kbmod/result_list.py @@ -674,6 +674,40 @@ def sort(self, key="final_likelihood", reverse=True): self.results.sort(key=lambda x: getattr(x, key), reverse=reverse) return self + def get_result_values(self, attribute): + """Return the values of the ResultRows' attribute as a list. + Subattributes can be extracted as "attribute.subattribute", + such as "trajectory.x" + + Examples: + trj_list = res.get_trajectory_values("trajectory") + x_values = res.get_trajectory_values("trajectory.x") + stamps = res.get_trajectory_values("stamp") + + Parameter + --------- + attribute : `str` + The name of the attribute to extract. + + Returns + ------- + values : `list` + A list of the results' values. + + Raises + ------ + Raises an ``AttributeError`` if the attribute does not exist. + """ + att_list = attribute.split(".") + + values = [] + for row in self.results: + obj = row + for att in att_list: + obj = getattr(obj, att) + values.append(obj) + return values + def compute_predicted_skypos(self, wcs): """Compute the predict sky position for each result's trajectory at each time step. diff --git a/tests/test_result_list.py b/tests/test_result_list.py index e903465fe..337c3fb27 100644 --- a/tests/test_result_list.py +++ b/tests/test_result_list.py @@ -264,6 +264,42 @@ def test_sort(self): for i, val in enumerate(expected_order): self.assertEqual(rs.results[i].trajectory.x, val) + def test_get_result_values(self): + rs = ResultList(self.times) + rs.append_result(ResultRow(make_trajectory(x=0, lh=1.0, obs_count=1), self.num_times)) + rs.append_result(ResultRow(make_trajectory(x=1, lh=-1.0, obs_count=2), self.num_times)) + rs.append_result(ResultRow(make_trajectory(x=2, lh=5.0, obs_count=3), self.num_times)) + rs.append_result(ResultRow(make_trajectory(x=3, lh=4.0, obs_count=5), self.num_times)) + rs.append_result(ResultRow(make_trajectory(x=4, lh=6.0, obs_count=4), self.num_times)) + + # Test getting a list of trajectories. + trjs = rs.get_result_values("trajectory") + self.assertEqual(len(trjs), 5) + for i in range(5): + self.assertTrue(type(trjs[i]) is Trajectory) + + # Stamps should all be None + stamps = rs.get_result_values("stamp") + self.assertEqual(len(stamps), 5) + for i in range(5): + self.assertTrue(stamps[i] is None) + + # We can extract sub-attributes + x_vals = rs.get_result_values("trajectory.x") + self.assertEqual(len(x_vals), 5) + for i in range(5): + self.assertEqual(x_vals[i], i) + + vx_vals = rs.get_result_values("trajectory.vx") + self.assertEqual(len(vx_vals), 5) + for i in range(5): + self.assertEqual(vx_vals[i], 0.0) + + # We get an error if we try to extract an attribute that doesn't exist. + self.assertRaises(AttributeError, rs.get_result_values, "") + self.assertRaises(AttributeError, rs.get_result_values, "Not There") + self.assertRaises(AttributeError, rs.get_result_values, "trajectory.z") + def test_filter(self): rs = ResultList(self.times) for i in range(10): From 6ebcd9dbc846f6bfc9acc4ba5470f79d03b96e5f Mon Sep 17 00:00:00 2001 From: Jeremy Kubica <104161096+jeremykubica@users.noreply.github.com> Date: Mon, 26 Feb 2024 12:21:30 -0500 Subject: [PATCH 2/3] Add a histogram plotting function --- notebooks/kbmod_analysis_demo.ipynb | 47 ++++++++++++++++++++++++++--- src/kbmod/analysis/plot_results.py | 22 +++++++++++++- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/notebooks/kbmod_analysis_demo.ipynb b/notebooks/kbmod_analysis_demo.ipynb index e92d71e24..eb4fa74ea 100644 --- a/notebooks/kbmod_analysis_demo.ipynb +++ b/notebooks/kbmod_analysis_demo.ipynb @@ -14,6 +14,7 @@ "outputs": [], "source": [ "import os\n", + "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "from kbmod.analysis.plot_results import *\n", @@ -148,6 +149,44 @@ "ResultsVisualizer.plot_result_row(row0)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Histograms of Results\n", + "\n", + "We can plot the histograms of individual attributes of the results. First we need to load a result set with more than one entry. Then we plot the histogram of number of observations in the trajectory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "results2 = load_result_list_from_files(\"../data/fake_results_noisy/\", \"DEMO\")\n", + "print(f\"Loaded {results2.num_results()} results.\")\n", + "\n", + "counts = results2.get_result_values(\"obs_count\")\n", + "_ = plt.hist(counts)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `ResultsVisualizer` class provides a helper function to plotting a 2-d histogram of the trajectory's starting positions on the image. This requires knowing the image size. The demo data consists of 256 by 256 images." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ResultsVisualizer.plot_starting_pixel_histogram(results2, 256, 256)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -159,9 +198,9 @@ "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Jeremy's KBMOD", "language": "python", - "name": "python3" + "name": "kbmod_jk" }, "language_info": { "codemirror_mode": { @@ -173,9 +212,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.8" + "version": "3.12.1" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/src/kbmod/analysis/plot_results.py b/src/kbmod/analysis/plot_results.py index afb41c43c..488fe0042 100644 --- a/src/kbmod/analysis/plot_results.py +++ b/src/kbmod/analysis/plot_results.py @@ -1,5 +1,4 @@ import math - import matplotlib.pyplot as plt import numpy as np @@ -156,3 +155,24 @@ def plot_result_row(row, times=None, title=None, fig=None): else: ax = fig_bot.add_axes([0, 0, 1, 1]) ax.text(0.5, 0.5, "No Individual Stamps") + + @staticmethod + def plot_starting_pixel_histogram(results, height, width): + """Plot a histogram of the starting pixels of each found trajectory. + + Parameters + ---------- + results : `ResultList` + The results to analyze. + height : `int` + The image height in pixels + width : `int` + The image width in pixels + """ + fig, ax = plt.subplots() + + x_vals = results.get_result_values("trajectory.x") + y_vals = results.get_result_values("trajectory.y") + _, _, _, img = ax.hist2d(x_vals, y_vals, bins=[height, width]) + fig.colorbar(img, ax=ax) + ax.set_title("Histogram of Starting Pixel") From 9269017a3dd687d3c6ac86cc85ce5f0bb47d22db Mon Sep 17 00:00:00 2001 From: Jeremy Kubica <104161096+jeremykubica@users.noreply.github.com> Date: Mon, 26 Feb 2024 12:38:40 -0500 Subject: [PATCH 3/3] Add another demo to the notebook --- notebooks/kbmod_analysis_demo.ipynb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/notebooks/kbmod_analysis_demo.ipynb b/notebooks/kbmod_analysis_demo.ipynb index eb4fa74ea..8c1d847e1 100644 --- a/notebooks/kbmod_analysis_demo.ipynb +++ b/notebooks/kbmod_analysis_demo.ipynb @@ -187,6 +187,28 @@ "ResultsVisualizer.plot_starting_pixel_histogram(results2, 256, 256)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or we could manually create a histogram of the pixel velocities." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "xv_vals = results2.get_result_values(\"trajectory.vx\")\n", + "yv_vals = results2.get_result_values(\"trajectory.vy\")\n", + "_, _, _, img = ax.hist2d(xv_vals, yv_vals, bins=10)\n", + "fig.colorbar(img, ax=ax)\n", + "_ = ax.set_xlabel(\"vx (pixels per day)\")\n", + "_ = ax.set_ylabel(\"vy (pixels per day)\")" + ] + }, { "cell_type": "code", "execution_count": null,