Search code examples
pythonpython-3.xmatplotlibginput

pyplot figure only updating after second call to ginput()


I have a method that uses matplotlib.pyplot.ginput() to collect a single click's location from axes, and then place an image at that location within an existing underlaid array of axes in the same figure.

The visual only updates after a second call to ginput(), meaning that its response is lagged compared to the user's clicks, and only as they are choosing the next location does the image they've just placed show. This is problematic because the random image that gets placed may influence where they want to click next.

The calling method looks something like the below, although here axes are drawn rather than images being added:

%matplotlib
from matplotlib import pyplot
import numpy
import random

dimensions = [10,10]

visual_width = 1366
visual_height = 768
print("Established screen dimensions as "+str(visual_width)+","+str(visual_height))
         
fig, axarr = pyplot.subplots(dimensions[1],dimensions[0]
                               , num="Live game visualised"
                            , figsize=(visual_width, visual_height)
                            , clear=True)
fig.set_size_inches(visual_width, visual_height, forward=False)
overax = fig.add_subplot(111)
overax.axis("off")
#remove axes for initial rendering
for horizontal in range(0, dimensions[0]):
    for vertical in range(0, dimensions[1]):
        axarr[vertical, horizontal].axis('off')
text = fig.text(0,0, "", va="bottom", ha="left")

# test repeated interactions with figure, through successively adding tiles to the play area
playing = True
while playing:
    click = pyplot.ginput()
    if not click:
        break
    
    horizontal = int(click[0][0]*dimensions[0])
    vertical = dimensions[1] - int(click[0][1]*dimensions[1])
    print(str(horizontal)+","+str(vertical))
    text.set_text(str(horizontal)+","+str(vertical))
    axarr[vertical-1, horizontal].axis("on")

My python 3 script is in jupyter notebook, but I'm popping the visuals out with the default %matplotlib backend. I'm working in Chrome on Ubuntu.


Solution

  • It's a hacky and unsatisfactory solution, but my workaround is to prompt a double click, and accept that the first call to ginput is the data that will be stored to the variable assigned to the second call:

    %matplotlib
    from matplotlib import pyplot
    import numpy
    import random
    
    dimensions = [10,10]
    
    visual_width = 1366
    visual_height = 768
    print("Established screen dimensions as "+str(visual_width)+","+str(visual_height))
             
    fig, axarr = pyplot.subplots(dimensions[1],dimensions[0]
                                   , num="Live game visualised"
                                , figsize=(visual_width, visual_height)
                                , clear=True)
    fig.set_size_inches(visual_width, visual_height, forward=False)
    overax = fig.add_subplot(111)
    overax.axis("off")
    #remove axes for initial rendering
    for horizontal in range(0, dimensions[0]):
        for vertical in range(0, dimensions[1]):
            axarr[vertical, horizontal].axis('off')
    text = fig.text(0,0, "", va="bottom", ha="left")
    
    # test repeated interactions with figure, through successively adding tiles to the play area
    playing = True
    while playing:
        pyplot.ginput()
        click = pyplot.ginput()
        if not click:
            break
        
        horizontal = int(click[0][0]*dimensions[0])
        vertical = dimensions[1] - int(click[0][1]*dimensions[1])
        print(str(horizontal)+","+str(vertical))
        text.set_text(str(horizontal)+","+str(vertical))
        axarr[vertical-1, horizontal].axis("on")
        
        text.set_text("Double click to make your next move")