def tracking(animal_id, session, scan_idx): form = TrackingForm(request.form) key = dict( animal_id=animal_id, session=session, scan_idx=scan_idx, ) figure = None if pupil.Eye() & key: prev = (pupil.Eye() & key).fetch1('preview_frames') fig, ax = plt.subplots(4,4,figsize=(10, 8), sharex="col", sharey="row") for a, fr in zip(ax.ravel(), prev.transpose([2,0,1])): a.imshow(fr, cmap='gray', interpolation='bicubic') a.axis('off') a.set_aspect(1) plugins.connect(fig, plugins.LinkedBrush([])) # TODO Edgar change that here figure = mpld3.fig_to_html(fig) else: flash('Could not find figure for key {}'.format(str(key))) if request.method == 'POST' and form.validate(): pass return render_template('trackingtask.html', form=form, figure=figure)
def plot_page_mpld3(df, columns, request): if request.method == 'POST': # Something is being submitted x1 = str(request.form['x1']) x2 = str(request.form['x2']) y1 = str(request.form['y1']) y2 = str(request.form['y2']) z = str(request.form['z']) for requested_col in {x1, x2, y1, y2, z}: if requested_col not in columns: return redirect(url_for('mpld3_plot')) else: x1, x2, y1, y2, z = 'teff', 'vt', 'Vabs', 'feh', 'logg' # Does not work with NaN values! df = df.loc[:, {x1, x2, y1, y2, z}].dropna(axis=0) fig, ax = plt.subplots(2, 2, figsize=(14, 8), sharex='col', sharey='row') points = ax[0, 0].scatter(df[x1], df[y1], c=df[z], alpha=0.6) points = ax[1, 0].scatter(df[x1], df[y2], c=df[z], alpha=0.6) points = ax[0, 1].scatter(df[x2], df[y1], c=df[z], alpha=0.6) points = ax[1, 1].scatter(df[x2], df[y2], c=df[z], alpha=0.6) ax[1, 0].set_xlabel(x1) ax[1, 1].set_xlabel(x2) ax[0, 0].set_ylabel(y1) ax[1, 0].set_ylabel(y2) plugins.connect(fig, plugins.LinkedBrush(points)) plot = fig_to_html(fig) return render_template('plot_mpld3.html', plot=plot, columns=columns, x1=x1, x2=x2, y1=y1, y2=y2, z=z)
def plot_page_mpld3(df, columns, request, field=None, value=None): if request.method == 'POST': # Something is being submitted x1 = str(request.form['x1']) x2 = str(request.form['x2']) y1 = str(request.form['y1']) y2 = str(request.form['y2']) z = str(request.form['z']) for requested_col in {x1, x2, y1, y2, z}: if requested_col not in columns: return redirect(url_for('sd')) else: x1, x2, y1, y2, z = 'days_old', 'los', 'los', 'los', 'days_old' if field and value is None: field = 'all fields' value = 'all values' # Does not work with NaN values! so we must remove rows with NaN values df = df.loc[:, {x1, x2, y1, y2, z}].dropna(axis=0) fig, ax = plt.subplots(2, 2, figsize=(12, 8), sharex='col', sharey='row') points = ax[0, 0].scatter(df[x1], df[y1], c=df[z], alpha=0.6) points = ax[1, 0].scatter(df[x1], df[y2], c=df[z], alpha=0.6) points = ax[0, 1].scatter(df[x2], df[y1], c=df[z], alpha=0.6) points = ax[1, 1].scatter(df[x2], df[y2], c=df[z], alpha=0.6) ax[0, 0].set_ylabel(y1) ax[0, 0].set_xlabel(x1) ax[1, 0].set_ylabel(y2) ax[1, 0].set_xlabel(x1) ax[1, 1].set_ylabel(y2) ax[1, 1].set_xlabel(x2) # ax[1, 0].set_title('Filtered by {} of {}'.format(field, value)) # ax[1, 1].set_title('Filtered by {} of {}'.format(field, value)) # ax[0, 0].set_title('Filtered by {} of {}'.format(field, value)) size = df.shape[0] ax[0, 1].set_title('all plots filtered by {} with {} of size: {}'.format( field, value, str(size))) ax[0, 1].set_ylabel(y1) ax[0, 1].set_xlabel(x2) for axe in ax.flatten(): for tk in axe.get_yticklabels(): tk.set_visible(True) for tk in axe.get_xticklabels(): tk.set_visible(True) ax[0, 0].grid(color='grey', linestyle='-', linewidth=2) ax[0, 1].grid(color='grey', linestyle='-', linewidth=2) ax[1, 0].grid(color='grey', linestyle='-', linewidth=2) ax[1, 1].grid(color='grey', linestyle='-', linewidth=2) plugins.connect(fig, plugins.LinkedBrush(points)) plot = fig_to_html(fig) return render_template('plot_mpld3.html', plot=plot, columns=columns, x1=x1, x2=x2, y1=y1, y2=y2, z=z)
def demo(): if request.method == 'POST': # Something is being submitted x1 = str(request.form['x1']) x2 = str(request.form['x2']) y1 = str(request.form['y1']) y2 = str(request.form['y2']) z = str(request.form['z']) else: x1, x2, y1, y2, z = 'teff', 'mass', 'Vmag', 'par', 'logg' df = pd.read_table('stars.csv') columns = df.columns.values df = df.loc[:, list(set([x1, x2, y1, y2, z]))].dropna(axis=0) fig, ax = plt.subplots(2, 2, figsize=(10, 8), sharex='col', sharey='row') points = ax[0, 0].scatter(df[x1], df[y1], c=df[z], alpha=0.6) points = ax[1, 0].scatter(df[x1], df[y2], c=df[z], alpha=0.6) points = ax[0, 1].scatter(df[x2], df[y1], c=df[z], alpha=0.6) points = ax[1, 1].scatter(df[x2], df[y2], c=df[z], alpha=0.6) ax[1, 0].set_xlabel(x1) ax[1, 1].set_xlabel(x2) ax[0, 0].set_ylabel(y1) ax[1, 0].set_ylabel(y2) plugins.connect(fig, plugins.LinkedBrush(points)) plot = fig_to_html(fig) return render_template('plot.html', plot=plot, columns=columns, x1=x1, x2=x2, y1=y1, y2=y2, z=z)
def gen_html(self, dataset=None, channels=["FSC-A", "SSC-A"]): if not dataset: dataset = self.dataset data = [dataset[i].values for i in channels] fig = plt.figure() ax = fig.add_subplot(111) plot = ax.scatter(data[0], data[1]) plugins.clear(fig) plugins.connect(fig, plugins.LinkedBrush(plot), plugins.ClickSendToBack(plot)) the_html = mpld3.fig_to_html(fig) with open("initialfigure.html", "w") as file: file.write(the_html) o = bs(open("initialfigure.html"), "html.parser") script = str(o.find_all("script")[0]) script_2 = script.replace("<script>", "").replace("</script>", "") with open("the_figure.js", "w") as file: file.write(script_2) with open("the_figure.html", "w") as file: the_html = the_html.replace( script, "<script src='.\\the_figure.js'></script>") file.write(the_html)
def testBrush(self): fig, ax = plt.subplots(3, 3, figsize=(6, 6)) fig.subplots_adjust(hspace=0.1, wspace=0.1) ax = ax[::-1] X = np.random.normal(size=(3, 100)) for i in range(3): for j in range(3): ax[i, j].xaxis.set_major_formatter(plt.NullFormatter()) ax[i, j].yaxis.set_major_formatter(plt.NullFormatter()) points = ax[i, j].scatter(X[j], X[i]) plugins.connect(fig, plugins.LinkedBrush(points)) mpld3.show()
def exploreSleepActivity(self): ''' assume each day have both data :param sleepf: :param activityf: :return: ''' fig, ax = plt.subplots(3, 3, figsize=(8, 8)) fig.suptitle("explore the sleep pattern and the activity level", fontsize=16) # fig.subplots_adjust(top=0.5, bottom=0.08, left=0.10, right=0.95, hspace=0.25, # wspace=0.25) ax = ax[::-1] sleep = self.sleep # awake, REM, light, deep acti = self.activity # -2, -1,0,1,2 allDic = {} for key in list(sleep.keys()): allDic[key] = [x for x in acti[key]] + sleep[key] # print(allDic.values()) lightDic = dict(sorted(allDic.items(), key=lambda d: d[1][0])) alldata = np.array(list(lightDic.values())) xlabel = [ "light activity duration", "fair activity duration", "very activity duration" ] ylabel = [ "REM duration", "light sleep duration", "deep sleep duration" ] # X = np.random.normal(size=(3, 100)) for i in range(3): for j in range(3): ax[i, j].xaxis.set_major_formatter(plt.NullFormatter()) ax[i, j].yaxis.set_major_formatter(plt.NullFormatter()) ax[i, j].set(xlabel=xlabel[i], ylabel=ylabel[j]) points = ax[i, j].scatter(alldata[:, i], alldata[:, 3 + j]) fig.tight_layout() plugins.connect(fig, plugins.LinkedBrush(points)) # mpld3.show() mpld3.save_html(fig, 'sleepvsactivity.html')
def show_tsne(): np_rep = np.array(reps) tenth = len(labels) // 10 X = np_rep[:tenth, :, :] tsne = TSNE(n_components=2, init='random') np_corr = np.array(corrects[:tenth]) mark_col = np.zeros_like(np_corr) mark_col[np_corr] = 1 np_lbls = np.array(labels[:tenth]) num_heads = X.shape[1] tX = np.zeros((tenth, num_heads, 2)) #dumb = np.arange(tenth, dtype=np.float)/tenth #dumb = dumb.reshape((-1,1)) fig, ax = plt.subplots(num_heads // 2, 6, figsize=(24, 12)) for i in range(num_heads): tX[:, i, :] = tsne.fit_transform(X[:, i, :]) #print(tX[:10,:]) tips = np_lbls.tolist() for i in range(num_heads): points = ax[i // 2, i % 2].scatter(tX[:, i, 0], tX[:, i, 1], c=mark_col, s=30, edgecolors='k', alpha=0.6) tooltip = plugins.PointLabelTooltip(points, labels=tips) plugins.connect(fig, tooltip) points = ax[i // 2, (i % 2) + 2].scatter(tX[:, i, 0], tX[:, (i + 1) % num_heads, 0], alpha=0) points = ax[i // 2, (i % 2) + 4].scatter(tX[:, i, 0], tX[:, (i + 2) % num_heads, 1], alpha=0) #for i, txt in enumerate(labels[:680]): # ax.annotate(txt, (tX[i,0], tX[i,1])) plugins.connect(fig, plugins.LinkedBrush(points)) #chart = json.dumps(mpld3.fig_to_dict(fig)) #ax.legend() mpld3.show() #return mpld3.fig_to_html(fig) return render_template('clusters.html', chart=chart)
def aei_plot(self, snp_plot=None, n_sufficient_hets=50, common_only=False): """ AEI plots in mpld3 """ x_scale = 1e6 size_maf = ((200 * self.maf) + 20) cm = plt.cm.get_cmap('winter') if type(snp_plot) == pd.Series or type(snp_plot) == list: suff_hets = pd.Series(snp_plot, index=pd.Index(snp_plot)) else: suff_hets = self.sufficient_hets[np.logical_and( self.sufficient_hets >= n_sufficient_hets, self.overall_counts.sum(axis=1) >= 500)] nplots = len(suff_hets) + 2 pos = self.meQTL.loc[:, 'pos'] pos = np.asarray(pos, dtype=np.uint64) / x_scale min_x = np.min(pos) max_x = np.max(pos) #range_x = max_x - min_x text_x = min_x fig, ax = plt.subplots(nrows=int(ceil(nplots / 2.0)), ncols=2, figsize=(24, 4 * nplots / 2), sharey=False, sharex=True, subplot_kw=dict(axisbg='#EEEEEE')) ko = 0 print(int(ceil(len(suff_hets) / 2.0))) for j in range(2): io = 0 for i in range(int(ceil(len(suff_hets) / 2.0))): if ko < len(suff_hets): curr = suff_hets.index[ko] adj_pvalue = -1 * np.log10(self.aei_pvalues.loc[:, curr]) scatter = ax[io, j].scatter(pos, adj_pvalue, s=30) ax[io, j].set_ylabel(r'-1*$log_{10}$ p-value', fontsize=15) ax[io, j].set_xlabel('Genomic Position (mb)', fontsize=15) ax[io, j].set_title( 'AEI plot for %s (N=%i)' % (curr, self.overall_counts.ix[suff_hets.index[ko], 'Nhets']), fontsize=25) # Need to make the text relative positioning #labels = list(self.annot_table.index) #tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=labels) ko += 1 io += 1 else: pass scatter = ax[-1, j].scatter(pos, -1 * np.log10(self.meQTL.ix[:, 'p-value']), c=self.ld, s=size_maf, cmap=cm) ax[-1, j].set_ylabel('-1*$log_{10}$ p-value', fontsize=15) ax[-1, j].set_xlabel('Genomic Position (mb)', fontsize=15) ax[-1, j].set_title('%s eQTL plot' % (self.gene_name, ), fontsize=25) labels = list(self.annot_table.index) tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=labels) mpld3.plugins.connect(fig, tooltip, plugins.LinkedBrush(scatter)) fig.tight_layout() return (fig)
def plot_page_inventory(df, columns, request, field=None, value=None): if request.method == 'POST': # Something is being submitted x = str(request.form['x']) y = str(request.form['y']) for requested_col in {x, y}: if requested_col not in columns: return redirect(url_for('sd')) else: x, y = 'date', 'inventory' if field and value is None: field = 'all fields' value = 'all values' nowtime = time.time() # current headers are: headers = list(df.columns.values) print('[Dimensions]: total ' + str(np.shape(df))) # print('[Dimensions]: lost & found ' + str(np.shape(df[(df.intake_type == "LOST&FOUND")]))) # print('[Dimensions]: dead and disposal intake ' + str(np.shape(df[(df.intake_type == "DEAD") | (df.intake_type == "Disposal") | (df.intake_subtype == "DEAD") | (df.intake_subtype == "DISPOSAL")])) ) # Filter out LOST&FOUND group and DEAD intake types df = df[(df.intake_type != "Disposal") & (df.outcome_type != "Disposal")] print('[Dimensions]: total after lost&found and dead removed ' + str(np.shape(df))) df = df[(df.animal_type == "Cat") | (df.animal_type == "Dog") | (df.animal_type == "Kitten") | (df.animal_type == "Puppy")] print('[Dimensions]: CATs DOGs KITTENs or PUPPPYs selected ' + str(np.shape(df))) df['outcome_datetime'] = df['outcome_datetime'].fillna( '2019-08-15 11:01:00') # df = df[(df.outcome_datetime != "") | (df.outcome_datetime.isnull())] print( '[Dimensions]: total after still in shelter on data end-date removed ' + str(np.shape(df))) print("[INFO] Filtered out Dead Intakes and Lost and Found Animals.") catdf = df[(df.animal_type == "Cat")] kittendf = df[(df.animal_type == "Kitten")] dogdf = df[(df.animal_type == "Dog")] puppydf = df[(df.animal_type == "Puppy")] felinedf = df[(df.animal_type == "Cat") | (df.animal_type == "Kitten")] caninedf = df[(df.animal_type == "Dog") | (df.animal_type == "Puppy")] dogmaxdate = dogdf['datetime'].max() dogmindate = dogdf['outcome_datetime'].min() daterange = pd.date_range(start=dogmindate, end=dogmaxdate) print("[INFO] Filtered by animal_type.") lasttime = nowtime nowtime = time.time() deltatime = nowtime - lasttime print("[TIMING] data loaded in {} seconds.".format(deltatime)) # inv = [len(getdailyinventory(str(day), df)) for day in daterange ] invcat = [getdailyinventory(str(day), catdf) for day in daterange] invkitten = [getdailyinventory(str(day), kittendf) for day in daterange] invdog = [getdailyinventory(str(day), dogdf) for day in daterange] invpuppy = [getdailyinventory(str(day), puppydf) for day in daterange] # invfeline = [len(getdailyinventory(str(day), felinedf)) for day in daterange ] # invcanine = [len(getdailyinventory(str(day), caninedf)) for day in daterange ] #print dfinvcat['inventory'].values # tsinv = pd.Series(inv, index = daterange) tsinvcat = pd.Series(invcat, index=daterange) tsinvkitten = pd.Series(invkitten, index=daterange) tsinvdog = pd.Series(invdog, index=daterange) tsinvpuppy = pd.Series(invpuppy, index=daterange) # tsinvfeline = pd.Series(invfeline, index = daterange) # tsinvcanine = pd.Series(invcanine, index = daterange) # print dimensions of our pandas dataframe # print( np.shape(df) ) # print('\nCat Inventory: ' + str(np.shape(tsinvcat)) ) # print( '\nKitten Invenory: ' + str(np.shape(tsinvkitten)) ) # print( '\nDog Inventory: ' + str(np.shape(tsinvdog)) ) # print( '\nPuppy Inventory: ' + str(np.shape(tsinvpuppy)) ) # print( '\nFeline Inventory: ' + str(np.shape(tsinvfeline))+ "\n" ) # print( '\nCanine Inventory: ' + str(np.shape(tsinvcanine))+ "\n" ) # # Does not work with NaN values! # tsinvcat = tsinvcat.loc[:, {x, y}].dropna(axis=0) # tsinvcdog = tsinvdog.loc[:, {x, y}].dropna(axis=0) # tsinvkitten = tsinvkitten.loc[:, {x, y}].dropna(axis=0) # tsinvpuppy = tsinvpuppy.loc[:, {x, y}].dropna(axis=0) # print(tsinvcat.index) # print(tsinvcat.columns) # print(df.head()) fig, ax = plt.subplots(2, 2, figsize=(10, 6), sharex='col', sharey='row') points = ax[0, 0].plot_date(tsinvcat.index, tsinvcat.values, 'bo-') points = ax[1, 0].plot_date(tsinvdog.index, tsinvdog.values, 'ro-') points = ax[0, 1].plot_date(tsinvkitten.index, tsinvkitten.values, 'go-') points = ax[1, 1].plot_date(tsinvpuppy.index, tsinvpuppy.values, 'yo-') ax[1, 0].set_xlabel(x) ax[1, 0].set_ylabel('dog ' + y) ax[1, 0].set_title('Daily Inventory for {} of {}'.format(field, value)) ax[1, 0].grid(color='black', linestyle='-', linewidth=2) ax[1, 1].set_xlabel(x) ax[1, 1].set_ylabel('puppy ' + y) ax[1, 1].set_title('Daily Inventory for {} of {}'.format(field, value)) ax[1, 1].grid(color='black', linestyle='-', linewidth=2) ax[0, 0].set_ylabel('cat ' + y) ax[0, 0].set_xlabel(x) ax[0, 0].set_title('Daily Inventory for {} of {}'.format(field, value)) ax[0, 0].grid(color='black', linestyle='-', linewidth=2) ax[0, 1].set_ylabel('kitten ' + y) ax[0, 1].set_xlabel(x) ax[0, 1].set_title('Daily Inventory for {} of {}'.format(field, value)) ax[0, 1].grid(color='black', linestyle='-', linewidth=2) fig.autofmt_xdate() plugins.connect(fig, plugins.LinkedBrush(points)) plot = fig_to_html(fig) return render_template('plot_inventory.html', plot=plot, columns=columns, x=x, y=y)
import mpld3 from mpld3 import plugins, utils data = load_iris() X = data.data y = data.target # dither the data for clearer plotting X += 0.1 * np.random.random(X.shape) fig, ax = plt.subplots(4, 4, sharex="col", sharey="row", figsize=(8, 8)) fig.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=0.95, hspace=0.1, wspace=0.1) for i in range(4): for j in range(4): points = ax[3 - i, j].scatter(X[:, j], X[:, i], c=y, s=40, alpha=0.6) # remove tick labels for axi in ax.flat: for axis in [axi.xaxis, axi.yaxis]: axis.set_major_formatter(plt.NullFormatter()) # Here we connect the linked brush plugin plugins.connect(fig, plugins.LinkedBrush(points)) mpld3.show()
def exploreSleepPro(self): ''' assume each day have both data :param sleepf: :param activityf: :return: ''' sleep = self.sleep # awake, REM, light, deep pro = self.desk # light, fair, very allDic = {} for key in list(sleep.keys()): allDic[key] = [x for x in pro[key]] + [sum(x for x in pro[key]) ] + sleep[key] # print(allDic.values()) lightDic = dict(sorted(allDic.items(), key=lambda d: d[1][0])) alldata = np.array(list(lightDic.values())) fig, ax = plt.subplots(3, 3, figsize=(8, 8)) ax = ax[::-1] xlabel = [ "not productive duration", "neutural duration", "productive duration" ] ylabel = [ "REM duration", "light sleep duration", "deep sleep duration" ] # X = np.random.normal(size=(3, 100)) for i in range(3): for j in range(3): ax[i, j].xaxis.set_major_formatter(plt.NullFormatter()) # ax[i, j].yaxis.set_major_formatter(plt.NullFormatter()) ax[i, j].set(xlabel=xlabel[i], ylabel=ylabel[j]) if i != 1: points = ax[i, j].scatter( alldata[:, i * 2] + alldata[:, i * 2 + 1], alldata[:, 7 + j], ) else: points = ax[i, j].scatter( alldata[:, i * 2], alldata[:, 7 + j], ) # points = ax[0, 0].scatter(alldata[:, 0] + alldata[:, 1], alldata[:, 7],) # points = ax[0, 1].scatter(alldata[:, 0] + alldata[:, 1], alldata[:, 8], ) # points = ax[0, 2].scatter(alldata[:, 0] + alldata[:, 1], alldata[:, 9], ) # lightDic = dict(sorted(allDic.items(), key=lambda d: d[1][2])) # # alldata = np.array(list(lightDic.values())) # points = ax[1, 0].scatter(alldata[:, 2], alldata[:, 7], ) # points = ax[1, 1].scatter(alldata[:, 2], alldata[:, 8], ) # points = ax[1, 2].scatter(alldata[:, 2], alldata[:, 9], ) # lightDic = dict(sorted(allDic.items(), key=lambda d: d[1][4])) # alldata = np.array(list(lightDic.values())) # points = ax[2, 0].scatter(alldata[:, 4] + alldata[:, 5], alldata[:, 7], ) # points = ax[2, 1].scatter(alldata[:, 4] + alldata[:, 5], alldata[:, 8], ) # points = ax[2, 2].scatter(alldata[:, 4] + alldata[:, 5], alldata[:, 9], ) plugins.connect(fig, plugins.LinkedBrush(points)) # mpld3.show() mpld3.save_html(fig, 'sleepvspro.html')
def MapInteractivePlot(fig, s, h, dh, lat, lon, zoom_level, margin_percentage, use_proxy, proxy_data, verbose): fig.subplots_adjust(hspace=0.1, wspace=0.1) gs = gridspec.GridSpec(1, 3, width_ratios=[5, 0.001, 5]) ax0 = plt.subplot(gs[0]) ax1 = plt.subplot(gs[1]) ax2 = plt.subplot(gs[2]) X = np.vstack((s, h[0:-1], lon[0:-1], lat[0:-1])) # Elevation over distance points = ax0.plot(X[0], X[1], color='0.5') points = ax0.scatter(X[0], X[1], s=4) ax0.set_ylabel("Elevation (m)") ax0.set_xlabel("Distance (m)") ax0.grid(True) ax0.set_xlim(np.min(s), np.max(s)) ax0.set_ylim(0, np.max(h) + 100) # Total ascent/descent #at = AnchoredText("Total ascent. %dm\nTotal descent: %dm" % (TotalAscentDescent(dh_filtered, 1), TotalAscentDescent(dh_filtered, -1)), # prop=dict(size=12), frameon=True, # loc=2, # ) #at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2") #ax1.add_artist(at) # Fake subplot points = ax1.scatter(X[0], X[2]) ax1.xaxis.set_major_formatter(plt.NullFormatter()) ax1.yaxis.set_major_formatter(plt.NullFormatter()) # Map with route margin = np.max((np.max(lat) - np.min(lat), np.max(lon) - np.min(lon))) * margin_percentage lat_origin = np.min(lat) - margin lon_origin = np.min(lon) - margin lat_span = np.max(lat) - np.min(lat) + 2 * margin lon_span = np.max(lon) - np.min(lon) + 2 * margin a, tiles_edges_coords = GetMapImageCluster(use_proxy, proxy_data, lat_origin, lon_origin, lat_span, lon_span, zoom_level, verbose) fig.patch.set_facecolor('white') points = ax2.plot(X[2], X[3], color='0.5') img = np.asarray(a) # Extent simply associates values, in this case longitude and latitude, to # the map's corners. ax2.imshow(img, extent=[ tiles_edges_coords[2], tiles_edges_coords[3], tiles_edges_coords[0], tiles_edges_coords[1] ], zorder=0, origin="lower") points = ax2.scatter(X[2], X[3], s=4) ax2.set_xlim(lon_origin, lon_origin + lon_span) ax2.set_ylim(lat_origin, lat_origin + lat_span) ax2.set_xlabel("Lat") ax2.set_ylabel("Lon") ax2.grid(True) plugins.connect(fig, plugins.LinkedBrush(points)) mpld3.show() return fig