How to update a plot or graph in matplotlib - python

I would like to know how to update a graph and or plot in matplotlib every few seconds. Code:
import matplotlib.pyplot as plt
import numpy as np
axes = plt.gca()
axes.set_xlim([0,5])
axes.set_ylim([0,100])
X = [0, 1, 2, 3, 4, 5]
Y = [15, 30, 45, 60, 75, 90]
plt.plot(X, Y)
plt.xlabel('Time spent studying (hours)')
plt.ylabel('Score (percentage)')
plt.show()

What you have written is correct , but in order to make your code dynamic , you can put the code in a function and pass the X and Y coordinates to the function . One example as shown below
def GrapgPlot(X, Y):
"Your code"
GrapgPlot([0, 1, 2, 3, 4, 5],[90, 30, 45, 60, 75, 90])
In the plot if you are certain that X axis will not change than you can fix X axis in the code and take only Y axis values as a list from the user as an input and pass it in the function as an argument.
else the best way if you do want user interaction . Update the X and Y axis list with a loop and pass X and Y values in the function as an argument

Used time.sleep(1) for being able to see the changes and reversed Y for new data to be updated. Hopefully this is what you want:
%matplotlib notebook
import time
import matplotlib.pyplot as plt
X = [0, 1, 2, 3, 4, 5]
Y = [15, 30, 45, 60, 75, 90]
fig, ax = plt.subplots()
ax.set_xlim([0,5])
ax.set_ylim([0,100])
ax.set_xlabel('Time spent studying (hours)')
ax.set_ylabel('Score (percentage)')
l, = ax.plot(X, Y)
for ydata in [Y, Y[::-1]]*2:
l.set_ydata(ydata)
fig.canvas.draw()
time.sleep(0.5)

Related

Keep the gap between two datasets in matplotlib

I have two datasets
firstX = [0, 1, 2, 3, 4, 5, 6] # X Axis
firstY = [10, 10, 20, 30, 40, 60, 70] # Y Axis
secondX = [9, 10, 11, 12, 13, 14, 15] # X Axis
secondY = [40, 20, 60, 11, 77, 12, 54] # Y Axis
I want to plot these two datasets in the same chart but without connecting them together. As you can see, there is a disconnection between them (in X axis, 7 and 8 are missing). When I concat them, matplotlib will try to connect the last point of the first dataset (6, 70) with the first point of the second dataset (9, 40). I would like to know how to avoid this behavior
You can just plot them individually. If they're sublists of a list, e.g. X = [[X1], [X2]], Y = [[Y1], [Y2]], you can loop over them.
import matplotlib.pyplot as plt
fig = plt.figure()
for i in range(len(X)):
plt.plot(X[i], Y[i])
plt.show()
Instead of concatenating the datasets, you can call the plot command two times, plotting two times to the same axes:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(firstX, firstY)
ax.plot(secondX, secondY)
From what I understand your question, this should work:
import matplotlib.pyplot as plt
plt.figure()
plt.plot(firstX, firstY, c='b')
plt.plot(secondX, secondY, c='b')
plt.show

How to create a scatter plot with color specified for each point individually?

