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

Annotation sub-package and point annotation tool (a.k.a. interactive CustomROI) #816

Merged
merged 66 commits into from
Dec 14, 2021
Merged
Show file tree
Hide file tree
Changes from 65 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
7a4c52b
Update roi_methods.py
HaleySchuhl Aug 16, 2021
7fa45a4
add interactive custom roi tool and helper function
HaleySchuhl Aug 16, 2021
c8695e3
add test for interactive custom roi function
HaleySchuhl Aug 20, 2021
a6bb1d7
remove warning print statement
HaleySchuhl Aug 20, 2021
ef53c76
simulate mouse click events for testing
HaleySchuhl Aug 20, 2021
faa0a6b
test type of python object
HaleySchuhl Aug 20, 2021
5f54f28
add space
HaleySchuhl Aug 20, 2021
f07a561
update test to exact right click
HaleySchuhl Aug 23, 2021
a1fed30
add more clicks to tests
HaleySchuhl Aug 24, 2021
1dddd50
exact coord match
HaleySchuhl Aug 24, 2021
967b419
print statement to debug index err
HaleySchuhl Aug 24, 2021
58a9561
new print statement
HaleySchuhl Aug 24, 2021
8e9a402
more debugging the right click testing
HaleySchuhl Aug 24, 2021
251effc
Update roi_methods.py
HaleySchuhl Aug 24, 2021
30ef36c
return index if pt is an exact match
HaleySchuhl Aug 24, 2021
a73c872
remove print statements
HaleySchuhl Aug 24, 2021
002104f
return two elements regardless
HaleySchuhl Aug 24, 2021
4ea39d0
add approx right click instance for full coverage
HaleySchuhl Aug 24, 2021
31ff95d
refactor class name
HaleySchuhl Aug 31, 2021
c89b0b4
refactor class name within init
HaleySchuhl Aug 31, 2021
6fc0b22
refactor class name within tests
HaleySchuhl Aug 31, 2021
b72ab6a
Create interactive_custom_roi.md
HaleySchuhl Aug 31, 2021
f2c0e45
Create custom_roi.gif
HaleySchuhl Sep 3, 2021
57e5f7e
add new doc page to mkdocs.yml
HaleySchuhl Sep 3, 2021
53f077f
Update interactive_custom_roi.md
HaleySchuhl Sep 3, 2021
6278eda
reformat mkdocs
HaleySchuhl Sep 3, 2021
2670e5a
upload resulting ROI image
HaleySchuhl Sep 3, 2021
b295206
continue filling out doc page
HaleySchuhl Sep 3, 2021
950a81e
correct class name/path
HaleySchuhl Sep 3, 2021
b7415d7
Update updating.md
HaleySchuhl Sep 3, 2021
29b5190
round coords to int with the floor function
HaleySchuhl Sep 15, 2021
0a2b450
Merge branch '4.x' into interactive_roi
HaleySchuhl Nov 9, 2021
02a69f5
Merge branch '4.x' into interactive_roi
HaleySchuhl Nov 9, 2021
527aebe
create annotation subpackage
HaleySchuhl Nov 12, 2021
df740c2
move CustomROI into new subpackage
HaleySchuhl Nov 12, 2021
84b4898
remove unused import statements
HaleySchuhl Nov 12, 2021
2689d7b
add import statements and change function name
HaleySchuhl Nov 12, 2021
85e55a9
Update __init__.py
HaleySchuhl Nov 12, 2021
04bb4fe
Update __init__.py
HaleySchuhl Nov 12, 2021
69cc3f5
Update tests.py
HaleySchuhl Nov 12, 2021
ab8e22c
Update interactive_custom_roi.md
HaleySchuhl Nov 12, 2021
4a2a0a0
Update updating.md
HaleySchuhl Nov 12, 2021
1f42270
Merge branch 'interactive_roi' of https://github.com/danforthcenter/p…
HaleySchuhl Nov 12, 2021
76c6c7e
Update __init__.py
HaleySchuhl Nov 12, 2021
464cd57
move Points class into classes.py
HaleySchuhl Nov 16, 2021
daf48a8
Update tests.py
HaleySchuhl Nov 16, 2021
991640d
add import for private function
HaleySchuhl Nov 16, 2021
cdd04f8
Update __init__.py
HaleySchuhl Nov 16, 2021
352ca67
add import statement
HaleySchuhl Nov 16, 2021
4bcc6c4
refactor doc page
HaleySchuhl Nov 23, 2021
240c0d0
move documentation gifs
HaleySchuhl Nov 23, 2021
0d44afc
Update mkdocs.yml
HaleySchuhl Nov 23, 2021
beb2ed8
remove extra space
HaleySchuhl Nov 23, 2021
3237d71
make private function private
HaleySchuhl Nov 23, 2021
a17b7fb
update import statement
HaleySchuhl Nov 23, 2021
df87a91
remove extra space
HaleySchuhl Nov 30, 2021
9e412ea
add attribute description and complement docstring in Points class
JorgeGtz Dec 6, 2021
be489d7
add click instructions to class Points docstring
JorgeGtz Dec 6, 2021
ac036bd
add attributes to documentation of Points class
JorgeGtz Dec 6, 2021
adb0d39
remove annotation subpackage call in Points documentation (now it is …
JorgeGtz Dec 6, 2021
52e9199
remove annotate in call to Points class in updating documentation
JorgeGtz Dec 6, 2021
3ca13e6
remove space in call in Points documentation
JorgeGtz Dec 6, 2021
19a0244
leave one point and assert that it is registered in test for annotate…
JorgeGtz Dec 6, 2021
4a8ae9b
fix minor lint issues related to Points class
JorgeGtz Dec 6, 2021
4c6f937
add back remove exact point in tests for Points class to cover relate…
JorgeGtz Dec 6, 2021
9136447
Merge branch '4.x' into interactive_roi
HaleySchuhl Dec 14, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions docs/Points.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
## Interactive Point Annotation Tool

Using [Jupyter Notebooks](jupyter.md) it is possible to interactively click to collect coordinates from an image, which can be used in various downstream applications. Left click on the image to collect a point. Right click removes the
closest collected point.

**plantcv.Points**(*img, figsize=(12, 6)*)

**returns** interactive image class

- **Parameters:**
- img - Image data
- figsize - Interactive plot figure size (default = (12,6))

- **Attributes:**
- points - Coordinates (x,y) of the collected points as a list of tuples

- **Context:**
- Used to define a list of coordinates of interest.
- For example the [`pcv.roi.custom`](roi_custom.md) function defines a polygon Region of Interest based on a list of vertices, which can be labor intensive to define but is streamlined with the ability to click for point collection.
- The list of vertices output has also shown to be helpful while using [pcv.roi.multi](roi_multi.md) in cases where centers are defined with a custom list of vertices.
- **Example use:**
- Below


```python
from plantcv import plantcv as pcv

# Create an instance of the Points class
marker = pcv.Points(img=img, figsize=(12,6))

# Click on the plotted image to collect coordinates

# Use the identified coordinates to create a custom polygon ROI
roi_contour, roi_hierarchy = pcv.roi.custom(img=img, vertices=marker.points)

```

**Selecting Coordinates**

![screen-gif](img/documentation_images/annotate_Points/custom_roi.gif)

**Resulting ROI**

![Screenshot](img/documentation_images/annotate_Points/custom_roi.jpg)


**Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/master/plantcv/plantcv/classes.py)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 30 additions & 25 deletions docs/updating.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ conda list plantcv
### Updating from the source code

