2

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.

4

2 回答 2

0

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")   
于 2020-06-27T06:04:19.627 回答
0

I think my problem is similar with yours. Mine is enlarging an image area selected by ginput using my own method.

This is my solution using plt.ion and plt.draw, and works fine in my script. The image super resolution method is deleted.

#!/usr/bin/env python
import matplotlib.pyplot as plt
import numpy as np

import argparse
import sys

parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument(
    "-i", "--image_name", type=str, default="test.jpg", help="Input image path"
)
args = parser.parse_known_args(sys.argv[1:])[0]

plt.ion()  # works in `.py` scripts
imm = plt.imread(args.image_name)
fig = plt.figure()
plt.imshow(imm)
plt.tight_layout()
plt.show()

imms = [imm]
while True:
    aa = plt.ginput(2, timeout=-1)
    aa = np.array(aa)

    left, right = int(aa[:, 0].min()), int(aa[:, 0].max())
    top, bottom = int(aa[:, 1].min()), int(aa[:, 1].max())

    if right - left < 1 or bottom - top < 1:  # Double click to return
        if len(imms) > 1:
            imms.pop(-1)
        else:
            break
    else:
        sub_image = imms[-1][top:bottom, left:right, :]
        imms.append(sub_image)
    plt.imshow(imms[-1])
    plt.draw()  # works in `ipython` environment

In my tests:

  • Adding plt.ion without the last plt.draw still works in a .py script.
  • Adding the last plt.draw without plt.ion works in ipython environment.
于 2021-03-08T03:56:40.267 回答