Using matplotlib I create a scatter plot animation that shows a new point after each second and shows all old points partly transparent. Each point is defined by x and y, but also by a category s. I want the color of the points to be tied to its category. Ideally that means that the array s contains values 1, 2 and 3, and the colors belonging to those values are defined seperately. However, I can not get this to work.
What I do get to work is to specify the edgecolors of each point individually in s, the code for this is shown below.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as plti
import matplotlib.animation
s = [[1,0,0],[0,1,0],[0,0,1]];
x = [525,480,260];
y = [215,180,180];
img = plti.imread('myimage.png')
fig, ax = plt.subplots()
plt.imshow(img)
plt.axis('off')
x_vals = []
y_vals = []
intensity = []
iterations = len(x)
colors = []
t_vals = np.linspace(0,iterations-1,iterations,dtype=int)
scatter = ax.scatter(x_vals, y_vals, s=100, c=colors, vmin=0, vmax=1)
def init():
pass
def update(t):
global x, y, x_vals, y_vals, intensity
x_vals.extend([x[t]])
y_vals.extend([y[t]])
scatter.set_offsets(np.c_[x_vals,y_vals])
intensity = np.concatenate((np.array(intensity), np.ones(1)))
if len(intensity) > 1:
intensity[-2] = 0.5
scatter.set_array(intensity)
colors.extend([s[t]])
scatter.set_color(colors)
return ani
ani = matplotlib.animation.FuncAnimation(fig, update, frames=t_vals, interval=1000, repeat=False, init_func=init)
plt.show()
Simply changing c=colors to facecolor=colors does not work. Also I have tried to use colormaps but I cannot get it to work using that either.
The resulting animation from the code above looks as below.
However, the animation should look like this..
So my question is; does someone know how to tie the facecolor of each point to the category that that point belongs to?
The normal way to plot plots with points in different colors in matplotlib is to pass a list of colors as a parameter.
E.g.:
import matplotlib.pyplot
matplotlib.pyplot.scatter([1,2,3],[4,5,6],color=['red','green','blue'])
But if for some reason you wanted to do it with just one call, you can make a big list of colors, with a list comprehension and a bit of flooring division:
import matplotlib
import numpy as np
X = [1,2,3,4]
Ys = np.array([[4,8,12,16],
[1,4,9,16],
[17, 10, 13, 18],
[9, 10, 18, 11],
[4, 15, 17, 6],
[7, 10, 8, 7],
[9, 0, 10, 11],
[14, 1, 15, 5],
[8, 15, 9, 14],
[20, 7, 1, 5]])
nCols = len(X)
nRows = Ys.shape[0]
colors = matplotlib.cm.rainbow(np.linspace(0, 1, len(Ys)))
cs = [colors[i//len(X)] for i in range(len(Ys)*len(X))] #could be done with numpy's repmat
Xs=X*nRows #use list multiplication for repetition
matplotlib.pyplot.scatter(Xs,Ys.flatten(),color=cs)
The problem occurred because the line scatter.set_array(intensity) was called before scatter.set_color(colors). So instead of defining the intensity by a seperate variable, it is instead integrated into the colors directly. The following code produces the desired result.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as plti
import matplotlib.animation
s = [1,2,3];
x = [525,480,260];
y = [215,180,180];
img = plti.imread('myimage.png')
fig, ax = plt.subplots()
plt.imshow(img)
plt.axis('off')
x_vals = []
y_vals = []
iterations = len(x)
colors = []
t_vals = np.linspace(0,iterations-1,iterations,dtype=int)
scatter = ax.scatter(x_vals, y_vals, s=100, color=colors, vmin=0, vmax=1)
def init():
pass
def update(t):
global x, y, x_vals, y_vals
x_vals.extend([x[t]])
y_vals.extend([y[t]])
scatter.set_offsets(np.c_[x_vals,y_vals])
if t > 0:
if s[t-1] == 1:
colors[t-1] = [1,0,0,0.5];
elif s[t-1] == 2:
colors[t-1] = [0,1,0,0.5];
else:
colors[t-1] = [0,0,1,0.5];
if s[t] == 1:
colors.extend([[1,0,0,1]])
elif s[t] == 2:
colors.extend([[0,1,0,1]])
else:
colors.extend([[0,0,1,1]])
scatter.set_color(colors);
return ani
ani = matplotlib.animation.FuncAnimation(fig, update, frames=t_vals, init_func=init, interval=1000, repeat=False)
plt.show()

Got more ylabels than specified by set_yticklabel() [duplicate]

Here is a simple plot:
1) How to disable the ticks?
2) How to reduce their number?
Here is a sample code:
from pylab import *
import numpy as np
x = [5e-05, 5e-06, 5e-07, 5e-08, 5e-09, 5e-10]
y = [-13, 14, 100, 120, 105, 93]
def myfunc(x,p):
sl,yt,yb,ec=p
y = yb + (yt-yb)/(1+np.power(10, sl*(np.log10(x)-np.log10(ec))))
return y
xp = np.power(10, np.linspace(np.log10(min(x)/10), np.log10(max(x)*10), 100))
pxp=myfunc(xp, [1,100,0,1e-6])
subplot(111,axisbg="#dfdfdf")
plt.plot(x, y, '.', xp, pxp, 'g-', linewidth=1)
plt.xscale('log')
plt.grid(True,ls="-", linewidth=0.4, color="#ffffff", alpha=0.5)
plt.draw()
plt.show()
Which produces:
plt.minorticks_off()
Turns em off!
To change the number of them/position them, you can use the subsx parameter. like this:
plt.xscale('log', subsx=[2, 3, 4, 5, 6, 7, 8, 9])
From the docs:
subsx/subsy: Where to place the subticks between each major tick.
Should be a sequence of integers. For example, in a log10 scale: [2,
3, 4, 5, 6, 7, 8, 9]
will place 8 logarithmically spaced minor ticks between each major
tick.
Calling plt.minorticks_off() will apply this to the current axis. (The function is actually a wrapper to gca().minorticks_off().)
You can also apply this to an individual axis in the same way:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.minorticks_off()
from pylab import *
import numpy as np
x = [5e-05, 5e-06, 5e-07, 5e-08, 5e-09, 5e-10]
y = [-13, 14, 100, 120, 105, 93]
def myfunc(x,p):
sl,yt,yb,ec=p
y = yb + (yt-yb)/(1+np.power(10, sl*(np.log10(x)-np.log10(ec))))
return y
xp = np.power(10, np.linspace(np.log10(min(x)/10), np.log10(max(x)*10), 100))
pxp=myfunc(xp, [1,100,0,1e-6])
ax=subplot(111,axisbg="#dfdfdf")
plt.plot(x, y, '.', xp, pxp, 'g-', linewidth=1)
plt.xscale('log')
plt.grid(True,ls="-", linewidth=0.4, color="#ffffff", alpha=0.5)
plt.minorticks_off() # turns off minor ticks
plt.draw()
plt.show()

