Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added 3D Plotting Functionality to plotter.py #584

Merged
merged 15 commits into from
Mar 2, 2022
Merged

Conversation

PACarniglia
Copy link
Contributor

Adds three-dimensional plotting functionality to the plotter.py function. Plotting of truth data, measurements (including clutter and true detection distinction), and tracks with error bars are supported. The underlying 2D plotting functionality is unchanged. Plotting dimensionality is now selected by the user when instantiating new Plotter objects by passing a plotter.py Dimension Enum object. Currently Dimension.TWO and Dimension.THREE are supported but can be extended in the future.

The legend is now populated with a dictionary where the keys show up as labels and values associated with those keys appear as the handles. This implementation avoids duplicate legend entries if plotting the same data multiple times.

A unit test file, test_plotter.py, was also created to ensure subsequent changes to plotter.py do not break current functionality.

plotter3.py is an additional plotter function that functions similarly to plotter.py, though is meant to visualize targets and measurements in 3D as opposed to 2D planes. Currently, only truth visualization is supported.
Can now plot both measurements and tracks in 3D, functionality & use is identical to plotter.py to maintain consistency in implementation.

Todo - add error bars to legend, consider alternate ways to display track uncertainty
-*NEW* Added 3D error bars as option for plot_tracks()
-*NEW* err_freq is an attribute of plot_tracks() that defines how frequently error bars should be displayed along the track (default is 1, or for every point)
-labels_list and handles_list removed, replaced by legend_dict.
  --legend_dict holds *_handle with
    *_label as the key
-legend is now plotted with legend_dict.values() as the handles and legend_dict.keys() as the labels; avoids duplicate entries in legend if plotting the same data multiple times. If similar elements are desired to be displayed in legend, a unique *_label must be passed into the appropriate plot function

*TODO*
-Redo header documentation for Plotter class and methods
-Add buttons to have interactive plots (turning on and off measurements, tracks, truth, etc.). See https://matplotlib.org/stable/gallery/widgets/check_buttons.html
-Allow user to plot tracks and truths with unique legend identifiers WITHOUT having to call plot_tracks() for each unique element; list of labels same length as list of tracks/truth
Using flake8 python library
plotter.py now contains all functionality of original 2D plotter.py and 3D plotting of plotter3.py. Plotting type is now chosen by the user by using the optional Enumerate parameter "dimension" when instantiating Plotter(). Documentation has been updated to reflect these changes

TODO
-Add unit tests
-Use flake8 to ensure the file complies with PEP8 standards
-Submit pull request on Stone Soup Github repo
Deprecated - functionality now contained fully within plotter.py
Delete cached python libraries
@PACarniglia PACarniglia requested a review from a team as a code owner January 17, 2022 17:37
@PACarniglia PACarniglia requested review from sdhiscocks and svidal-dstl and removed request for a team January 17, 2022 17:37
@codecov
Copy link

codecov bot commented Jan 17, 2022

Codecov Report

Merging #584 (f239056) into main (6a57078) will decrease coverage by 0.26%.
The diff coverage is 71.42%.

❗ Current head f239056 differs from pull request most recent head f190be0. Consider uploading reports for the commit f190be0 to get more accurate results

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #584      +/-   ##
==========================================
- Coverage   94.22%   93.95%   -0.27%     
==========================================
  Files         144      144              
  Lines        7008     7035      +27     
  Branches     1037     1336     +299     
