如何在鼠标移动时动态更改图形的颜色?

时间:2017-04-11 19:49:42

标签: python dynamic graph colors interactive

我有一个条形图。我希望它能在我上下移动光标时改变颜色(所以基于y值)。我可以制作一个离散的颜色值列表,并在每次点击时更新图表。但我仍然不知道如何使它连续运动。

import matplotlib.pyplot as plt
from math import floor

def hex_to_RGB(hex):


# Pass 16 to the integer function for change of base
    return [int(hex[i:i + 2], 16) for i in range(1, 6, 2)]


def RGB_to_hex(RGB):
    # Components need to be integers for hex to make sense
    RGB = [int(x) for x in RGB]
    return "#" + "".join(["0{0:x}".format(v) if v < 16 else
                          "{0:x}".format(v) for v in RGB])


def color_dict(gradient):
    return {"hex": [RGB_to_hex(RGB) for RGB in gradient],
            "r": [RGB[0] for RGB in gradient],
            "g": [RGB[1] for RGB in gradient],
            "b": [RGB[2] for RGB in gradient]}


def linear_gradient(start_hex, finish_hex="#FFFFFF", n = 100):
    # Starting and ending colors in RGB form
    s = hex_to_RGB(start_hex)
    f = hex_to_RGB(finish_hex)
    # Initilize a list of the output colors with the starting color
    RGB_list = [s]
    # Calcuate a color at each evenly spaced value of t from 1 to n
    for t in range(1, n):
        # Interpolate RGB vector for color at the current value of t
        curr_vector = [
            int(s[j] + (float(t) / (n - 1)) * (f[j] - s[j]))
            for j in range(3)]
        # Add it to our list of output colors
        RGB_list.append(curr_vector)

    return color_dict(RGB_list)

WtoR = linear_gradient('#FFFFFF', '#FF0000')['hex']
# -------------------------------- PLOTTING -----------------------------------------

width = 1

plt.figure()

plt.bar(1, 100, width, color = 'white', align = 'center')

def onclick(event):
    plt.cla()
    plt.clf()
    y = event.ydata
    plt.bar(1, 100, width, color = str(WtoR[floor(y)]), align = 'center')
    plt.draw()
plt.gcf().canvas.mpl_connect('button_press_event', onclick)

plt.show()

1 个答案:

答案 0 :(得分:1)

TL/DR; change your onclick code to:

def onmotion(event):
    plt.cla()
    plt.clf()
    plt.gca()
    y = event.ydata
    if y:
        plt.bar(1, 100, width, color = str(WtoR[int(y)]), align = 'center')
        plt.draw()
plt.gcf().canvas.mpl_connect('motion_notify_event', onmotion)

You have registered your onclick function to be called whenever you get receive a button press event. To have it update as soon as the mouse is moved you should listen to the motion notify event.

However, with this event, you are not certain to get a y value (if you are not within the axes of the figure), therefore you have to update only conditionally when you have a y value.

Further, when leaving the window, it seems the axes are deactivated to matplotlib. This means that they have to be reactivated by a plt.gca() call.

And as a note, for me in python 2.7 it did not work to index the array with the value from the floor() function. I had to use int() instead, but this may work differently in python 3.

Also, right now, the bar plot is redrawn every time the callback is called. It might be worthwhile looking into the possibility to get the id the of the first bar and then update the color only. This could be quicker, as it may require less from the computer.