Matplotlib animation: draw lines in different colours

I have the following code right now, to show growth of a curve:
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation
def move_curve(i, line, x, y, z):
# Add points rather than changing start and end points.
line.set_data(x[:i+1], y[:i+1])
line.set_3d_properties(z[:i+1])
fig = plt.figure()
ax = fig.gca(projection='3d')
x = [1, 3, 8, 11, 17]
y = [7, 2, -5, 3, 5]
z = [5, 7, 9, 13, 18]
i = 0
line = ax.plot([x[i], x[i+1]], [y[i],y[i+1]], [z[i],z[i+1]])[0]
ax.set_xlim3d([1, 17])
ax.set_ylim3d([-5, 7])
ax.set_zlim3d([5, 18])
line_ani = animation.FuncAnimation(fig, move_curve, 5, fargs=(line, x, y, z))
plt.show()
I want to show the different lines in different colours. Also, I want to update the length of the axis as the curve grows.
How to do that? I am new to python so I might be missing something simple. Thanks for the help!
Here is how #MrT's answer would look like using FuncAnimation. The advantage is that you do not need to care about autoscaling; that is done automatically on the fly.
import matplotlib.pyplot as plt
import matplotlib.animation as anim
import mpl_toolkits.mplot3d.axes3d as p3
fig = plt.figure()
ax = fig.gca(projection='3d')
x = [1, 3, 8, 11, 17]
y = [7, 2, -5, 3, 5]
z = [5, 7, 9, 13, 18]
#colour map
colors = ["green", "blue", "red", "orange"]
def init():
ax.clear()
def update(i):
newsegm, = ax.plot([x[i], x[i + 1]], [y[i], y[i + 1]], [z[i], z[i + 1]], colors[i])
ani = anim.FuncAnimation(fig, update, init_func=init,
frames = range(len(x)-1), interval = 300, repeat=True)
plt.show()
You can use ArtistAnimation and attribute an individual colour to each line segment:
import matplotlib.pyplot as plt
import matplotlib.animation as anim
import mpl_toolkits.mplot3d.axes3d as p3
fig = plt.figure()
ax = fig.gca(projection='3d')
x = [1, 3, 8, 11, 17]
y = [7, 2, -5, 3, 5]
z = [5, 7, 9, 13, 18]
#colour map
cmap = ["green", "blue", "red", "orange"]
#set up list of images for animation with empty list
lines=[[]]
for i in range(len(x) - 1):
#create next segment with new color
newsegm, = ax.plot([x[i], x[i + 1]], [y[i], y[i + 1]], [z[i], z[i + 1]], cmap[i])
#append new segment to previous list
lines.append(lines[-1] + [newsegm])
#animate list of line segments
ani = anim.ArtistAnimation(fig, lines, interval = 300)
plt.show()
Output:

How to plot pseudo-3d bar chart in matplotlib?

I'd like to prepare some statistics for my boss. The flat style of matplotlib bar chart would make them look cheap for those used to Excel charts, although for clarity, using styles like this probably should be avoided.
I'm not that far away, but I don't get how to give the right thickness of the bars:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
row = [0, 0, 0, 22, 0, 0, 4, 16, 2, 0, 4, 4, 12, 26]
length = len(row)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.arange(length)
y = np.zeros(14)
z = np.array(row)
width = 0.8
ax.bar3d(x, y, [0]*length, 0.5, 0.001, z)
ax.set_xticks(x + width/2)
ax.set_xticklabels(titles[2:], rotation=90)
ax.set_yticks(y)
ax.set_zlabel('count')
plt.show()
Result:
The thickness of the bars are set by the dx, dy arguments in ax.bar3d for which you have the values 0.5, 0.001. The issue, as I'm sure you noticed is that changing dy will change the length of the bar (in your case the untitled axis), but matplotlib helpfully rescales the y axis so the data fills it. This makes it look strange (I am assuming this is the problem, sorry if it isn't).
To remedy this you could set the y limits using ax.set_ylim(0, 0.002) (basically your y values go from 0->0.001). If you change either dy or the value of y given to bar3d which is currently 0, then you will need to update the limits accordingly.
Example:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
row = [0, 0, 0, 22, 0, 0, 4, 16, 2, 0, 4, 4, 12, 26]
length = len(row)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.bar3d(range(length), [0]*length, [0]*length, 0.5, 0.001, row)
ax.set_ylim(-0.005, 0.005)
plt.show()

Categories