Используя matplotlib, как обновить часть фигуры с помощью ползунков? - PullRequest
0 голосов
/ 11 апреля 2019

Мне нужно взаимодействовать со следующей фигурой.Я хочу добавить два ползунка, чтобы изменить положение (x, y) красной точки на следующем рисунке.Штриховая линия и круг также должны быть изменены действием красной точки, в то время как синяя точка должна оставаться там.

TOF Я нашел несколько демонстраций ползунков под matplotlib, в то время как все они обновили кривую фигуры.Моя фигура немного сложнее, чем они, я не знаю, как обновить ее части.

import numpy as np
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import rcParams
from matplotlib.widgets import Slider

fig, ax = plt.subplots()
ax.axis([-5,15,-5,15])
ax.set_aspect(1) # x y轴等比例显示

anchorNum = 4
anchorX = [0,10,0,10]
anchorY = [0,0,10,10]
anchorName = ['A0', 'A1', 'A2', 'A3']
colorArray = ['blue', 'green', 'magenta', 'green'] 

ax.scatter(anchorX, anchorY, s=200) # plot stable blue point

for i, txt in enumerate(anchorName):
    ax.annotate(txt, (anchorX[i], anchorY[i]), fontsize = 20)

initTagX = np.random.random_sample()*10
initTagY = np.random.random_sample()*10

tagPos = [initTagX, initTagY]

ax.scatter(tagPos[0], tagPos[1], c='red', s=300) # plot the red point 

# plot the dash line
for i in range(anchorNum):
    anchorPos = (anchorX[i], anchorY[i])
    diffVector = [(tagPos[0] - anchorX[i]), (tagPos[1] - anchorY[i])]
    dist = np.linalg.norm(diffVector,ord = 2) # 计算二阶范数 平方和开根号
    circle = plt.Circle(anchorPos, dist, color = colorArray[i], fill = False, linestyle='--', linewidth=4)
    ax.add_artist(circle)
    ax.plot([anchorX[i], tagPos[0]], [anchorY[i], tagPos[1]], linestyle = '--',  color = colorArray[i], linewidth=4)

plt.show()

1 Ответ

1 голос
/ 11 апреля 2019

Единственная разница между вашей фигурой и примерами, которые вы, возможно, видели, заключается в том, что вам нужно обновлять сразу несколько вещей при смене ползунков.

При изменении положения x или y необходимо обновить положение x или y красной точки, радиус 4 окружностей и положение 4 пунктирных линий.

Код ниже делает все это.Когда ползунки перемещаются, вызывается либо update_rp_x, либо update_rp_y.Это, в свою очередь, вызвало функцию update_plot с обновленными координатами, а затем переместило все соответствующие элементы графика вокруг.Для красной точки я переключился с использования ax.scatter на ax.plot, потому что немного проще обновить его положение (например, rp.set_xdata()).При первом построении линии и круги сохраняются в списках, поэтому, когда мы обновляем их, мы можем просто зацикливать эти списки и обновлять каждый по очереди.Кружкам просто нужно изменить их радиус, что мы можем сделать с Circle.set_radius, а линии снова с set_xdata и set_ydata.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider

fig, ax = plt.subplots()
ax.axis([-5,15,-5,15])
ax.set_aspect(1) # x y

# Make room at the bottom for sliders
fig.subplots_adjust(bottom=0.3)

# Initial tag location
initTagX = np.random.random_sample()*10
initTagY = np.random.random_sample()*10
tagPos = [initTagX, initTagY]

# Set up the anchors
anchorNum = 4
anchorX = [0,10,0,10]
anchorY = [0,0,10,10]
anchorName = ['A0', 'A1', 'A2', 'A3']
colorArray = ['blue', 'green', 'magenta', 'green'] 

# Plot the anchors
ax.scatter(anchorX, anchorY, s=100) # plot stable blue point

# Label the anchors
for i, txt in enumerate(anchorName):
    ax.annotate(txt, (anchorX[i], anchorY[i]), fontsize = 10)

# Plot initial location of red point
rp, = ax.plot(tagPos[0], tagPos[1], c='red', marker='o', ms=10) # plot the red point 

# Store circles and lines for update later
circles = []
lines = []

# Plot initial circles
for i in range(anchorNum):
    anchorPos = (anchorX[i], anchorY[i])
    diffVector = [(tagPos[0] - anchorX[i]), (tagPos[1] - anchorY[i])]
    dist = np.linalg.norm(diffVector,ord = 2) 
    circle = plt.Circle(anchorPos, dist, color = colorArray[i], fill = False, linestyle='--', linewidth=2)
    circles.append(ax.add_artist(circle))
    lines.append(ax.plot([anchorX[i], tagPos[0]], [anchorY[i], tagPos[1]], linestyle = '--',
        color = colorArray[i], linewidth=2)[0])

def update_plot(xpos, ypos):
    ''' 
    This function updates the radius of the circles
    and the position of the dashed lines
    '''

    # Update the tag position
    tagPos = [xpos, ypos]
    rp.set_xdata(xpos)
    rp.set_ydata(ypos)

    for i in range(anchorNum):
        anchorPos = (anchorX[i], anchorY[i])
        diffVector = [(tagPos[0] - anchorX[i]), (tagPos[1] - anchorY[i])]
        dist = np.linalg.norm(diffVector,ord = 2)

        # Now we actually update the circles and dashed lines
        circles[i].set_radius(dist)
        lines[i].set_xdata([anchorX[i], tagPos[0]])
        lines[i].set_ydata([anchorY[i], tagPos[1]])

    return tagPos

def update_rp_x(xpos):
    ''' This function updates the x position of the red point '''
    global tagPos
    tagPos = update_plot(xpos, tagPos[1])
    fig.canvas.draw_idle()

def update_rp_y(ypos):
    ''' This function updates the y position of the red point '''
    global tagPos
    tagPos = update_plot(tagPos[0], ypos)
    fig.canvas.draw_idle() 

# Create Axes for the sliders
axcolor = '#909090'
sax_x = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor=axcolor)
sax_y = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor=axcolor)

# Create sliders
sx = Slider(sax_x, 'x position', -5, 15, valinit=initTagX)
sy = Slider(sax_y, 'y position', -5, 15, valinit=initTagY)

# Tell sliders which function to call when changed
sx.on_changed(update_rp_x)
sy.on_changed(update_rp_y)

plt.show()

enter image description here enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...