Skip to content

Commit

Permalink
Merge pull request #702 from dstl/misc_typo_fixes
Browse files Browse the repository at this point in the history
Plotter minor fix
  • Loading branch information
sdhiscocks committed Aug 24, 2022
2 parents 56b449e + 7e654c3 commit 0418c1b
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 38 deletions.
62 changes: 36 additions & 26 deletions stonesoup/plotter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import warnings
from abc import ABC, abstractmethod
from itertools import chain
from typing import Collection

import numpy as np
from matplotlib import pyplot as plt
Expand All @@ -17,7 +18,7 @@

from .types import detection
from .types.groundtruth import GroundTruthPath
from .types.state import State
from .types.state import State, StateMutableSequence
from .types.update import Update

from .models.base import LinearModel, Model
Expand Down Expand Up @@ -161,10 +162,10 @@ def plot_ground_truths(self, truths, mapping, truths_label="Ground Truth", **kwa
Parameters
----------
truths : set of :class:`~.GroundTruthPath`
Set of ground truths which will be plotted. If not a set, and instead a single
:class:`~.GroundTruthPath` type, the argument is modified to be a set to allow for
iteration.
truths : Collection of :class:`~.GroundTruthPath`
Collection of ground truths which will be plotted. If not a collection and instead a
single :class:`~.GroundTruthPath` type, the argument is modified to be a set to allow
for iteration.
mapping: list
List of items specifying the mapping of the position components of the state space.
\\*\\*kwargs: dict
Expand All @@ -173,7 +174,7 @@ def plot_ground_truths(self, truths, mapping, truths_label="Ground Truth", **kwa

truths_kwargs = dict(linestyle="--")
truths_kwargs.update(kwargs)
if not isinstance(truths, set):
if not isinstance(truths, Collection) or isinstance(truths, StateMutableSequence):
truths = {truths} # Make a set of length 1

for truth in truths:
Expand Down Expand Up @@ -207,7 +208,7 @@ def plot_measurements(self, measurements, mapping, measurement_model=None,
Parameters
----------
measurements : list of :class:`~.Detection`
measurements : Collection of :class:`~.Detection`
Detections which will be plotted. If measurements is a set of lists it is flattened.
mapping: list
List of items specifying the mapping of the position components of the state space.
Expand All @@ -222,6 +223,9 @@ def plot_measurements(self, measurements, mapping, measurement_model=None,
measurement_kwargs = dict(marker='o', color='b')
measurement_kwargs.update(kwargs)

if not isinstance(measurements, Collection):
measurements = {measurements} # Make a set of length 1

if any(isinstance(item, set) for item in measurements):
measurements_set = chain.from_iterable(measurements) # Flatten into one set
else:
Expand Down Expand Up @@ -269,8 +273,8 @@ def plot_tracks(self, tracks, mapping, uncertainty=False, particle=False, track_
Parameters
----------
tracks : set of :class:`~.Track`
Set of tracks which will be plotted. If not a set, and instead a single
tracks : Collection of :class:`~.Track`
Collection of tracks which will be plotted. If not a collection, and instead a single
:class:`~.Track` type, the argument is modified to be a set to allow for iteration.
mapping: list
List of items specifying the mapping of the position
Expand All @@ -291,7 +295,7 @@ def plot_tracks(self, tracks, mapping, uncertainty=False, particle=False, track_

tracks_kwargs = dict(linestyle='-', marker=".", color=None)
tracks_kwargs.update(kwargs)
if not isinstance(tracks, set):
if not isinstance(tracks, Collection) or isinstance(tracks, StateMutableSequence):
tracks = {tracks} # Make a set of length 1

# Plot tracks
Expand Down Expand Up @@ -411,7 +415,7 @@ def plot_sensors(self, sensors, sensor_label="Sensors", **kwargs):
Parameters
----------
sensors : list of :class:`~.Sensor`
sensors : Collection of :class:`~.Sensor`
Sensors to plot
sensor_label: str
Label to apply to all tracks for legend.
Expand All @@ -423,7 +427,7 @@ def plot_sensors(self, sensors, sensor_label="Sensors", **kwargs):
sensor_kwargs = dict(marker='x', color='black')
sensor_kwargs.update(kwargs)

if not isinstance(sensors, set):
if not isinstance(sensors, Collection):
sensors = {sensors} # Make a set of length 1

for sensor in sensors:
Expand Down Expand Up @@ -586,18 +590,18 @@ def plot_ground_truths(self, truths, mapping, truths_label="Ground Truth", **kwa
Parameters
----------
truths : set of :class:`~.GroundTruthPath`
Set of ground truths which will be plotted. If not a set, and instead a single
:class:`~.GroundTruthPath` type, the argument is modified to be a set to allow for
iteration.
truths : Collection of :class:`~.GroundTruthPath`
Collection of ground truths which will be plotted. If not a collection,
and instead a single :class:`~.GroundTruthPath` type, the argument is modified to be a
set to allow for iteration.
mapping: list
List of items specifying the mapping of the position components of the state space.
\\*\\*kwargs: dict
Additional arguments to be passed to scatter function. Default is
``line=dict(dash="dash")``.
"""
if not isinstance(truths, set):
truths = {truths} # Make a set of length 1
if not isinstance(truths, Collection) or isinstance(truths, StateMutableSequence):
truths = {truths}

truths_kwargs = dict(
mode="lines", line=dict(dash="dash"), legendgroup=truths_label, legendrank=100,
Expand Down Expand Up @@ -631,22 +635,27 @@ def plot_measurements(self, measurements, mapping, measurement_model=None,
Parameters
----------
measurements : list of :class:`~.Detection`
measurements : Collection of :class:`~.Detection`
Detections which will be plotted. If measurements is a set of lists it is flattened.
mapping: list
List of items specifying the mapping of the position components of the state space.
measurement_model : :class:`~.Model`, optional
User-defined measurement model to be used in finding measurement state inverses if
they cannot be found from the measurements themselves.
measurements_label : str
Label for the measurements. Default is "Measurements".
\\*\\*kwargs: dict
Additional arguments to be passed to scatter function for detections. Defaults are
``marker=dict(color="#636EFA")``.
"""

if not isinstance(measurements, Collection):
measurements = {measurements}

if any(isinstance(item, set) for item in measurements):
measurements_set = chain.from_iterable(measurements) # Flatten into one set
else:
measurements_set = measurements
measurements_set = set(measurements)

plot_detections, plot_clutter = self._conv_measurements(measurements_set,
mapping,
Expand Down Expand Up @@ -702,8 +711,8 @@ def plot_tracks(self, tracks, mapping, uncertainty=False, particle=False, track_
Parameters
----------
tracks : set of :class:`~.Track`
Set of tracks which will be plotted. If not a set, and instead a single
tracks : Collection of :class:`~.Track`
Collection of tracks which will be plotted. If not a collection, and instead a single
:class:`~.Track` type, the argument is modified to be a set to allow for iteration.
mapping: list
List of items specifying the mapping of the position
Expand All @@ -717,7 +726,7 @@ def plot_tracks(self, tracks, mapping, uncertainty=False, particle=False, track_
\\*\\*kwargs: dict
Additional arguments to be passed to scatter function.
"""
if not isinstance(tracks, set):
if not isinstance(tracks, Collection) or isinstance(tracks, StateMutableSequence):
tracks = {tracks} # Make a set of length 1

# Plot tracks
Expand Down Expand Up @@ -833,16 +842,17 @@ def plot_sensors(self, sensors, sensor_label="Sensors", **kwargs):
Parameters
----------
sensors : list of :class:`~.Sensor`
sensors : Collection of :class:`~.Sensor`
Sensors to plot
sensor_label: str
Label to apply to all tracks for legend.
\\*\\*kwargs: dict
Additional arguments to be passed to scatter function for detections. Defaults are
``marker=dict(symbol='x', color='black')``.
"""
if not isinstance(sensors, set):
sensors = {sensors} # Make a set of length 1

if not isinstance(sensors, Collection):
sensors = {sensors}

sensor_kwargs = dict(mode='markers', marker=dict(symbol='x', color='black'),
legendgroup=sensor_label, legendrank=50)
Expand Down
24 changes: 12 additions & 12 deletions stonesoup/sensor/radar/radar.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ class RadarBearingRange(Sensor):
doc="Number of state dimensions. This is utilised by (and follows in format) "
"the underlying :class:`~.CartesianToBearingRange` model")
position_mapping: Tuple[int, int] = Property(
doc="Mapping between the targets state space and the sensors "
doc="Mapping between the target's state space and the sensor's "
"measurement capability")
noise_covar: CovarianceMatrix = Property(
doc="The sensor noise covariance matrix. This is utilised by "
"(and follow in format) the underlying "
"(and follows in format) the underlying "
":class:`~.CartesianToBearingRange` model")
clutter_model: ClutterModel = Property(
default=None,
doc="An optional clutter generator that adds a set of simulated "
":class:`Clutter` ojects to the measurements at each time step. "
":class:`Clutter` objects to the measurements at each time step. "
"The clutter is simulated according to the provided distribution.")
max_range: float = Property(
default=np.inf,
Expand Down Expand Up @@ -206,7 +206,7 @@ class RadarElevationBearingRange(RadarBearingRange):
"the underlying :class:`~.CartesianToBearingRange` model")
noise_covar: CovarianceMatrix = Property(
doc="The sensor noise covariance matrix. This is utilised by "
"(and follow in format) the underlying "
"(and follows in format) the underlying "
":class:`~.CartesianToElevationBearingRange` model")
max_range: float = Property(
default=np.inf,
Expand Down Expand Up @@ -267,7 +267,7 @@ class RadarBearingRangeRate(RadarBearingRange):
Note
----
This class implementation assuming at 3D cartesian space, it therefore\
This class implementation assumes a 3D cartesian space and therefore\
expects a 6D state space.
"""
Expand All @@ -281,7 +281,7 @@ class RadarBearingRangeRate(RadarBearingRange):
"the underlying :class:`~.CartesianToBearingRangeRate` model")
noise_covar: CovarianceMatrix = Property(
doc="The sensor noise covariance matrix. This is utilised by "
"(and follow in format) the underlying "
"(and follows in format) the underlying "
":class:`~.CartesianToBearingRangeRate` model")

@property
Expand Down Expand Up @@ -332,7 +332,7 @@ class RadarElevationBearingRangeRate(RadarBearingRangeRate):
"the underlying :class:`~.CartesianToElevationBearingRangeRate` model")
noise_covar: CovarianceMatrix = Property(
doc="The sensor noise covariance matrix. This is utilised by "
"(and follow in format) the underlying "
"(and follows in format) the underlying "
":class:`~.CartesianToElevationBearingRangeRate` model")

@property
Expand Down Expand Up @@ -377,7 +377,7 @@ class RadarRasterScanBearingRange(RadarRotatingBearingRange):
Note
----
This class implementation assuming at 3D cartesian space, it therefore\
This class implementation assumes a 3D cartesian space and therefore \
expects a 6D state space.
"""
Expand Down Expand Up @@ -496,7 +496,7 @@ class AESARadar(Sensor):
doc="Mapping between or positions and state "
"dimensions. [x,y,z]")
measurement_model: MeasurementModel = Property(
doc="The Measurement model used to generate "
doc="The measurement model used to generate "
"measurements.")
beam_shape: BeamShape = Property(
doc="Object describing the shape of the beam.")
Expand All @@ -507,15 +507,15 @@ class AESARadar(Sensor):
number_pulses: int = Property(
default=1, doc="The number of pulses in the radar burst.")
duty_cycle: float = Property(
doc="Duty cycle is the fraction of the time the radar it transmitting.")
doc="Duty cycle is the fraction of the time the radar is transmitting.")
band_width: float = Property(
doc="Bandwidth of the receiver in hertz.")
receiver_noise: float = Property(
doc="Noise figure of the radar in decibels.")
frequency: float = Property(
doc="Transmitted frequency in hertz.")
antenna_gain: float = Property(
doc="Total Antenna gain in decibels.")
doc="Total antenna gain in decibels.")
beam_width: float = Property(
doc="Radar beam width in radians.")
loss: float = Property(
Expand All @@ -528,7 +528,7 @@ class AESARadar(Sensor):
"distribution of the Swerling 1 case.")
rcs: float = Property(
default=None,
doc="The radar cross section of targets in meters squared. Used if rcs not present on "
doc="The radar cross section of targets in meters squared. Used if RCS not present on "
"truth. Default `None`, where 'rcs' must be present on truth.")
probability_false_alarm: Probability = Property(
default=1e-6, doc="Probability of false alarm used in the North's approximation")
Expand Down
5 changes: 5 additions & 0 deletions stonesoup/tests/test_plotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ def test_measurement_clutter(): # no clutter should be plotted
assert 'Clutter' not in plotter.legend_dict


def test_single_measurement(): # A single measurement outside of a Collection should still run
plotter.plot_measurements(all_measurements[0], [0, 2])
plt.close()


def test_particle_3d(): # warning should arise if particle is attempted in 3d mode
plotter3 = Plotter(dimension=Dimension.THREE)

Expand Down

0 comments on commit 0418c1b

Please sign in to comment.