1

I'm trying to be able to move a dot around the matplotlib plot using the w, a, s, and d keys without having to hit enter each time after I type the letter. This works using readchar.readchar(), but then the plot does not show up. What am I doing wrong?

""" Moving dot """
import matplotlib.pyplot as plt
import time
import readchar

x = 0
y = 0
q = 0
e = 0
counter = 0
while 1 :
    #arrow_key = input()
    arrow_key = readchar.readchar()
    print(x,y)
    if arrow_key == "d" :
        q = x + 1
    elif arrow_key == "a" :
        q = x - 1
    elif arrow_key == "w" :
        e = y + 1
    elif arrow_key == "s" :
        e = y - 1
    plt.ion()   
    plt.plot(x,y, "wo", markersize = 10)
    plt.plot(q,e, "bo")
    plt.xlim(-10,10)
    plt.ylim(-10,10)
    x = q
    y = e

1 Answers1

1

The first problem in your code is that the readchar.readchar() returns binary strings. You need to decode it to utf-8: arrow_key = readchar.readchar().lower().decode("utf-8")

I'd say it's best that you do the plt.xlim() and plt.ylim() limitations before the while loop.

My plt froze if I wasn't using plt.pause(). I added multiple plt.pause(0.0001) to get the code working. reference: Matplotlib ion() function fails to be interactive

Also, you required user input in your code before showing the plot. I changed it to the plot showing before user input.

Changing x to be q and y to be e is best done before input. It being after the input caused the previous plots to show for me.

EDIT: as FriendFX suggested below, it's good to define the plots as variables (pl1 = plt.plot(x,y, "wo", markersize = 10) and pl2 = plt.plot(q,e, "bo")) and delete them after use to not fill the memory. pl1.pop(0).remove() and pl2.pop(0).remove()

Full repaired code below. Note that in startup you may lose terminal window focus, which is critical for the input.

import matplotlib.pyplot as plt
import time # you didn't use this, do you need it?
import readchar

x = 0
y = 0
q = 0
e = 0
plt.xlim(-10,10)
plt.ylim(-10,10)

counter = 0 # you didn't use this, do you need it?
while(1):
    plt.ion()
    plt.pause(0.0001)
    pl1 = plt.plot(x,y, "wo", markersize = 10)
    pl2 = plt.plot(q,e, "bo")
    plt.pause(0.0001)
    plt.draw()
    plt.pause(0.0001)
    x = q
    y = e

    arrow_key = readchar.readchar().lower().decode("utf-8")
    print(arrow_key)

    if arrow_key == "d" :
        q = x + 1
    elif arrow_key == "a" :
        q = x - 1
    elif arrow_key == "w" :
        e = y + 1
    elif arrow_key == 's' :
        e = y - 1
    print(q, e, x, y)
    pl1.pop(0).remove()
    pl2.pop(0).remove()
jolammi
  • 492
  • 3
  • 16
  • Nice one. Depending on what the OP needs, it may also be helpful to delete existing plot points with `lines.pop(0).remove()` as stated in [this answer](https://stackoverflow.com/a/4981918/897968), where `lines` is a variable storing the output of one (or both) of the `plt.plot()` calls, e.g. `line = plot.plot(q,e, "bo")`. Also, I don't think the `show()` call is required in the loop. – FriendFX Aug 30 '19 at 05:37
  • @FriendFX You're right. Added your suggestions and deleted the `plt.show()` – jolammi Aug 30 '19 at 06:14