[英]change color of a pie chart when hovering mouse over it
I have just created a pie chart by Tkinter in Python as follows: 我刚刚在Python中用Tkinter创建了一个饼图,如下所示:
def frac(n):
return 360. * n / 500
import Tkinter
c = Tkinter.Canvas(width=100, height=100); c.pack()
c.create_arc((2,2,98,98), fill="red", start=frac(0), extent =
frac(100))
c.create_arc((2,2,98,98), fill="blue", start=frac(100), extent = frac(400))
c.create_arc((2,2,98,98), fill="white", start=frac(400), extent = frac(100), width=0)
c.mainloop()
This is the result: 这是结果:
Now, I want to change the color of each slice when hovering the mouse over it. 现在,我希望在将鼠标悬停在每个切片上时更改每个切片的颜色。 How can I do that? 我怎样才能做到这一点? Many thanks 非常感谢
So, my code is a mess, but I hope it will help you get started and get the basic ideas. 所以,我的代码很乱,但我希望它能帮助你开始并获得基本的想法。
The first idea is that you need to bind the <Motion>
mouse event to the c
canvas. 第一个想法是您需要将<Motion>
鼠标事件绑定到c
画布。 The bind
method takes two arguments: an event, which says when to do something, and a function, which says what to do. bind
方法有两个参数:一个事件,它说什么时候做什么,一个函数,它说明要做什么。 I chose to define a redraw_chart
function, that draws the pie according to the position of the mouse. 我选择定义一个redraw_chart
函数,它根据鼠标的位置绘制饼图。 This function is what will be called on a <Motion>
event, so I bind as follows: 这个函数将在<Motion>
事件中调用,所以我绑定如下:
c.bind('<Motion>', lambda e: redraw_chart(e.x, e.y))
The lambda
function is just an anonymous function, that receives the event raised, and passes the two coordinates of the event (that is, the coordinates of the mouse) to the redraw_chart
. lambda
函数只是一个匿名函数,它接收引发的事件,并将事件的两个坐标(即鼠标的坐标)传递给redraw_chart
。
The redraw_chart
function is really dumb: it draws the pie according to the coordinates it received: redraw_chart
函数非常愚蠢:它根据收到的坐标绘制饼图:
def redraw_chart(x, y):
global redCode, blueCode, whiteCode
arc = get_arc(x, y)
if arc == "red":
c.itemconfig(redCode, fill="green")
c.itemconfig(redCode, fill="blue")
c.itemconfig(redCode, fill="white")
elif arc == "blue":
c.itemconfig(redCode, fill="red")
c.itemconfig(redCode, fill="green")
c.itemconfig(redCode, fill="white")
elif arc == "white":
c.itemconfig(redCode, fill="red")
c.itemconfig(redCode, fill="blue")
c.itemconfig(redCode, fill="green")
else:
c.itemconfig(redCode, fill="green")
c.itemconfig(redCode, fill="blue")
c.itemconfig(redCode, fill="white")
Now, what are redCode
, blueCode
and whiteCode
? 现在, redCode
, blueCode
和whiteCode
什么? They are the addresses of the three arc objects created by the c.create_arc
method. 它们是c.create_arc
方法创建的三个弧对象的地址。 They are useful to modify the arcs, so as to avoid creating new ones. 它们对修改弧非常有用,以避免创建新的弧。 There is still one thing left to define: the get_arc
function. 还有一件事要定义: get_arc
函数。
The get_arc
function takes a (x, y)
couple, representing a point of the canvas, and returns the corresponding arc: get_arc
函数采用(x, y)
对,表示画布的一个点,并返回相应的弧:
def get_arc(x, y):
if is_in_arc(x, y, redArc[0], redArc[0]+redArc[1]):
return "red"
elif is_in_arc(x, y, blueArc[0], blueArc[0]+blueArc[1]):
return "blue"
elif is_in_arc(x, y, whiteArc[0], whiteArc[0]+whiteArc[1]):
return "white"
else:
return None
It relies on the is_in_arc
function, that takes a point, a portion of the pie, and tells if the point lies in the portion. 它依赖于is_in_arc
函数,它接受一个点,一部分饼,并告诉该点是否位于该部分中。
def is_in_arc(x, y, angle0, angle1):
if (x-50)**2 + (y-50)**2 > 48**2:
return False
theta = - np.arctan2(y-50, x-50)
return angle0 <= frac(theta) <= angle1
The np.arctan2
function from numpy
returns the angle in radians corresponding to the (x, y)
point. 来自numpy
的np.arctan2
函数返回对应于(x, y)
点的弧度角度。 Then, the fract
method returns the corresponding value in degrees. 然后, fract
方法以度为单位返回相应的值。 I modified it, because I did not really understand yours: 我修改了它,因为我真的不了解你的:
def frac(n):
if n < 0:
n += 2*np.pi
return 360 * n / (2*np.pi)
So here is what it looks like. 所以这就是它的样子。 You cannot see the cursor one the screenshot, but I guarantee you that the parts turn green when hovered. 您无法在屏幕截图中看到光标,但我保证在悬停时部件会变为绿色。
Here is the complete code: 这是完整的代码:
import tkinter as tk
import numpy as np
def frac(n):
if n < 0:
n += 2*np.pi
return 360 * n / (2*np.pi)
c = tk.Canvas(width=100, height=100)
c.pack()
redArc = (frac(0), frac(np.pi/3))
blueArc = (frac(np.pi/3), frac(4*np.pi/3))
whiteArc = (frac(5*np.pi/3), frac(np.pi/3))
redCode = c.create_arc((2,2,98,98), fill="red", start=redArc[0], extent=redArc[1])
blueCode = c.create_arc((2,2,98,98), fill="blue", start=blueArc[0], extent=blueArc[1])
whiteCode = c.create_arc((2,2,98,98), fill="white", start=whiteArc[0], extent=whiteArc[1])
def is_in_arc(x, y, angle0, angle1):
if (x-50)**2 + (y-50)**2 > 48**2:
return False
theta = - np.arctan2(y-50, x-50)
return angle0 <= frac(theta) <= angle1
def get_arc(x, y):
if is_in_arc(x, y, redArc[0], redArc[0]+redArc[1]):
return "red"
elif is_in_arc(x, y, blueArc[0], blueArc[0]+blueArc[1]):
return "blue"
elif is_in_arc(x, y, whiteArc[0], whiteArc[0]+whiteArc[1]):
return "white"
else:
return None
def redraw_chart(x, y):
global redCode, blueCode, whiteCode
arc = get_arc(x, y)
if arc == "red":
c.itemconfig(redCode, fill="green")
c.itemconfig(redCode, fill="blue")
c.itemconfig(redCode, fill="white")
elif arc == "blue":
c.itemconfig(redCode, fill="red")
c.itemconfig(redCode, fill="green")
c.itemconfig(redCode, fill="white")
elif arc == "white":
c.itemconfig(redCode, fill="red")
c.itemconfig(redCode, fill="blue")
c.itemconfig(redCode, fill="green")
else:
c.itemconfig(redCode, fill="green")
c.itemconfig(redCode, fill="blue")
c.itemconfig(redCode, fill="white")
c.bind('<Motion>', lambda e: redraw_chart(e.x, e.y))
c.mainloop()
You can use the bind
method to, well, bind an event and redraw the chart, like this: 您可以使用bind
方法来绑定事件并重绘图表,如下所示:
def on_enter(event):
c.create_arc((2,2,98,98), fill="orange", start=frac(100), extent = frac(400))
(...)
c.bind('<Enter>', on_enter)
See this answer for an example of how to embed the whole thing in a class. 有关如何将整个事物嵌入到类中的示例,请参阅此答案 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.