Tkinter and matplotlib: select coordinates with cursor - python

For the lab where I am working, I am currently developing a software that, basically, takes a 3D matrix, where the three axis are intensity as a function of time, and perform some FT over them, obtaining a 3D matrix with intensity as a function of frequency. By slicing and plotting that 3D matrix over the Z axis, it is possible to visualize some 2D maps that contain useful information for my experiments, like this one:
beating_map
A different source of information is obtained when summing over the X and Y axis, and plotting the results as intensity as a function of the Z axis. In our experiment, not every X and Y coordinate contains the information that we need. Therefore, making the sum over specific x-y coordinates of that 3D matrix is necessary. Example of this windows setting can be found here:
sum_spectra
Question is, is there a way that, with the cursor, tkinter can interact with matplotlib graphs and extract information about coordinates? A way in such, making some clicks, the user could select these coordinates without having to write them manually in some input box to make the sum. This is only one example of windows setting but, in fact, I have many other graphs where this interaction cursor-matplotlib-tkinter would be amazing to simplify the work.
I add the code of the map where I would like to have this interaction, just an example to work with:
self.fig = Figure(figsize=(4.5, 4.5))
self.ax = self.fig.add_subplot(111) # create axis
self.canvas = FigureCanvasTkAgg(self.fig, master=frame) # A tk.DrawingArea.
self.canvas.get_tk_widget().pack(side="top")
self.map = self.ax.contourf(x, y, intensity,
cmap=cmap, levels=15) # draw board
self.toolbar = NavigationToolbar2Tk(self.canvas, frame)
self.toolbar.update()
self.canvas.get_tk_widget().pack(side="bottom")
self.canvas.draw_idle() # update matplotlib figure
Simple code to include would be:
Trigger: click on the graph
Event: print the coordinates
With that tool is enough for me to start developing the code. If you need more of my code, please let me know. I leave one example of a MatLab software that does what I need:
matlab_example
It is possible to see that the cursor is now an arrow that, after clicking, save the x coordinates of the point where the click has been made.
Thank you very much for your time.

Related

How to change the scale of an image to overlay with points in Matplotlib? [duplicate]

I want to create a figure that shows a background image with overlaid scatter and line plots:
As you can see, the axes ticks show image coordinates. The scatter and line plot are given in image coordinates, too - which is not desired. The scatter and line plots should still be able to work (and be meaningful) without the background image. The extent is not known because this figure is used to determine the extent (interactively) in the first place.
Instead, I'd like to specify the scatter and line plots in the coordinate system shown in the background image (units m³/h and m): the transformation from image coordinates to "axis on top" coordinates would be roughly (110,475) -> (0,10) and (530,190) -> (8,40).
In principle I can see two ways of doing it:
specify image extent after it has been added. However, I don't see this documented anywhere; This example shows how it's done when the extent is known at the call to imshow(): Plot over an image background in python
add an axes on top of the image axes with twinx and twin y, where both x,x and y,y pairs are tightly coupled. I have only seen features that allow me to specify a shared x or a shared y axis, not both.
The restriction here seems to be that "The scatter and line plots should still be able to work (and be meaningful) without the background image.". This however would not imply that you cannot use the extent keyword argument.
At the time you add the image, you'd specify the extent.
plt.scatter(...)
plt.plot(...)
plt.imshow(..., extent = [...])
You can also set the extent later, if that is desired for some reason not explained in the question, i.e.
plt.scatter(...)
plt.plot(...)
im = plt.imshow(...)
im.set_extent([...])
Finally you may also decide to remove the image, and plot it again; this time with the desired extent,
plt.scatter(...)
plt.plot(...)
im = plt.imshow(...)
im.remove()
im = plt.imshow(..., extent=[...])

Specify Height and Width of zoomed Image in Matplotlib after plt.show()

I have a plotting routine and I show the result with
plt.show()
as this is the easiest way for me to see my data. Once I have found and area which I want to look at i want to plot the exact same area again for a different set of data which has the same xy dimensions. The easies way for me would be to see the coordinates of the corners after the zoom or the origin of the zoom and the size in xy direction.
I found this solution . If I understand it correctly I have to manually change the plotting script with the new x y limits for each subsequent plot I want to make.
Is there a possibility to show the limit of the manual zoom in the panel itself and have the possibility to perform and actual input in dedicated fields such that I can recreate this zoom?
Do you mean something like this?
This "Figure options" dialog is present in the Qt backend. To use it,
import matplotlib
matplotlib.use("Qt4Agg") # or "Qt5Agg" depending on the version

Getting matplotlib to render points clicked with a mouse.

