1

I have a two panel wxPython GUI set up. In my right panel, I have a map display using Basemap. On this basemap (of the United States) I plot a scatter plot of different cities. I would like to be able to click on these dots and have a pop up window within my GUI that gives some information relative to that dot I select (ex. City, lat/long, etc. -- I would have all this info stored in a list or other means).

I have come across AnnoteFinder, but this does not seem to work inside my GUI (it will work if i use Basemap by itelf and not in my 2 panel GUI). Also, this just puts some text on top of the dot -- I would rather have a small window show up.

Example of my code so far:

#Setting up Map Figure
self.figure = Figure(None,dpi=75)
self.canvas = FigureCanvas(self.PlotPanel, -1, self.figure)
self.axes = self.figure.add_axes([0,0,1,1],frameon=False)
self.SetColor( (255,255,255) )

#Basemap Setup
self.map = Basemap(llcrnrlon=-119, llcrnrlat=22, urcrnrlon=-64,
                    urcrnrlat=49, projection='lcc', lat_1=33, lat_2=45,
                    lon_0=-95, resolution='h', area_thresh=10000,ax=self.axes)
self.map.drawcoastlines()
self.map.drawcountries()
self.map.drawstates()
self.figure.canvas.draw()

#Set up Scatter Plot
m = Basemap(llcrnrlon=-119, llcrnrlat=22, urcrnrlon=-64,
            urcrnrlat=49, projection='lcc', lat_1=33, lat_2=45,
            lon_0=-95, resolution='h', area_thresh=10000,ax=self.axes)

x,y=m(Long,Lat)

#Scatter Plot (they plot the same thing)
self.map.plot(x,y,'ro')
self.map.scatter(x,y,90)

self.figure.canvas.draw()

Any thoughts?

bmu
  • 35,119
  • 13
  • 91
  • 108
mcfly
  • 1,151
  • 4
  • 33
  • 55

1 Answers1

3

Check out this answer. Basically you set up a pick event that creates an annotation on the graph. This annotation can pop up as a tooltip-style text box.

Note that this doesn't produce a real GUI "window" (i.e., a dialog box or other control with close button, title bar, etc.), but just an annotation on the plot itself. However, from looking at the code you can see how it determines the artist (e.g., point) you've clicked on. Once you have that info, you could run whatever code you want with it, for instance creating a wxPython dialog instead of an annotation.

Edit re your question about the last few lines: Based on your code, it looks like you'd want to do:

pts = self.map.scatter(x, y, 90)
self.figure.canvas.mpl_connect('pick_event', DataCursor(plt.gca()))
pts.set_picker(5)

Another edit re your question about having different text in the annotation: You may have to play around with the event object a bit to extract the information you want. As described at http://matplotlib.sourceforge.net/users/event_handling.html#simple-picking-example , different artist types (i.e., different kinds of plots) will provide different event information.

I have some old code that does almost exactly what you described (displaying city name when a point on the map is clicked). I have to admit I don't remember exactly how all of it works, but my code has this in the DataCursor:

def __call__(self, event):
    self.event = event
    xdata, ydata = event.artist._offsets[:,0], event.artist._offsets[:,1]
    #self.x, self.y = xdata[event.ind], ydata[event.ind]
    self.x, self.y = event.mouseevent.xdata, event.mouseevent.ydata
    if self.x is not None:
        city = clim['Name'][event.ind[0]]
        if city == self.annotation.get_text() and self.annotation.get_visible():
            # You can click the visible annotation to remove it
            self.annotation.set_visible(False)
            event.canvas.draw()
            return
        self.annotation.xy = self.x, self.y
        self.annotation.set_text(city)
        self.annotation.set_visible(True)
        event.canvas.draw()

clim['Name'] is the list of city names, and I was able to index into that using event.ind to get the city name corresponding to the picked point. Your code may need to be slightly different depending on the format of your data, but that should give you an idea.

Community
  • 1
  • 1
BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • can u assist with the last four lines of the other code and how i would work it into my code above? i cant seem to figure that out. thanks! – mcfly Jun 22 '12 at 22:23
  • Great! I got this to work. However, is there a way to have the annotations be something other than the given x,y? For instance, for each (x,y) scatter point, I have an associated 'city name' that I would rather display than the (x,y) value. I see where it gets self.x and self.y, do i add a self.z? What's the appropriate way to approach this? Thanks! – mcfly Jun 25 '12 at 13:29