Mouse Click Display using mpldatacursor is unreadable - python

I am using the mpldatacursor library to click on points on a scatter plot and store the values into a list for later use. This seems to be working fine but I also would like to see the values that I've clicked on in the scatter plot. I am using this example from Stack Overflow: Python: get corresponding information of data points interactively with mouse. The problem I am having is that the values shown when clicked are unreadable and sometimes doesn't even show up. The code is roughly the same as shown in the example, so I don't understand why, in my case, the values aren't readable. Could this possibly be because I need to update matplotlib to the newest version? Any suggestions would be appreciated.
import matplotlib.pyplot as plt
from mpldatacursor import datacursor
%matplotlib nbagg
import random
import numpy as np
fig, ax = plt.subplots()
ax.set_title('Double click on a dot to display its label')
# Plot a number of random dots
for i in range(1, 1000):
x = random.random()
y = random.random()
ax.scatter([x], [y], label='ID: X: {:.4f},Y: {:.4f}'.format(x,y))
# Use a DataCursor to interactively display the label for a selected line...
datacursor(formatter='{label}'.format)
coords = []
def onclick(event):
global ix, iy
ix, iy = event.xdata, event.ydata
print ('x = %d, y = %d'%(
ix, iy))
global coords
coords.append((ix, iy))
if len(coords) == 3:
fig.canvas.mpl_disconnect(cid)
return coords
cid = fig.canvas.mpl_connect('button_press_event', onclick)

Related

Faster rendering by using blitting is not working in Matplotlib

Hello fellow developers,
I am working on a project where I have to plot real time data coming from the sensors. I have created a naive generator that gives data points to plot. I was referencing the code from the documentation but it doesn't draw anything, even though the program is reading all the data points from the file. I have include screenshots of the outputs.
The first value in the tuple is the x value and the second value is the list of y value. I am plotting only the 1 value from the y value's list.
The graph opens but the plot is not drawn.
What could be the possible issue with the code?
from getData import GetData
import numpy as np
import matplotlib
# matplotlib.use('MacOSX')
from matplotlib import pyplot as plt
def getNextPoint(getDataObj):
dataPoint = getDataObj.__next__()
if dataPoint != None:
x,y = dataPoint
print(x,y)
return x,y
else:
return getNextPoint(getDataObj)
def run(niter=1000):
fig, ax = plt.subplots()
getDataObj = GetData()
x, y = getNextPoint(getDataObj)
points = ax.plot(x, y[0], animated=True)[0]
plt.show(block=False)
plt.pause(0.1)
background = fig.canvas.copy_from_bbox(fig.bbox)
ax.draw_artist(points)
fig.canvas.blit(fig.bbox)
for ii in range(niter):
# restore background
fig.canvas.restore_region(background)
# update the xy data
x, y = getNextPoint(getDataObj)
points.set_data(x, y[0])
# redraw just the points
ax.draw_artist(points)
# fill in the axes rectangle
fig.canvas.blit(fig.bbox)
fig.canvas.flush_events()
ax.autoscale()
# plt.show()
if __name__ == '__main__':
run()

PyCharm how to display plot in seperate window on same monitor

When i plot something in PyCharm using matplotlib it plots the figure in a seperate window, which is what i want, but it also opens it on the main monitor. Is there a option to open it on my second monitor?
I could not find any similar question (only questions about plotting on the same monitor without a seperate window).
Thanks in advance!
You can specify a position in the code
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
mngr = plt.get_current_fig_manager()
# to put it into the upper left corner for example:
mngr.window.setGeometry(2000,100,640, 545)
plt.show()
I have found a solution in another post How do you set the absolute position of figure windows with matplotlib?
def move_figure(f, x, y):
"""Move figure's upper left corner to pixel (x, y)"""
backend = matplotlib.get_backend()
if backend == 'TkAgg':
f.canvas.manager.window.wm_geometry("+%d+%d" % (x, y))
elif backend == 'WXAgg':
f.canvas.manager.window.SetPosition((x, y))
else:
# This works for QT and GTK
# You can also use window.setGeometry
f.canvas.manager.window.move(x, y)
f, ax = plt.subplots()
move_figure(f, 2200, 500)
plt.show()

ipywidget with matplotlib figure always shows two axes