I am new to Gui programming, so if this question has been repeated elsewhere using proper terminology I apologize.
Is it possible to make interactive geometric animations with matplotlib? In particular, I want to embed an interactive Matplotlib window within a Tkinter frame to test out several variants of the same algorithm.
Here is a typical usage scenario for which I want to write an interactive
program as described above: Say I want to test a triangulation algorithm for point-sets in the 2-d plane.
When I run my new_triangulation_algorithm.py script, I would like to open up an interactive tkinter frame having an embedded matplotlib window, where the user "mouses-in" his/her points by clicking on, say, 20 different points -- every time a point is selected, a thick blue dot appears at that position. I know Matplotlib "knows" the coordinates of the point when I hover my mouse cursor over it since I always see it displayed in the status bar of my plots.
But I don't know how to input a point at that position with a mouse.
The second panel of my Tkinter frame would then contain several buttons, each button corresponding a different triangulation algorithm which I would like to animate on a given point set.
As the algorithm proceeds, I would like the matplotlib window to get refreshed to show the current state of the algorithm. I presume I would have to use Matplotlib's animation feature to do this, but I am not sure about
this since Matplotlib will have to be embedded in a Tkinter frame.
In future, I would like not only to input points, but also segments, circles, rectangles, but I would want to master a basic example with points
as described above.
This example might be a start. Its backend independend. To add your own buttons you might want to have a look at matplotlibs NavigationToolbar class. There are backend specific implementations like NavigationToolbar2QTAgg. You could inherit the Tk version and add some controls.
from matplotlib import pyplot
import numpy
x_pts = []
y_pts = []
fig, ax = pyplot.subplots()
line, = ax.plot(x_pts, y_pts, marker="o")
def onpick(event):
m_x, m_y = event.x, event.y
x, y = ax.transData.inverted().transform([m_x, m_y])
x_pts.append(x)
y_pts.append(y)
line.set_xdata(x_pts)
line.set_ydata(y_pts)
fig.canvas.draw()
fig.canvas.mpl_connect('button_press_event', onpick)
pyplot.show()

Creating triangulated grid mesh using matplotlib

So I have been creating mesh's using software called BlueKenue for hydraulic models, which is great. In the document I am currently writing I would like to include an image of the mesh however the mesh's I have constructed are very long in the x-axis and short in the y direction. Unfortunately BlueKenue will not allow you to have different scale ranges on your axis (or if it does I have not been able to find a way), i.e. if you have increments of 5 on one axis you will have likewise on the other. I have included an image of the mesh I currently have to illustrate my problem. If I can construct this mesh in matplotlib I can then ensure my image is suitably clear.
My question is can I reproduce this mesh in Matplotlib in a relatively simple way? (I am fairly new to python). The mesh is a regular grid which has been triangulated.
Edit:
Mesh dimensions 29.76 x 2
x intervals = 0.16m (186 points along the x axis)
y intervals = 0.20m (10 points along the y axis)
Thanks

How do I convert (or scale) axis values and redefine the tick frequency in matplotlib?

I am displaying a jpg image (I rotate this by 90 degrees, if this is relevant) and of course
the axes display the pixel coordinates. I would like to convert the axis so that instead of displaying the pixel number, it will display my unit of choice - be it radians, degrees, or in my case an astronomical coordinate. I know the conversion from pixel to (eg) degree. Here is a snippet of what my code looks like currently:
import matplotlib.pyplot as plt
import Image
import matplotlib
thumb = Image.open(self.image)
thumb = thumb.rotate(90)
dpi = plt.rcParams['figure.dpi']
figsize = thumb.size[0]/dpi, thumb.size[1]/dpi
fig = plt.figure(figsize=figsize)
plt.imshow(thumb, origin='lower',aspect='equal')
plt.show()
...so following on from this, can I take each value that matplotlib would print on the axis, and change/replace it with a string to output instead? I would want to do this for a specific coordinate format - eg, rather than an angle of 10.44 (degrees), I would like it to read 10 26' 24'' (ie, degrees, arcmins, arcsecs)
Finally on this theme, I'd want control over the tick frequency, on the plot. Matplotlib might print the axis value every 50 pixels, but I'd really want it every (for example) degree.
It sounds like I would like to define some kind of array with the pixel values and their converted values (degrees etc) that I want to be displayed, having control over the sampling frequency over the range xmin/xmax range.
Are there any matplotlib experts on Stack Overflow? If so, thanks very much in advance for your help! To make this a more learning experience, I'd really appreciate being prodded in the direction of tutorials etc on this kind of matplotlib problem. I've found myself getting very confused with axes, axis, figures, artists etc!
Cheers,
Dave
It looks like you're dealing with the matplotlib.pyplot interface, which means that you'll be able to bypass most of the dealing with artists, axes, and the like. You can control the values and labels of the tick marks by using the matplotlib.pyplot.xticks command, as follows:
tick_locs = [list of locations where you want your tick marks placed]
tick_lbls = [list of corresponding labels for each of the tick marks]
plt.xticks(tick_locs, tick_lbls)
For your particular example, you'll have to compute what the tick marks are relative to the units (i.e. pixels) of your original plot (since you're using imshow) - you said you know how to do this, though.
I haven't dealt with images much, but you may be able to use a different plotting method (e.g. pcolor) that allows you to supply x and y information. That may give you a few more options for specifying the units of your image.
For tutorials, you would do well to look through the matplotlib gallery - find something you like, and read the code that produced it. One of the guys in our office recently bought a book on Python visualization - that may be worthwhile looking at.
The way that I generally think of all the various pieces is as follows:
A Figure is a container for all the Axes
An Axes is the space where what you draw (i.e. your plot) actually shows up
An Axis is the actual x and y axes
Artists? That's too deep in the interface for me: I've never had to worry about those yet, even though I rarely use the pyplot module in production plots.

Categories

Resources