I am in the process of developing an application which can generate a 2nd plot by clicking data point in the 1st plot. I am using events to accomplish this.
Question:
Code I have so far:
"""
compute the mean and stddev of 100 data sets and plot mean vs stddev.
When you click on one of the mu, sigma points, plot the raw data from
the dataset that generated the mean and stddev
"""
import numpy as np
import matplotlib.pyplot as plt
X = np.random.rand(100, 1000)
xs = np.mean(X, axis=1)
ys = np.std(X, axis=1)
fig = plt.figure()
ax = fig.add_subplot(211)
bx = fig.add_subplot(212)
# ax.set_title('click on point to plot time series')
# bx.set_title('click on point to plot time series')
line, = ax.plot(xs, ys, 'bs', picker=5) # 5 points tolerance
line1, = bx.plot(xs, ys, 'bo', picker=5) # 5 points tolerance
def onpick(event):
if event.artist!=line: return True
N = len(event.ind)
if not N: return True
figi = plt.figure()
for subplotnum, dataind in enumerate(event.ind):
ax = figi.add_subplot(N,1,subplotnum+1)
ax.plot(X[dataind])
ax.text(0.05, 0.9, 'mu=%1.3f\nsigma=%1.3f'%(xs[dataind], ys[dataind]),
transform=ax.transAxes, va='top')
ax.set_ylim(-0.5, 1.5)
bx = figi.add_subplot(N,1,subplotnum+1)
bx.plot(X[dataind])
bx.text(0.05, 0.9, 'mu=%1.3f\nsigma=%1.3f'%(xs[dataind], ys[dataind]),
transform=ax.transAxes, va='top')
bx.set_ylim(-0.5, 1.5)
figi.show()
return True
fig.canvas.mpl_connect('pick_event', onpick)
plt.show()
By clicking data points on the first plot, 2nd plot will be generated.
Now expectations are to generate a 3rd plot clicking the 2nd plot data point.
I have researched on this, but I am not successful :-( :-(
If my approach is wrong, please do suggest the any other alternative.
Call matplotlib. pyplot. plot(x, y) with x and y set to arrays of data points to construct a plot. Calling this function multiple times on the same figure creates multiple plots in the same graph.
import matplotlib.pyplot as plt
import numpy as np
# data source
data_bucket = {}
# l1: randn
# l2: sum(l1)
# l3: sum(l2)
# generate some 3 layer synthetic data
N = 1000
l1_count = 50
l2_count = 50
l3_count = 2
x = np.arange(N)
for j in range(l3_count):
l3 = []
for k in range(l2_count):
l2 = []
for m in range(l1_count):
l1 = data_bucket[(j, k, m)] = np.random.randn(N)
l2.append(np.sum(l1))
l2 = data_bucket[(j, k)] = np.asarray(l2)
l3.append(np.sum(l2))
data_bucket[(j, )] = np.asarary(l3)
# only hase to close over the data
def picker(event):
print(event.artist.get_gid())
print(event.ind)
# some function to generate next data key from gid + index
k = event.artist.get_gid() + tuple(event.ind)
try:
next_data = data_bucket[k]
except KeyError:
print("no generations of data left")
return
# make the previous generation of plot
fig, ax = plt.subplots()
# can use the key here to dispatch to different plotting functions
ax.plot(next_data, gid=k, picker=5, ls='-')
fig.canvas.mpl_connect('pick_event', picker)
fig, ax = plt.subplots()
for k in range(l3_count):
k = (k, )
ax.plot(data_bucket[k], gid=k, picker=5, ls='', marker='o')
fig.canvas.mpl_connect('pick_event', picker)
The tricky part of this managing the mapping between the data in the 'current' figure and the next layer of data. All mpl artists have a gid
attribute which can be used to uniquely identify them so here I use that + the index to generate keys into a dictionary which are tuples of integers of varying length. This was just the first thing that popped into my head when trying to make synthetic 3-layer data. In principle any keying system that uses the gid of the picked artist + the index in that line -> next layer of data will work.
You can then use the same picker function for all of your figures and it only needs to close over the data source. All of this could (should?) be rolled up into a single class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With