I am trying to create a ipywidget interface with a matplotlib figure that updates upon changing a slider. It works in principle, but it always creates an extra figure.
Here's the code:
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import widgets
from IPython.display import display, clear_output
# make a grid
x = np.linspace(0, 5, 100)
X, Y = np.meshgrid(x, x)
# create the layout with slider
out = widgets.Output(layout=widgets.Layout(height='300px', width = '400px', border='solid'))
slider = widgets.IntSlider(value=1, min=1, max=5)
w = widgets.VBox(children=(out, slider))
# axes to plot into
ax = plt.axes()
display(w)
def update(value):
i = slider.value
Z = np.exp(-(X / i)**2 - (Y / i)**2)
ax.pcolormesh(x, x, Z, vmin=0, vmax=1, shading='auto')
with out:
clear_output(wait=True)
display(ax.figure)
slider.observe(update)
update(None)
And here's the undesired output
The widget works, and only the upper output is updated, but I do not understand why the lower output also exists or how to get rid of it. Am I missing something obvious?
You can use the widget backend, %matplotlib widget, which I think is designed for this. You'll need to put %matplotlib widget at the top (or before matplotlib stuff is brought in).
Update: Also some guidance form matplotlib here and below, emphasis added.
Note
To get the interactive functionality described here, you must be using
an interactive backend. The default backend in notebooks, the inline
backend, is not. backend_inline renders the figure once and inserts a
static image into the notebook when the cell is executed. Because the
images are static, they can not be panned / zoomed, take user input,
or be updated from other cells.
Your example can be reduced to:
%matplotlib widget
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import widgets
from IPython.display import display, clear_output
x = np.linspace(0, 5, 100)
X, Y = np.meshgrid(x, x)
slider = widgets.IntSlider(value=1, min=1, max=5)
ax = plt.axes()
display(slider)
def update(value):
i = slider.value
Z = np.exp(-(X / i)**2 - (Y / i)**2)
ax.pcolormesh(x, x, Z, vmin=0, vmax=1, shading='auto')
slider.observe(update)
update(None)
The answer by jayveesa is a really good way to avoid this output. I'd like to add an answer to the why of your question.
The widget works, and only the upper output is updated, but I do not understand why the lower output also exists or how to get rid of it. Am I missing something obvious?
An instructive thing to do here is to comment out the lines in update that display the figure
def update(value):
i = slider.value
Z = np.exp(-(X / i)**2 - (Y / i)**2)
ax.pcolormesh(x, x, Z, vmin=0, vmax=1, shading='auto')
# with out:
# clear_output(wait=True)
# display(ax.figure)
update(None)
if you do this you will see only one plot output. This is because when you use the the %matplotlib inline backend for jupyter notebooks then any figure that was created in a cell will be closed and displayed when the cell finishes running. (see explanation from a core matplotlib dev here: https://github.com/matplotlib/matplotlib/issues/18248#issuecomment-675177108). So the figure surrounded by a black outline is from the display(ax.figure) and the lower figure is from the figure that was created earlier.

How to slice list from matplotlib ginput

I have a list of values in Python, which I'm plotting with matplotlib. I'm then trying to use ginput in matplotlib to click two points on the graph, from which the X coordinates will be taken, between which to slice my original list. However, I can't seem to find a way to do this.
I already have a list of numbers called MIList, and the following code isn't working for me:
startinput = plt.ginput(2)
print("clicked", startinput)
startinputxvalues = [x[0] for x in startinput]
print(startinputxvalues)
x1 = startinputxvalues[0]
print(x1)
x2 = startinputxvalues[1]
print(x2)
slicedMIList = [MIList[int(x1):int(x2)]]
plt.plot(slicedMIList)
This gives me an array, but it doesn't plot these values on my graph - does anyone have any input as to what I'm doing wrong?
Thanks
The main point is that you need to redraw the canvas, once changes have been made to it. So in order for the new plot to become visible you can call
plt.gcf().canvas.draw()
Here is a complete working code:
import matplotlib.pyplot as plt
import numpy as np
X = np.arange(10)
Y = np.sin(X)
plt.plot(X, Y)
startinput = plt.ginput(2)
x, y = zip(*startinput)
Ysliced = Y[int(x[0]):int(x[1])+1]
Xsliced = X[int(x[0]):int(x[1])+1]
plt.plot(Xsliced, Ysliced, color="C3", linewidth=3)
#draw the canvas, such that the new plot becomes visible
plt.gcf().canvas.draw()
plt.show()

How to display data in a matplot plot

I'm trying to make an interactive plot in the jupyter notebook but i don't know exactly how to implement it. Having a dataframe i run a simple regression that is then plotted to see the distribution. I'd like to be able to hover one of the points and get data associated with this point. How can i do that? Right now i can only produce a static plot
import pandas as pd
from sklearn import linear_model
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
net = pd.read_csv("network_ver_64.csv")
net = net[net.AWDT12 > 0]
x = net.LOAD_DAILY.values
y = net.AWDT12.values
x_lenght = int(x.shape[0])
y_lenght = int(y.shape[0])
x = x.reshape(x_lenght, 1)
y = y.reshape(y_lenght,1)
regr = linear_model.LinearRegression()
regr.fit(x, y)
plt.scatter(x, y, color='black')
plt.plot(x, regr.predict(x), color='blue', linewidth=1)
plt.xticks(())
plt.yticks(())
plt.show()
First of all it's clear that the %matplotlib inline backend does not allow for interaction, as it is inline (in the sense that the plots are images).
However even in the notebook you can get interaction using the %matplotlib notebook backend. A basic hover took is already implemented: Moving the mouse in the canvas shows the current mouse position in data coordinates in the lower right corner.
Of course you can obtain more sophisticated functionality by writing some custom code. E.g. we can modify the picking example a little bit as follows:
import matplotlib.pyplot as plt
%matplotlib notebook
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_title('click on points')
line, = ax.plot(np.random.rand(100), 'o', picker=5) # 5 points tolerance
text = ax.text(0,0,"")
def onpick(event):
thisline = event.artist
xdata = thisline.get_xdata()
ydata = thisline.get_ydata()
ind = event.ind
text.set_position((xdata[ind], ydata[ind]))
text.set_text(zip(xdata[ind], ydata[ind]))
fig.canvas.mpl_connect('pick_event', onpick)
plt.show()
This now shows the data coordinates of the point the mouse has clicked.
You're pretty free to adapt this to any case you like and make it more pretty using the standard matplotlib tools.

Categories