The general procedure for updating PlantCV if you are using the `master` branch
cloned from the `danforthcenter/plantcv` repository is to update your local
cloned from the `danforthcenter/plantcv` repository is to update your local
repository and reinstall the package.

With GitHub Desktop you can [synchronize](https://docs.github.com/en/free-pro-team@latest/desktop/contributing-and-collaborating-using-github-desktop/syncing-your-branch)
Expand All @@ -51,7 +51,7 @@ automatically. Alternatively, you can run `python setup.py install` to reinstall

The setuptools installation method was not available in PlantCV v1, so users
put the `plantcv/lib` directory in their custom `PYTHONPATH`. In PlantCV v2, the
plantcv library directory is no longer in the lib directory, now it is in the
plantcv library directory is no longer in the lib directory, now it is in the
main repository folder (`plantcv/plantcv`). If you want to continue to have
plantcv in your `PYTHONPATH` you will need to update by simply removing `lib`
from the path. You can also remove the lib folder after pulling the new version.
Expand All @@ -60,7 +60,7 @@ Git will automatically remove the `*.py` files but because we do not track the
cause confusion.

For Linux/Unix, `PYTHONPATH` can be edited in `~/.bash_profile`, `~/.bashrc`,
`~/.profile`, `~/.cshrc`, `~/.zshrc`, etc. For Windows, right-click on My
`~/.profile`, `~/.cshrc`, `~/.zshrc`, etc. For Windows, right-click on My
Computer/This PC and select Properties > Advanced system settings >
Environmental Variables... and edit the User variables entry for `PYTHONPATH`.

Expand All @@ -76,7 +76,7 @@ an issue on GitHub or contact us directly.

In order to support the installation of optional add-on subpackages, we converted
PlantCV to a [namespace package](https://packaging.python.org/guides/packaging-namespace-packages/).
To achieve this new functionality, existing functions had to be moved into a
To achieve this new functionality, existing functions had to be moved into a
subpackage to maintain easy importing. To maintain previous behavior, PlantCV
analysis scripts simply need to have updated PlantCV import syntax. So if you were
previously doing something like:
Expand All @@ -96,14 +96,14 @@ package API. The goal is to make each PlantCV function easier to use by reducing
the number of inputs and outputs that need to be configured (without losing
functionality) and by making input parameters more consistently named and clearly
defined where input types matter (e.g. instead of just `img` it could be `rgb_img`,
`gray_img`, or `bin_img` for RGB, grayscale, or binary image, respectively).
`gray_img`, or `bin_img` for RGB, grayscale, or binary image, respectively).

In PlantCV v3.0dev2 onwards, all functions were redesigned to utilize a global
parameters class to inherit values for standard inputs like `debug` and `device`
so that these values will not need to be explicitly input or output to/from each
In PlantCV v3.0dev2 onwards, all functions were redesigned to utilize a global
parameters class to inherit values for standard inputs like `debug` and `device`
so that these values will not need to be explicitly input or output to/from each
function. An instance of the class [`Params`](params.md) as `params` is created automatically
when PlantCV is imported and it can be imported to set global defaults. For example,
to change debug from `None` to 'plot' or 'print' you can now just add one line to
when PlantCV is imported and it can be imported to set global defaults. For example,
to change debug from `None` to 'plot' or 'print' you can now just add one line to
the top of your script or notebook to change the behavior of all subsequent function
calls:

Expand Down Expand Up @@ -216,13 +216,13 @@ pages for more details on the input and output variable types.

* pre v3.0dev2: device, masked_img = **plantcv.apply_mask**(*img, mask, mask_color, device, debug=None*)
* post v3.0dev2: masked_img = **plantcv.apply_mask**(*rgb_img, mask, mask_color*)
* post v3.7: masked_img = **plantcv.apply_mask**(*img, mask, mask_color*)
* post v3.7: masked_img = **plantcv.apply_mask**(*img, mask, mask_color*)

#### plantcv.auto_crop

* pre v3.0dev2: device, cropped = **plantcv.auto_crop**(*device, img, objects, padding_x=0, padding_y=0, color='black', debug=None*)
* post v3.0dev2: cropped = **plantcv.auto_crop**(*img, objects, padding_x=0, padding_y=0, color='black'*)
* post v3.2: cropped = **plantcv.auto_crop**(*img, obj, padding_x=0, padding_y=0, color='black'*)
* post v3.2: cropped = **plantcv.auto_crop**(*img, obj, padding_x=0, padding_y=0, color='black'*)

#### plantcv.background_subtraction

Expand All @@ -234,7 +234,7 @@ pages for more details on the input and output variable types.
* pre v3.0dev2: device, bin_img = **plantcv.binary_threshold**(*img, threshold, maxValue, object_type, device, debug=None*)
* post v3.0dev2: Deprecated, see:
* bin_img = **plantcv.threshold.binary**(*gray_img, threshold, max_value, object_type="light"*)

#### plantcv.canny_edge_detect

* pre v3.2: NA
Expand Down Expand Up @@ -466,20 +466,20 @@ pages for more details on the input and output variable types.
#### plantcv.morphology.find_tips

* pre v3.3: NA
* post v3.3: tip_img = **plantcv.morphology.find_tips**(*skel_img, mask=None*)
* post v3.11: tip_img = **plantcv.morphology.find_tips**(*skel_img, mask=None, label="default"*)
* post v3.3: tip_img = **plantcv.morphology.find_tips**(*skel_img, mask=None*)
* post v3.11: tip_img = **plantcv.morphology.find_tips**(*skel_img, mask=None, label="default"*)

#### plantcv.morphology.prune

* pre v3.3: NA
* post v3.3: pruned_img = **plantcv.morphology.prune**(*skel_img, size*)
* post v3.4: pruned_skeleton, segmented_img, segment_objects = **plantcv.morphology.prune**(*skel_img, size=0, mask=None*)
* post v3.3: pruned_img = **plantcv.morphology.prune**(*skel_img, size*)
* post v3.4: pruned_skeleton, segmented_img, segment_objects = **plantcv.morphology.prune**(*skel_img, size=0, mask=None*)

#### plantcv.morphology.segment_angle

* pre v3.3: NA
* post v3.3: labeled_img = **plantcv.morphology.segment_angle**(*segmented_img, objects*)
* post v3.11: labeled_img = **plantcv.morphology.segment_angle**(*segmented_img, objects, label="default"*)
* post v3.3: labeled_img = **plantcv.morphology.segment_angle**(*segmented_img, objects*)
* post v3.11: labeled_img = **plantcv.morphology.segment_angle**(*segmented_img, objects, label="default"*)

#### plantcv.morphology.segment_curvature

Expand All @@ -490,15 +490,15 @@ pages for more details on the input and output variable types.
#### plantcv.morphology.segment_euclidean_length

* pre v3.3: NA
* post v3.3: labeled_img = **plantcv.morphology.segment_euclidean_length**(*segmented_img, objects*)
* post v3.11: labeled_img = **plantcv.morphology.segment_euclidean_length**(*segmented_img, objects, label="default"*)
* post v3.3: labeled_img = **plantcv.morphology.segment_euclidean_length**(*segmented_img, objects*)
* post v3.11: labeled_img = **plantcv.morphology.segment_euclidean_length**(*segmented_img, objects, label="default"*)

#### plantcv.morphology.segment_id

* pre v3.3: NA
* post v3.3: segmented_img, labeled_img = **plantcv.morphology.segment_id**(*skel_img, objects, mask=None*)
* post v3.3: segmented_img, labeled_img = **plantcv.morphology.segment_id**(*skel_img, objects, mask=None*)

#### plantcv.morphology.segment_path_length
#### plantcv.morphology.segment_path_length

* pre v3.3: NA
* post v3.3: labeled_img = **plantcv.morphology.segment_path_length**(*segmented_img, objects*)
Expand All @@ -507,7 +507,7 @@ pages for more details on the input and output variable types.
#### plantcv.morphology.segment_skeleton

* pre v3.3: NA
* post v3.3: segmented_img, segment_objects = **plantcv.morphology.segment_skeleton**(*skel_img, mask=None*)
* post v3.3: segmented_img, segment_objects = **plantcv.morphology.segment_skeleton**(*skel_img, mask=None*)

#### plantcv.morphology.segment_sort

Expand All @@ -523,7 +523,7 @@ pages for more details on the input and output variable types.
#### plantcv.morphology.skeletontize

* pre v3.3: NA
* post v3.3: skeleton = **plantcv.morphology.skeletonize**(*mask*)
* post v3.3: skeleton = **plantcv.morphology.skeletonize**(*mask*)

#### plantcv.naive_bayes_classifier

Expand Down Expand Up @@ -608,6 +608,11 @@ pages for more details on the input and output variable types.
* pre v3.0dev2: **plantcv.plot_image**(*img, cmap=None*)
* post v3.0dev2: **plantcv.plot_image**(*img, cmap=None*)

#### plantcv.Points

* pre v4.0: NA
* post v4.0: marker = **plantcv.Points**(*img, figsize=(6,12)*)

#### plantcv.print_image

* pre v3.0dev2: **plantcv.print_image**(*img, filename*)
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ nav:
- 'Analyze NIR': analyze_NIR_intensity.md
- 'Analyze Shape': analyze_shape.md
- 'Analyze Thermal': analyze_thermal_values.md
- 'Annotation Tools':
- 'Points': Points.md
- 'Apply Mask': apply_mask.md
- 'Auto Crop': auto_crop.md
- 'Background Subtraction': background_subtraction.md
Expand Down
7 changes: 5 additions & 2 deletions plantcv/plantcv/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from plantcv.plantcv.classes import Outputs
from plantcv.plantcv.classes import Spectral_data
from plantcv.plantcv.classes import PSII_data
from plantcv.plantcv.classes import Points

# Initialize an instance of the Params and Outputs class with default values
# params and outputs are available when plantcv is imported
params = Params()
Expand Down Expand Up @@ -85,14 +87,15 @@
from plantcv.plantcv.stdev_filter import stdev_filter
from plantcv.plantcv.spatial_clustering import spatial_clustering
from plantcv.plantcv import photosynthesis
from plantcv.plantcv import annotate
# add new functions to end of lists

# Auto versioning
from ._version import get_versions
__version__ = get_versions()['version']
del get_versions

__all__ = ['fatal_error', 'Params', 'Outputs', 'Spectral_data', 'PSII_data', 'deprecation_warning', 'print_image',
__all__ = ['fatal_error', 'Params', 'Outputs', 'Spectral_data', 'PSII_data', 'Points', 'deprecation_warning', 'print_image',
'plot_image', 'color_palette', 'apply_mask', 'gaussian_blur', 'transform', 'hyperspectral', 'readimage', 'readbayer',
'laplace_filter', 'sobel_filter', 'scharr_filter', 'hist_equalization', 'erode', 'image_add',
'image_subtract', 'dilate', 'watershed', 'rectangle_mask', 'rgb2gray_hsv', 'rgb2gray_lab', 'rgb2gray_cmyk',
Expand All @@ -106,4 +109,4 @@
'background_subtraction', 'naive_bayes_classifier', 'distance_transform', 'params',
'cluster_contour_mask', 'analyze_thermal_values', 'opening',
'closing', 'within_frame', 'fill_holes', 'get_kernel', 'crop', 'stdev_filter',
'spatial_clustering', 'photosynthesis', 'homology']
'spatial_clustering', 'photosynthesis', 'homology', 'annotate']
Empty file.
23 changes: 23 additions & 0 deletions plantcv/plantcv/annotate/points.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Point/vertice annotation tool(s)

import numpy as np
from scipy.spatial import distance

## INTERACTIVE ROI TOOLS ##


def _find_closest_pt(pt, pts):
""" Given coordinates of a point and a list of coordinates of a bunch of points, find the point that has the
smallest Euclidean to the given point

:param pt: (tuple) coordinates of a point
:param pts: (a list of tuples) coordinates of a list of points
:return: index of the closest point and the coordinates of that point
"""
if pt in pts:
idx = pts.index(pt)
return idx, pt

dists = distance.cdist([pt], pts, 'euclidean')
idx = np.argmin(dists)
return idx, pts[idx]
48 changes: 46 additions & 2 deletions plantcv/plantcv/classes.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# PlantCV classes
import os
import cv2
import json
from plantcv.plantcv import fatal_error
import matplotlib.pyplot as plt
from math import floor
from plantcv.plantcv.annotate.points import _find_closest_pt


class Params:
Expand Down Expand Up @@ -182,7 +186,7 @@ def save_results(self, filename, outformat="json"):

class Spectral_data:
"""PlantCV Hyperspectral data class"""

def __init__(self, array_data, max_wavelength, min_wavelength, max_value, min_value, d_type, wavelength_dict,
samples, lines, interleave, wavelength_units, array_type, pseudo_rgb, filename, default_bands):
# The actual array/datacube
Expand Down Expand Up @@ -235,10 +239,50 @@ def __repr__(self):
if v is not None:
mvars.append(k)
return "PSII variables defined:\n" + '\n'.join(mvars)

def add_data(self, protocol):
"""
Input:
protocol: xr.DataArray with name equivalent to initialized attributes
"""
self.__dict__[protocol.name] = protocol


class Points(object):
"""Point annotation/collection class to use in Jupyter notebooks. It allows the user to
interactively click to collect coordinates from an image. Left click collects the point and
right click removes the closest collected point
"""

def __init__(self, img, figsize=(12, 6)):
"""
Initialization
:param img: image data
:param figsize: desired figure size, (12,6) by default
:attribute points: list of points as (x,y) coordinates tuples
"""

self.fig, self.ax = plt.subplots(1, 1, figsize=figsize)
self.ax.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

self.points = []
self.events = []

self.fig.canvas.mpl_connect('button_press_event', self.onclick)

def onclick(self, event):
""" Handle mouse click events
"""
self.events.append(event)
if event.button == 1:

self.ax.plot(event.xdata, event.ydata, 'x', c='red')
self.points.append((floor(event.xdata), floor(event.ydata)))

else:
idx_remove, _ = _find_closest_pt((event.xdata, event.ydata), self.points)
# remove the closest point to the user right clicked one
self.points.pop(idx_remove)
ax0plots = self.ax.lines
self.ax.lines.remove(ax0plots[idx_remove])
self.fig.canvas.draw()
42 changes: 42 additions & 0 deletions tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5200,6 +5200,48 @@ def test_plantcv_roi_custom_bad_input():
_ = pcv.roi.custom(img=img, vertices=[[226, -1], [3130, 1848], [2404, 2029], [2205, 2298], [1617, 1761]])


def test_plantcv_annotate_Points_interactive():
# Read in a test grayscale image
img = cv2.imread(os.path.join(TEST_DATA, TEST_INPUT_COLOR), -1)

# initialize interactive tool
drawer_rgb = pcv.Points(img, figsize=(12, 6))

# simulate mouse clicks
# event 1, left click to add point
e1 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=drawer_rgb.fig.canvas,
x=0, y=0, button=1)
point1 = (200, 200)
e1.xdata, e1.ydata = point1
drawer_rgb.onclick(e1)

# event 2, left click to add point
e2 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=drawer_rgb.fig.canvas,
x=0, y=0, button=1)
e2.xdata, e2.ydata = (300, 200)
drawer_rgb.onclick(e2)

# event 3, left click to add point
e3 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=drawer_rgb.fig.canvas,
x=0, y=0, button=1)
e3.xdata, e3.ydata = (50, 50)
drawer_rgb.onclick(e3)

# event 4, right click to remove point with exact coordinates
e4 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=drawer_rgb.fig.canvas,
x=0, y=0, button=3)
e4.xdata, e4.ydata = (50, 50)
drawer_rgb.onclick(e4)

# event 5, right click to remove point with coordinates close but not equal
e5 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=drawer_rgb.fig.canvas,
x=0, y=0, button=3)
e5.xdata, e5.ydata = (301, 200)
drawer_rgb.onclick(e5)

assert drawer_rgb.points[0] == point1


# ##############################
# Tests for the transform subpackage
# ##############################
Expand Down