==========================================
+ Hits         6603     6610       +7     
- Misses        307      325      +18     
- Partials       98      100       +2     
Flag Coverage Δ
integration 67.93% <60.00%> (-0.28%) ⬇️
unittests 91.44% <68.57%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
stonesoup/plotter.py 83.85% <71.42%> (-11.68%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6a57078...f190be0. Read the comment docs.

Copy link
Contributor

@nperree-dstl nperree-dstl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All looks good to me from a first glance at the code. A couple of documentation things, but really nothing major. I've not tried to use it yet but I will have a go when I get a chance.

stonesoup/plotter.py Outdated Show resolved Hide resolved
stonesoup/plotter.py Outdated Show resolved Hide resolved
stonesoup/plotter.py Outdated Show resolved Hide resolved
stonesoup/plotter.py Outdated Show resolved Hide resolved
PACarniglia and others added 4 commits January 18, 2022 11:45
Co-authored-by: Nikki Perree <[email protected]>
Co-authored-by: Nikki Perree <[email protected]>
Co-authored-by: Nikki Perree <[email protected]>
Co-authored-by: Nikki Perree <[email protected]>
@PACarniglia
Copy link
Contributor Author

@sdhiscocks I was told by @ekhunter123 that the remaining failing tests can be ignored, is this still the case for this PR?

@ekhunter123
Copy link
Contributor

@sdhiscocks I was told by @ekhunter123 that the remaining failing tests can be ignored, is this still the case for this PR?

I think here I was referencing the comment on my pull request #587, that CircleCi is having a problem lately with the dependency cache. I told @PACarniglia about this and wondered if the same applies for this PR. Perhaps "ignore" was too strong of a word for me to use. The fact that the tests fail still gives important information and maybe more work can be done to fix it. On the other hand, maybe it is just a problem with CircleCi, I don't know.

@sdhiscocks
Copy link
Member

sdhiscocks commented Feb 3, 2022

You are correct @ekhunter123, the tests are broken for pull requests; the same dependency cache issue. I'll see if I can work out a way to resolve this, but any fix will probably only resolve itself for new PRs.

Copy link
Member

@sdhiscocks sdhiscocks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍

Minor suggestion:

diff --git a/stonesoup/plotter.py b/stonesoup/plotter.py
index 9cdc0c80..999f7566 100644
--- a/stonesoup/plotter.py
+++ b/stonesoup/plotter.py
@@ -53,11 +53,7 @@ class Plotter:
     """
 
     def __init__(self, dimension=Dimension.TWO):
-        if isinstance(dimension, type(Dimension.TWO)):
-            self.dimension = dimension
-        else:
-            raise TypeError("""%s is an unsupported type for \'dimension\';
-                            expected type %s""" % (type(dimension), type(Dimension.TWO)))
+        self.dimension = Dimension(dimension)
         # Generate plot axes
         self.fig = plt.figure(figsize=(10, 6))
         if self.dimension is Dimension.TWO:  # 2D axes
diff --git a/stonesoup/tests/test_plotter.py b/stonesoup/tests/test_plotter.py
index 258dab64..46cd7ed2 100644
--- a/stonesoup/tests/test_plotter.py
+++ b/stonesoup/tests/test_plotter.py
@@ -81,7 +81,7 @@ plotter = Plotter()
 
 
 def test_dimension_raise():
-    with pytest.raises(TypeError):
+    with pytest.raises(ValueError):
         Plotter(dimension=1)  # expected to raise TypeError
 
 

Wrapping the input with Enum should allow both Plotter(dimension=3) and Plotter(dimension=Dimension.THREE) to work.

@PACarniglia
Copy link
Contributor Author

Looks good 👍

Minor suggestion:

diff --git a/stonesoup/plotter.py b/stonesoup/plotter.py
index 9cdc0c80..999f7566 100644
--- a/stonesoup/plotter.py
+++ b/stonesoup/plotter.py
@@ -53,11 +53,7 @@ class Plotter:
     """
 
     def __init__(self, dimension=Dimension.TWO):
-        if isinstance(dimension, type(Dimension.TWO)):
-            self.dimension = dimension
-        else:
-            raise TypeError("""%s is an unsupported type for \'dimension\';
-                            expected type %s""" % (type(dimension), type(Dimension.TWO)))
+        self.dimension = Dimension(dimension)
         # Generate plot axes
         self.fig = plt.figure(figsize=(10, 6))
         if self.dimension is Dimension.TWO:  # 2D axes
diff --git a/stonesoup/tests/test_plotter.py b/stonesoup/tests/test_plotter.py
index 258dab64..46cd7ed2 100644
--- a/stonesoup/tests/test_plotter.py
+++ b/stonesoup/tests/test_plotter.py
@@ -81,7 +81,7 @@ plotter = Plotter()
 
 
 def test_dimension_raise():
-    with pytest.raises(TypeError):
+    with pytest.raises(ValueError):
         Plotter(dimension=1)  # expected to raise TypeError
 
 

Wrapping the input with Enum should allow both Plotter(dimension=3) and Plotter(dimension=Dimension.THREE) to work.

@sdhiscocks the reason for switching the current implementation of dimension as an int to dimension as an Enum is twofold; it sanitizes the input as users will have to use a Dimension instance (this was recommended by @ekhunter123), and makes it easier for future developers to extend the plotting capabilities present in Plotter.py without having to be restricted to just adding additional dimensions - in theory, the dimension parameter need not be a spatial number but could rather be sort of a "plot type" attribute.

@sdhiscocks sdhiscocks merged commit e3da986 into dstl:main Mar 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants