Advanced display
Contents
Advanced display#
This project consists in introducing some additional graphical interactivity into the graphical application display.py which you have developed all along the exercices, for what concerns background computation, background removal and cluster identification. You will explore advanced features of matplotlib to interact dynamically with your display application and its data. This project is split in three independent parts, and you are adviced to check the final section of graphics explanations.
Interactive Suppression of the Background and Cluster Building#
You’ll be implementing a Slider
widget to interactively select the level of background
to be applied to (remove from) the current image, with the ability to redo the cluster finding
to show the background change impact.
This will demonstrate how an interactive widget can be installed within the application so as to specify a numerical value for one application’s variable.
Principle#
A PyPlot widget is an object with specific behaviour, and specific properties. The behaviour is specified by declaring a user defined python function, as being connected with a given user action such as:
clicking the mouse
dragging the mouse
changing a value
In our case, we want to study the impact of selecting a background level to the signal/background separation.
Implementation details#
The main program for this project must be in a file called pjd_display.py
.
It can be started by duplicating the content of your previous display.py
.
Background control#
One possibility is to use a matplotlib.widgets.Slider
widget.
Some useful hints to help with this project:
create a specific display area (using the
matplotlib.axes.Axes
functions) specifying the size of the areaCreate a
slider
widget inside this area, with the following arguments:the display area where to install it
a title
the minimum value of the variable controled by the slider button
the maximum value of the variable controled by the slider button
the initial value of the variable controled by the slider button (this is a named argument
valinit=x
)
define an action function to be called whenever the slider changes.
this function receives one argument: the current value
don’t forget to use the generic redraw function (
matplotlib.canvas.draw_idle
) within this action function
declare the action function to the widget, using the
my_widget.on_changed(my_function)
Cluster rebuild#
re-compute the number of clusters whenever the slider changes
you can refresh the displayed image using the update function
my_plotting_area.set_data(my_new_image)
Expected Result#
When the user move the slider, she can see the effect on background removal and clustering.
Cluster discovery#
You are now asked to extend your pjd_display.py
application with some kind of animation:
each time the mouse pointer enter a cluster, you are asked to draw a red rectangle
around this cluster. When the mouse pointer goes outside the cluster area, we want the red
rectangle to disappear.
To do so, you must define a function onmove()
, or an object-function OnMove()
,
that you will declare as the handler for any mouse motion event. The event is an object with
several attributes, two of them indicating the position of the mouse:
event.xdata
: the pixel x coordinate of the mouse (in the display coordinate system)event.ydata
: the pixel y coordinate of the mouse (in the display coordinate system)
Once written, your event handler has to be associated with the appropriate event
(here mouse motion) to become active. This is done with the following pyplot
method:
fig.canvas.mpl_connect('motion_notify_event', onmove)
Cluster identification#
Finally, when the mouse is over a cluster, and the user click, we ask you to display over the image the name of the associated celestial object. It must stay here until the mouse leave the cluster area.
Processing Mouse Clicks#
To be able to select interactively an object in the image by clicking on it, it is necessary
to add another event handler that will process the click event, using the same mechanism that
we used in the previous section.
After writing the handler function (on_click()
in the example below), you need
to register it for the click event:
fig.canvas.mpl_connect('button_press_event', on_click)
As for the previous section, the click handler receives
one argument which is a dictionary describing the event. The button
entry in this dictionary
is a number indicating which button has been pressed (1 for the leftmost one).
To check if a user clicked on a cluster (or outside of any cluster), you will need to implement
a new method in the cluster object. The click coordinates received as part of the event are
expressed in display coordinates which are different from the image coordinates
(pixel x
and y
in the image array). To convert from the display coordinates
to the image coordinates, you need to do:
# Create a transformation matrix display_to_image = axes.transData.inverted() # Image coordinates returned as a list image_x_y = display_to_image.transform((event.x, event.y))
Displaying a Text on an Image#
To display some text onto the displayed image, you have to use the pyplot
axes.text()
function (which returns an identifier of the text block written). axes.text()
requires
the following arguments:
x coordinate: x position in display pixel coordinates where the text must be displayed (x coordinate of the cluster peak for example)
y coordinate: same remark as above for the y position
The string you want to display
One or several optional arguments (note that the suggested values are not strings but an argument name followed by a value). In the present case, you should define:
the font size: a typical value is
fontsize=14
the text color: a typical value is
color='white'
Coordinate system to use: must be
transform=axes.transData
if the coordinates are expressed as image pixel coordinates ortransform=None
if the coordinates are those returned by the event in the context of an event handler. If the coordinates are expressed as image pixel coordinates, this argument can be omitted (this is the default).
If you want to add the text inside the mouse motion handler, you first need, in the event handler, to retrieve the axes (image) where the mouse is located. This is done with:
axes = event.inaxes
Note that the axes can be undefined (None
) if the mouse is outside an image (an event
is generated wherever the mouse is located, as soon as it moves).
Once the text has been added, it is necessary to redraw the image for the text to be displayed. Inside the event handler, this is done as follow:
event.canvas.draw()