Related
I need help to generate this graph, especially with domains limits
and the arrow indicating the domain
all I can do is generate the domains name but not the limits and arrow
The following code will produce something like what you require:
from matplotlib import pyplot as plt
from matplotlib.patches import Wedge
import numpy as np
labels = ["Obésité\nmassive", "Obésité", "Surpoids", "Normal", "Maigreur"]
innerlabels = [">40", "30 à 40", "25 à 30", "18,5 à 25", "< 18,5"]
colours = ["red", "darkorange", "orange", "green", "blue"]
fig, ax = plt.subplots(figsize=(6, 6), dpi=200)
theta = 0
dtheta = 180 / len(labels)
width = 0.35
def pol2cart(rho, phi):
x = rho * np.cos(phi)
y = rho * np.sin(phi)
return(x, y)
patches = []
for i in range(len(labels)):
# outer wedge
wedge = Wedge(0, r=1, width=width, theta1=theta, theta2=(theta + dtheta), fc=colours[i], alpha=0.6, edgecolor="whitesmoke")
ax.add_patch(wedge)
# inner wedge
wedge = Wedge(0, r=1 - width, width=width, theta1=theta, theta2=(theta + dtheta), fc=colours[i], edgecolor="whitesmoke")
ax.add_patch(wedge)
theta += dtheta
# add text label
tr = 1 - (width / 2)
ta = theta - dtheta / 2
x, y = pol2cart(tr, np.deg2rad(ta))
textangle = -np.fmod(90 - ta, 180)
ax.text(x, y, labels[i], rotation=textangle, va="center", ha="center", color="white", fontweight="bold")
# inner labels
tr = (1 - width) - (width / 2)
x, y = pol2cart(tr, np.deg2rad(ta))
textangle = -np.fmod(90 - ta, 180)
ax.text(x, y, innerlabels[i], rotation=textangle, va="center", ha="center", color="white")
ax.set_xlim([-1, 1])
ax.set_ylim([0, 1])
ax.set_axis_off()
ax.set_aspect("equal")
def bmiposition(bmi):
"""
Get angular position of BMI arrow.
"""
from scipy.interpolate import interp1d
bmiranges = [(0, 18.5), (18.5, 25), (25, 30), (30, 40), (40, 80)]
angrange = [(180 - dtheta * i, 180 - dtheta * (i + 1)) for i in range(len(bmiranges))]
interpfuncs = []
for i in range(len(bmiranges)):
interpfuncs.append(interp1d(bmiranges[i], angrange[i], kind="linear"))
bmiang = np.piecewise(
bmi,
[bmiranges[i][0] < bmi <= bmiranges[i][1] for i in range(len(bmiranges))],
interpfuncs,
)
return bmiang
bmi = 22.5 # set BMI
# add arrow
pos = bmiposition(bmi) # get BMI angle
x, y = pol2cart(0.25, np.deg2rad(pos))
ax.arrow(0, 0, x, y, head_length=0.125, width=0.025, fc="k")
ax.plot(0, 0, 'ko', ms=10) # circle at origin
giving:
I want to create a simple animation to show my data changes.
create a 3 * 3 grid.
I have an array which is 20 * 9. The data is read into the animation line by line.
Color = [[0,0,0,0,0,0,0,0,0],
[100,0,0,0,100,0,0,0,0,0],
[80,0,80,0,80,100,0,0,0]
......]
I hope the list for the grid is read line by line and each line works for 100ms. If the number is more than 0, the color of the grid change into red. For example, in the first 100ms, all color is black, then, in the second 100ms, grid number 0 and grid number 4 change to red and last for 100ms. In the third 100ms, grid number 0,2,4,5 change to red and last for 100ms.
My current version of the code looks like this. I don't know how to draw like what I describe above.
%matplotlib notebook ## show in jupyter
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 6.5)
ax = plt.axes(xlim=(0, 10), ylim=(0, 10))
patch = plt.Circle((5, -5), 0.75, fc='y')
def init():
patch.center = (5, 5)
ax.add_patch(patch)
return patch,
def animate(i):
x, y = patch.center
x = 5 + 3 * np.sin(np.radians(i))
y = 5 + 3 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
anim = animation.FuncAnimation(fig, animate,
init_func=init,
frames=360,
interval=20,
blit=True)
plt.show()
I would appreciate it a lot if anyone could help me!!!
Cool question! I have an answer that works but it changes the structure of your Colors list. Here's the answer with an explanation below.
%matplotlib notebook
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 6.5)
ax = plt.axes(xlim=(0, 10), ylim=(0, 10))
patch = plt.Circle((5, -5), 0.75, fc='y')
colors = [
[["black", None, None], ["black", None, "black"], [None, None, "red"]],
[["black", None, None], ["black", None, "red"], ["black", None, "red"]],
[["red", None, None], [None, None, None], [None, None, "red"]],
]
def get_coords(colors):
y = 0
x = 0
coords = []
for row in colors:
x = 0
for entry in row:
if entry:
coords.append([entry, x, y])
x += 3.33
y += 3.33
return coords
def get_grids(coord):
return [plt.Rectangle((x[1], x[2]), 3.33, 3.33, fc=x[0]) for x in coord]
coords = [get_coords(color) for color in colors]
grids = [get_grids(coord) for coord in coords]
def init():
patch.center = (5, 5)
ax.add_patch(patch)
return patch,
def animate(i):
patches = []
if (i % 100 == 0):
ax.patches = []
next_grid = grids.pop(0)
for rectangle in next_grid:
patches.append(ax.add_patch(rectangle))
x, y = patch.center
x = 5 + 3 * np.sin(np.radians(i))
y = 5 + 3 * np.cos(np.radians(i))
patch.center = (x, y)
patches.append(ax.add_patch(patch))
return patches
anim = animation.FuncAnimation(fig, animate,
init_func=init,
frames=360,
interval=20,
blit=True)
plt.show()
The key idea is adding and removing plt.Rectangles to give the appearance of a grid. Because your graph is 10x10, these rectangles are squares of side length 10/3 =~ 3.33.
I think it's easier to use 20 * 3 * 3 instead of a 20 * 9 list for the colors. I use the following:
colors = [
[["black", None, None], ["black", None, "black"], [None, None, "red"]],
[["black", None, None], ["black", None, "red"], ["black", None, "red"]],
[["red", None, None], [None, None, None], [None, None, "red"]],
]
Each entry in this list, as yours, is a grid. Within these grids, however, are rows, each with a desired color entry. colors[0][0] == ["black", None, None] means at the first frame of the animation, the bottom left corner of the grid will be black and the rest of the bottom transparent. colors[0][1] == ["black", None, "black"] means the middle of the grid will have the left and right thirds black with the middle transparent.
The get_coords and get_grids functions are pretty hairy and clearly hard-coded to support a 3x3 grid with dimensions 10x10 - it'd be cool to parameterize that out down the line.
Only other important idea is that to change the animation every 100ms, we just check if i in the animate function is divisible by 100. If it is, we clear the existing patches (so we're not just adding rectangles ad nausem) and plot our new ones. When the grid list runs out, the grid will be transparent for the rest of the animation.
Hope this helps - happy plotting!
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
Color = [[0,0,0,0,0,0,0,0,0],
[100,0,0,0,100,0,0,0,0,0],
[80,0,80,0,80,100,0,0,0]]
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 6.5)
fig.set_tight_layout(True)
ax = plt.axes(xlim=(0, 6), ylim=(0, 6))
patch = []
patch.append(plt.Rectangle(xy = (0,0),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (2,0),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (4,0),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (0,2),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (2,2),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (4,2),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (0,4),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (2,4),width = 2,height = 2,fill = True,color = 'k'))
patch.append(plt.Rectangle(xy = (4,4),width = 2,height = 2,fill = True,color = 'k'))
def init():
for i in range(9):
patch[i].set_color('k')
ax.add_patch(patch[i])
return patch
def animate(i):
value = (np.array(Color[i]) == 0)
for j in range(9):
patch[j].set_color('k' if value[j] else 'r')
return patch
anim = animation.FuncAnimation(fig, animate,
init_func=init,
frames=3,
interval=1000,
blit=True)
plt.show()
This program reads an image which is in location C:/Square.png and lines are plotted over it. The plot title is also defined. I want to show this whole image in tkinter window. How do I do it?
This is the image. The name has to be changed and we can run the code.
https://imgur.com/RkV02yY
import math
import matplotlib.pyplot as plt
def plot_output(opt_w, opt_h, n_x, n_y):
y_start, y_end = 100, 425
x_start, x_end = 25, 400
img = plt.imread("C:/Square.png") #Please change the location
fig, ax = plt.subplots(figsize=(10, 10))
plt.axis('off')
ax.imshow(img)
x_interval = (x_end - x_start)/n_x*2
h_x = range(x_start, x_end, 5)
for i in range(0,int(n_y)):
if i != 0:
ax.plot(h_x, [y_start + (y_end-y_start)/n_y*i]*len(h_x), '--', linewidth=5, color='firebrick')
plt.title(str(int(n_x*n_y)) + ' ABCD\n'+'TYUI:'+str(opt_w)+', Yummy:'+str(opt_h))
def get_get(min_w, min_h, max_w, max_h, PL, PH, min_t, max_t, cost_m, cost_a):
x = 1
if max_w < PL:
x = math.ceil(PL / max_w)
cost_rest = cost_m * PL * PH * (max_t + min_t) / 2 + cost_a * PH * x
cost_y = float("inf")
y = None
if min_h == 0:
min_h = 1
for i in range(math.ceil(PH / max_h), math.floor(PH / min_h)+1):
tmp_cost = cost_m * PL * PH * (max_t - min_t) / 2 / i + cost_a * PL * i
if tmp_cost < cost_y:
cost_y = tmp_cost
y = i
opt_w, opt_h, opt_cost = PL/x, PH/y, cost_rest + cost_y
plot_output(opt_w, opt_h, x, y)
return opt_w, opt_h, opt_cost
PL=30
PH=10
min_t=0.1
max_t=0.3
cost_m=0.1
cost_a=0.1
min_w=0.5
min_h=0.5
max_w=4
max_h=3
get_get(min_w, min_h, max_w, max_h, PL, PH, min_t, max_t, cost_m, cost_a)
You need to add plt.show()
import math
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use("Tkagg")
def plot_output(opt_w, opt_h, n_x, n_y):
y_start, y_end = 100, 425
x_start, x_end = 25, 400
img = plt.imread("C:/Square.png") #Please change the location
fig, ax = plt.subplots(figsize=(10, 10))
plt.axis('off')
ax.imshow(img)
x_interval = (x_end - x_start)/n_x*2
h_x = range(x_start, x_end, 5)
for i in range(0,int(n_y)):
if i != 0:
ax.plot(h_x, [y_start + (y_end-y_start)/n_y*i]*len(h_x), '--', linewidth=5, color='firebrick')
plt.title(str(int(n_x*n_y)) + ' ABCD\n'+'TYUI:'+str(opt_w)+', Yummy:'+str(opt_h))
plt.show()
def get_get(min_w, min_h, max_w, max_h, PL, PH, min_t, max_t, cost_m, cost_a):
x = 1
if max_w < PL:
x = math.ceil(PL / max_w)
cost_rest = cost_m * PL * PH * (max_t + min_t) / 2 + cost_a * PH * x
cost_y = float("inf")
y = None
if min_h == 0:
min_h = 1
for i in range(math.ceil(PH / max_h), math.floor(PH / min_h)+1):
tmp_cost = cost_m * PL * PH * (max_t - min_t) / 2 / i + cost_a * PL * i
if tmp_cost < cost_y:
cost_y = tmp_cost
y = i
opt_w, opt_h, opt_cost = PL/x, PH/y, cost_rest + cost_y
plot_output(opt_w, opt_h, x, y)
return opt_w, opt_h, opt_cost
PL=30
PH=10
min_t=0.1
max_t=0.3
cost_m=0.1
cost_a=0.1
min_w=0.5
min_h=0.5
max_w=4
max_h=3
get_get(min_w, min_h, max_w, max_h, PL, PH, min_t, max_t, cost_m, cost_a)
Edit: I forgot to change the backend to tkinter
I am attempting to animate two different particles in matplotlib (python). I just figured out a way to animate one particle in matplotlib, but I am havign difficulties trying to get the program to work with multiple particles. Does anyone know what is wrong and how to fix it?
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(5, 4.5)
ax = plt.axes(xlim=(0, 100), ylim=(0, 100))
enemy = plt.Circle((10, -10), 0.75, fc='r')
agent = plt.Circle((10, -10), 0.75, fc='b')
def init():
#enemy.center = (5, 5)
#agent.center = (5, 5)
ax.add_patch(agent)
ax.add_patch(enemy)
return []
def animationManage(i,agent,enemy):
patches = []
enemy.center = (5, 5)
agent.center = (5, 5)
enemy_patches = animateCos(i,agent)
agent_patches = animateLine(i,enemy)
patches[enemy_patches, agent_patches]
#patches.append(ax.add_patch(enemy_patches))
#patches.append(ax.add_patch(agent_patches))
return enemy_patches
def animateCirc(i, patch):
# It seems that i represents time step
x, y = patch.center
# 1st constant = position and 2nd constant = trajectory
x = 50 + 30 * np.sin(np.radians(i))
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
def animateLine(i, patch):
x, y = patch.center
x = x + 1
y = x+ 1
patch.center = (x, y)
return patch,
def animateCos(i, patch):
x, y = patch.center
x = x + 0.2
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
def animateSin(i, patch):
x, y = patch.center
x = x + 0.2
y = 50 + 30 * np.sin(np.radians(i))
patch.center = (x, y)
return patch,
anim = animation.FuncAnimation(fig, animationManage,
init_func=init,
frames=360,
fargs=(agent,enemy,),
interval=20,
blit=True)
plt.show()
Working code for animating one particle
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(5, 4.5)
ax = plt.axes(xlim=(0, 100), ylim=(0, 100))
enemy = plt.Circle((10, -10), 0.75, fc='r')
agent = plt.Circle((10, -10), 0.75, fc='b')
def init():
enemy.center = (5, 5)
agent.center = (5, 5)
ax.add_patch(enemy)
ax.add_patch(agent)
return enemy,
def animateCirc(i, patch):
# It seems that i represents time step
x, y = patch.center
# 1st constant = position and 2nd constant = trajectory
x = 50 + 30 * np.sin(np.radians(i))
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
def animateLine(i, patch):
x, y = patch.center
x = x + 1
y = x+ 1
patch.center = (x, y)
return patch,
def animateCos(i, patch):
x, y = patch.center
x = x + 0.2
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
def animateSin(i, patch):
x, y = patch.center
x = x + 0.2
y = 50 + 30 * np.sin(np.radians(i))
patch.center = (x, y)
return patch,
anim = animation.FuncAnimation(fig, animateCos,
init_func=init,
frames=360,
fargs=(enemy,),
interval=20,
blit=True)
plt.show()
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(5, 4.5)
ax = plt.axes(xlim=(0, 100), ylim=(0, 100))
enemy = plt.Circle((10, -10), 0.75, fc='r')
agent = plt.Circle((10, -10), 0.75, fc='b')
def init():
enemy.center = (5, 5)
agent.center = (5, 5)
ax.add_patch(agent)
ax.add_patch(enemy)
return []
def animationManage(i,agent,enemy):
animateCos(i,enemy)
animateLine(i,agent)
return []
def animateLine(i, patch):
x, y = patch.center
x += 0.25
y += 0.25
patch.center = (x, y)
return patch,
def animateCos(i, patch):
x, y = patch.center
x += 0.2
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
anim = animation.FuncAnimation(fig, animationManage,
init_func=init,
frames=360,
fargs=(agent,enemy,),
interval=20,
blit=True,
repeat=True)
plt.show()
I have two linked scatter plots with points that have different opacities. The problem is that when some points are selected with the box-select tool, all the unselected points become the same opacity.
I would like for the unselected points to stay their original opacity. Points with different opacities can be linked, so I can't solve the problem by making an array of points for each opacity value.
Is there a way that I can achieve this within the plotting API?
Can I extend nonselection_glyph so its alpha attribute accepts an array of opacity values like the circle marker's alpha attribute does?
import numpy as np
from bokeh.plotting import output_file, figure, gridplot, show
from bokeh.models import ColumnDataSource, Circle
N = 100
max = 100
x1 = np.random.random(size = N) * max
y1 = np.random.random(size = N) * max
a1 = np.random.choice(a = [0.2, 0.5, 1], size = N)
x2 = np.random.random(size = N) * max
y2 = np.random.random(size = N) * max
a2 = np.random.choice(a = [0.2, 0.5, 1], size = N)
output_file('scatter.html')
source = ColumnDataSource(data = dict(x1 = x1, y1 = y1, x2 = x2, y2 = y2,
a1 = a1, a2 = a2))
left = figure(tools = 'box_select, tap', width = 400, height = 400,
x_range = (0,100), y_range = (0,100))
right = figure(tools = 'box_select, tap', width = 400, height = 400,
x_range = (0,100), y_range = (0,100))
points1 = left.circle('x1', 'y1', source = source, size = 10,
fill_color = 'blue', line_color = None, alpha = 'a1')
points2 = right.circle('x2', 'y2', source = source, size = 10,
fill_color = 'blue', line_color = None, alpha = 'a2')
points1.selection_glyph = Circle(fill_color = 'red', line_color = None)
points2.selection_glyph = Circle(fill_color = 'red', line_color = None)
p = gridplot([[left, right]])
show(p)
Try this:
import numpy as np
from bokeh.plotting import output_file, figure, gridplot, show
from bokeh.models import ColumnDataSource, Circle
N = 100
max = 100
x1 = np.random.random(size = N) * max
y1 = np.random.random(size = N) * max
a1 = np.random.choice(a = [0.2, 0.5, 1], size = N)
x2 = np.random.random(size = N) * max
y2 = np.random.random(size = N) * max
a2 = np.random.choice(a = [0.2, 0.5, 1], size = N)
source = ColumnDataSource(data = dict(x1 = x1, y1 = y1, x2 = x2, y2 = y2,
a1 = a1, a2 = a2, a1n = a1 * 0.5, a2n=a2*0.5))
left = figure(tools = 'box_select, tap', width = 400, height = 400,
x_range = (0,100), y_range = (0,100))
right = figure(tools = 'box_select, tap', width = 400, height = 400,
x_range = (0,100), y_range = (0,100))
points1 = left.circle('x1', 'y1', source = source, size = 10,
fill_color = 'blue', line_color = None, alpha = 'a1')
points2 = right.circle('x2', 'y2', source = source, size = 10,
fill_color = 'blue', line_color = None, alpha = 'a2')
points1.selection_glyph = Circle(fill_color = 'red', line_color = None)
points2.selection_glyph = Circle(fill_color = 'red', line_color = None)
points1.nonselection_glyph.fill_alpha = "a1n"
points2.nonselection_glyph.fill_alpha = "a2n"
p = gridplot([[left, right]])
show(p)
I found that nonselection_glyph can take an array of opacity values, but that array has to be in the ColumnDataSource.