Updateing multi-plot matplotlib - python

I have a problem witch updateing matplotlib chart. The problem is that i have many curve's on it, and after update the number of them may change. In example code I have 2 sets of data, 1st with 90 curves, and 2nd with 80, and i wish I could plot 1st set, and then 2nd, in the same matplotlib window.
import matplotlib.pyplot as plt
from matplotlib.transforms import Bbox
import numpy as np
from numpy.lib.polynomial import RankWarning
import pandas as pd
import sys
fig, ax = plt.subplots()
fig.subplots_adjust(right=0.78)
_x = []
_y = []
_y1 = []
_x1 = []
for x in range(90):
_x.append(np.linspace(0, 10*np.pi, 100))
_y.append(np.sin(_x[x])+x)
for x in range(80):
_x1.append(np.linspace(0, 10*np.pi, 150))
_y1.append(np.tan(_x1[x]+x))
def narysuj(__x, __y):
p = [] # p-pomiar
f = [] # f-czestotliwosc
for x in range(len(__x)):
p.append([])
f.append([])
ax.set_prop_cycle(color=plt.cm.gist_rainbow(np.linspace(0, 1, len(__x))))
for x in range(len(__x)):
for line in range(len(__x[x])):
#print(len(_y[x]), line)
p[x].append(__y[x][line])
f[x].append(__x[x][line])
ax.plot(f[x], p[x], label=f"Label {x}")
plt.show()
narysuj(_x, _y)
narysuj(_x1, _y1)
PS I know the way I'm drawing those charts is highly ineffective.

I found what was the problem. I had to add plt.ion() at the start of program and ax.clear() before drawing.

Related

Choosing right data to encircle

I'm relatively new to python/mongodb and working on a project but ran into an issue.
I've been given a data set based on Game of Thrones and wanted to see the relationship between Killed Count, How many people they have been killed by on a scatter plot and encircling the data points that have to do with royals. I've created the columns counting the killed/killedBy columns, and have created an encircle data set that only has the rows that have royal=1, but am not sure how to write the encircle() line in order to encircle all the data. Here is the code that i've written below (apologies as I know its probably very inefficient).
from pymongo import MongoClient
import pandas as pd
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import style
import numpy as np
from scipy.spatial import ConvexHull
client=MongoClient()
db=client.GoT
characters = db.characters
M = characters.find()
CDB = {}
for m in M:
CDB[m["characterName"]] = m
CDBdf = pd.DataFrame(CDB)
CDBdf = CDBdf.T
CDBdf["RoyalExists"] = ""
CDBdf["KilledByExists"] = ""
CDBdf["KilledExists"] = ""
for index, row in CDBdf.iterrows():
if (pd.isna(row['royal'])==False):
row['RoyalExists']=1
else:
row['RoyalExists']=0
for index, row in CDBdf.iterrows():
if (np.any(pd.isna(row['killedBy'])== False)==False):
row['KilledByExists']=0
else:
row['KilledByExists']= len(row['killedBy'])
for index, row in CDBdf.iterrows():
if (np.any(pd.isna(row['killed'])== False)==False):
row['KilledExists']=0
else:
row['KilledExists']=len(row['killed'])
x= CDBdf["KilledExists"]
y= CDBdf["KilledByExists"]
fig = plt.figure(figsize=(16, 10), dpi= 80, facecolor='w', edgecolor='k')
plt.scatter(x, y)
def encircle(x,y, ax=None, **kw):
if not ax: ax=plt.gca()
p = np.c_[x,y]
hull = ConvexHull(p)
poly = plt.Polygon(p[hull.vertices,:], **kw)
ax.add_patch(poly)
encircle_data = CDBdf.loc[CDBdf["RoyalExists"]==1]
encircle(encircle_data.CDBdf["KilledExists"],encircle_data.CDBdf["KilledByExists"], ec="k", fc="gold", alpha=0.1)
plt.show()
encircle_data
Was just hoping for some clarification on how to write the line "encircle(encircle_data.CDBdf["KilledExists"],encircle_data.CDBdf["KilledByExists"], ec="k", fc="gold", alpha=0.1)" so that it circles all of the royals data points.

Hist chart from list

import matplotlib as plp
cube = []
z = 0
while not z == 50:
x = random.randint(1, 6)
cube.append(x)
z = z + 1
print(cube)
plp.plot(cube[1])
plp.show()
How to repair this code to show histogram from components include in my list cube?
The comments do make some suggestions on most of the fixes you can make, but you can also improve this code alot in other ways. Here is what I would propose:
import matplotlib.pyplot as plt
import random
cube = []
for _ in range(50):
x = random.randint(1, 6)
cube.append(x)
plt.hist(cube)
plt.show()
First, since you only use z as an iteration counter, a for loop is better here (though the while loop will still work, it is more error prone). I also changed plp to plt, you don't have to do this but this is the convention. You can then use plt.hist(cube) to plot a histogram.
Note that if you want to use numpy, you can make this even simpler:
import matplotlib.pyplot as plt
import numpy as np
cube = np.random.randint(1, 6, size=50)
plt.hist(cube)
plt.show()
Since numpy lets you specify the size of the array of random numbers you want.

Plot dual points with one point fixed

I'm trying to plot a set of points with a special feature,
first plot 2 points with a random coordinates x and y, in a range from 0 to 200,
but my problem is how can set this points as fixed or centers, take this center-points and from this points, plot one new point with random coordinates(as pairs of points A-a, B-b, etc), and define the distance that can't be higher than 30 meter or units of distance beetwen this points. To get the points like this
I add part of my code to make this
import matplotlib as mpl
from matplotlib.figure import Figure
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from itertools import product
from matplotlib.lines import Line2D
fig,ax=plt.subplots()
#AP POINTS
###################################################
points_xA=np.random.randint(0,200)
points_yA=np.random.randint(0,200)
points_xB=np.random.randint(0,200)
points_yB=np.random.randint(0,200)
center1=np.array([points_xA,points_yB])
center2=np.array([points_xB,points_yB])
ax.annotate("A",xy=(center1),fontsize=12,bbox={"boxstyle":"circle","color":"orange"})
ax.annotate("B",xy=(center2),fontsize=12,bbox={"boxstyle":"circle","color":"orange"})
#STA POINTS
######################################################
#points_xa=np.random.randint()
#points_ya=np.random.randint()
#points_xb=np.random.randint()
#points_yb=np.random.randint()
######################################################
#LABELS
plt.title('random points')
plt.xlabel('x(m)')
plt.ylabel('y(m)')
plt.xlim(0,210)
plt.ylim(0,210)
plt.grid(True)
plt.show()
i have develop a script that plot points as i wanted, but it have some issues:
1.- The menu or bar where the zoom functions, save image, etc. It disappeared and I can't zoom, which I think would be the most important thing.
2.- The table where is the coordinates of each point, for example, for AP_A it have his STA_A1 o more, depending how many STA's you want( for 3 STA's it would be STA_A1, STA_A2, STA_A3, etc)
but in the table apears as STA_A1, for any STA, in the next image it's more clear
I hope it will be useful to someone, on the other hand if someone can correct those errors in my code it would be great, I thank to this community where I have found some solutions on several occasions.
code:
import matplotlib as mpl
from matplotlib.figure import Figure
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from itertools import product
from matplotlib.lines import Line2D
##########################
#RADIOS
radius1=30
#radius2=30
#AP POINTS
###################################################
def setNodos(n,rango=300,n_clientes=6):
listaNodos = []
for i in range(n):
points_x=np.random.randint(0,rango)
points_y=np.random.randint(0,rango)
listaNodos.append((np.array([points_x,points_y]),n_clientes))
return listaNodos
listaNodos = setNodos(4,300,3)
abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
points_x = []
points_y = []
sta_cant = []
points_sta_x = []
points_sta_y = []
sta_names = []
for nodo,n in listaNodos:
points_x.append(nodo[0])
points_y.append(nodo[1])
sta_cant.append(n)
t_data=[]
########################################
fig = plt.figure(figsize = (15,10))
ax = plt.subplot2grid((3,2), (0, 0),colspan=2,rowspan=2)
l=0
sta_n=0
print(listaNodos)
for centerA,sta_n in listaNodos:
cxA,cyA = centerA
ax.annotate(abc[l],xy=(centerA),fontsize=12,bbox={"boxstyle":"circle","color":"orange"})
#RADIO CIRCULO ROJO
ct1A=np.linspace(0,2*np.pi)
circx11,circy12 = radius1*np.cos(ct1A)+cxA, radius1*np.sin(ct1A)+cyA
plt.plot(circx11, circy12, ls="-",color='red')
#RELLENO CIRCULO ROJO
ax= plt.gca()
t1= plt.Polygon([[i,j] for i, j in zip(circx11,circy12)], color='slategrey', alpha=0.2)
ax.add_patch(t1)
######################################################
#STA POINTS
######################################################
r_sta = np.random.randint(0,radius1,size=sta_n)
tita_sta = np.random.randint(0,359,size=sta_n)
x_sta = np.round(r_sta*np.cos(tita_sta)+cxA,0)
y_sta = np.round(r_sta*np.sin(tita_sta)+cyA,0)
print(x_sta,y_sta)
for x,y in zip(x_sta,y_sta):
#plt.scatter(x,y,c='b',zorder=1000)
x = np.min((300,np.max((0,int(x)))))
y = np.min((300,np.max((0,int(y)))))
ax.annotate(abc[l].lower(),xy=((x,y)),fontsize=10,color='black',
bbox={"boxstyle":"circle","color":"steelblue","alpha":0.5},
)
sta_names.append('STA_%s%i'%(abc[l],l+1))
points_sta_x.append(x)
points_sta_y.append(y)
l+=1
######################################################
#Tabla con coordenadas
plt.xlabel('x(m)')
plt.ylabel('y(m)')
plt.xlim(-10,310)
plt.ylim(-10,310)
ax.grid(True)
plt.title('random points')
t_data.append(points_x+points_sta_x)
t_data.append(points_y+points_sta_y)
print(t_data)
print(sta_n)
collLabels =[('AP_%s'%i) for i in abc[:len(points_x)]]
for name in sta_names:
collLabels.append(name)
print(collLabels)
ax1 = plt.subplot2grid((3,2), (2, 0),colspan=2,rowspan=1)
table=ax1.table(cellText = t_data,
colLabels=collLabels,
rowLabels=('coord_x','coord_y'),
bbox=[0,0.3,0.1+0.05*len(collLabels),0.6+0.01*len(collLabels)]
,cellLoc='center',fontsize=30)
plt.xticks([])
plt.yticks([])
plt.axis('OFF')
plt.tight_layout(rect=[0.01, 0.01, 1.0, 1.0])
#######################################################
#LABELS
ax.set_aspect('equal')
plt.savefig('./salida/escen_random.png')
plt.show()

Python plot with unique colors for more than 10 lines

I am trying to plot the line graph with around 15 to 50 items, colors are repeating that makes the graph not usable.
I have tried the answers from several method in the answers of a similar question like numpy, random.
However, i am unable to find a easy way to do this .
import matplotlib.pyplot as plt
import os
import pandas as pd
import random
from datetime import datetime, timedelta
import matplotlib.dates as dates
import matplotlib.colors as colors
import numpy as np
df2=pd.read_csv("Portperfdetails.csv")
df3 = df2.drop(df2.index[0])
df3['DATETIME'] = pd.to_datetime(df3['DATETIME'])
portname=list(dict.fromkeys(df3['PORT_NAME']))
for i in range(len(portname)):
X = []
Y = []
X = list(df3.loc[df3['PORT_NAME'] == '%s' % portname[i]]['DATETIME'])
Y = list(df3.loc[df3['PORT_NAME'] == '%s' % portname[i]]['TOTAL_MBYTES'])
ax = plt.axes()
ax.xaxis.set_minor_locator(dates.HourLocator(interval=4)) # every 4 hours
ax.xaxis.set_minor_formatter(dates.DateFormatter('%H:%M')) # hours and minutes
ax.xaxis.set_major_locator(dates.DayLocator(interval=1)) # every day
ax.xaxis.set_major_formatter(dates.DateFormatter('\n%d-%m-%Y'))
for i in range(len(Y)):
Y[i] = int(Y[i])
num_plots = 20
plt.plot(X, Y)
plt.ylabel('Port throughput')
plt.xlabel('Time')
plt.savefig('example.png')
Graph
I'll use a toy example since I do not have access to your data (df3).
I adapted this directly from the List of named colors example in the Matplotlib Gallery. The idea is to iterate over color names along with each line that is being plotted and use the color name to specify the color for each line.
from matplotlib import pyplot as plt
import matplotlib.colors as colors
fig, ax = plt.subplots()
lotsa_colors = colors.get_named_colors_mapping()
for cname,i in zip(lotsa_colors,range(50)):
y = [n for n in range(i,i+10)]
#print(cname,lotsa_colors[name])
ax.plot(y,color=lotsa_colors[cname])
plt.show()
#plt.close()
Looks like there are 1163 color names and 1105 unique colors
len(set(lotsa_colors.values()))
If you wanted to you could randomize the color names.
import random
lotsa_colors = colors.get_named_colors_mapping()
lotsa_colors = list(lotsa_colors.keys())
random.shuffle(lotsa_colors)

Python: Animated 3D Scatterplot gets slow

My program plots the positions of particles in my file for every time step. Unfortunately it gets slower and slower although I used matplotlib.animation. Where is the bottleneck?
My data file for two particles looks like the following:
# x y z
# t1 1 2 4
# 4 1 3
# t2 4 0 4
# 3 2 9
# t3 ...
My script:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation
# Number of particles
numP = 2
# Dimensions
DIM = 3
timesteps = 2000
with open('//home//data.dat', 'r') as fp:
particleData = []
for line in fp:
line = line.split()
particleData.append(line)
x = [float(item[0]) for item in particleData]
y = [float(item[1]) for item in particleData]
z = [float(item[2]) for item in particleData]
# Attaching 3D axis to the figure
fig = plt.figure()
ax = p3.Axes3D(fig)
# Setting the axes properties
border = 1
ax.set_xlim3d([-border, border])
ax.set_ylim3d([-border, border])
ax.set_zlim3d([-border, border])
def animate(i):
global x, y, z, numP
#ax.clear()
ax.set_xlim3d([-border, border])
ax.set_ylim3d([-border, border])
ax.set_zlim3d([-border, border])
idx0 = i*numP
idx1 = numP*(i+1)
ax.scatter(x[idx0:idx1],y[idx0:idx1],z[idx0:idx1])
ani = animation.FuncAnimation(fig, animate, frames=timesteps, interval=1, blit=False, repeat=False)
plt.show()
I would suggest to use pyqtgraph in this case. Citation from the docs:
Its primary goals are 1) to provide fast, interactive graphics for
displaying data (plots, video, etc.) and 2) to provide tools to aid in
rapid application development (for example, property trees such as
used in Qt Designer).
You can check out some examples after the installation:
import pyqtgraph.examples
pyqtgraph.examples.run()
This small code snippet generates 1000 random points and displays them in a 3D scatter plot by constantly updating the opacity, similar to the 3D scatter plot example in pyqtgraph.examples:
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph.opengl as gl
import numpy as np
app = QtGui.QApplication([])
w = gl.GLViewWidget()
w.show()
g = gl.GLGridItem()
w.addItem(g)
#generate random points from -10 to 10, z-axis positive
pos = np.random.randint(-10,10,size=(1000,3))
pos[:,2] = np.abs(pos[:,2])
sp2 = gl.GLScatterPlotItem(pos=pos)
w.addItem(sp2)
#generate a color opacity gradient
color = np.zeros((pos.shape[0],4), dtype=np.float32)
color[:,0] = 1
color[:,1] = 0
color[:,2] = 0.5
color[0:100,3] = np.arange(0,100)/100.
def update():
## update volume colors
global color
color = np.roll(color,1, axis=0)
sp2.setData(color=color)
t = QtCore.QTimer()
t.timeout.connect(update)
t.start(50)
## Start Qt event loop unless running in interactive mode.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
Small gif to give you an idea of the performance:
EDIT:
Displaying multiple points at every single time step is a little bit tricky since the gl.GLScatterPlotItem takes only (N,3)-arrays as point locations, see here. You could try to make a dictionary of ScatterPlotItems where each of them includes all time steps for a specific point. Then one would need to adapt the update function accordingly. You can find an example below where pos is an (100,10,3)-array representing 100 time steps for each point. I reduced the update time to 1000 ms for a slower animation.
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph.opengl as gl
import numpy as np
app = QtGui.QApplication([])
w = gl.GLViewWidget()
w.show()
g = gl.GLGridItem()
w.addItem(g)
pos = np.random.randint(-10,10,size=(100,10,3))
pos[:,:,2] = np.abs(pos[:,:,2])
ScatterPlotItems = {}
for point in np.arange(10):
ScatterPlotItems[point] = gl.GLScatterPlotItem(pos=pos[:,point,:])
w.addItem(ScatterPlotItems[point])
color = np.zeros((pos.shape[0],10,4), dtype=np.float32)
color[:,:,0] = 1
color[:,:,1] = 0
color[:,:,2] = 0.5
color[0:5,:,3] = np.tile(np.arange(1,6)/5., (10,1)).T
def update():
## update volume colors
global color
for point in np.arange(10):
ScatterPlotItems[point].setData(color=color[:,point,:])
color = np.roll(color,1, axis=0)
t = QtCore.QTimer()
t.timeout.connect(update)
t.start(1000)
## Start Qt event loop unless running in interactive mode.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
Keep in mind that in this examples, all points are shown in the scatter plot, however, the color opacity (4th dimension in the color array) is updated in every time step to get an animation. You could also try to update the points instead of the color to get better performance...
I would guess your bottleneck is calling ax.scatter and ax.set_xlim3d and similar in every frame in the animation.
Ideally, you should make a call to scatter once, then use the object returned by scatter and its set_... properties in the animate function (more details here).
I can't figure out how to do it with scatter, but if you use ax.plot(x, y, z, 'o') instead, you can then follow the demo method here.
Using some random data for x, y, z. It would work like this
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation
from numpy.random import random
# Number of particles
numP = 2
# Dimensions
DIM = 3
timesteps = 2000
x, y, z = random(timesteps), random(timesteps), random(timesteps)
# Attaching 3D axis to the figure
fig = plt.figure()
ax = p3.Axes3D(fig)
# Setting the axes properties
border = 1
ax.set_xlim3d([-border, border])
ax.set_ylim3d([-border, border])
ax.set_zlim3d([-border, border])
line = ax.plot(x[:1], y[:1], z[:1], 'o')[0]
def animate(i):
global x, y, z, numP
idx1 = numP*(i+1)
# join x and y into single 2 x N array
xy_data = np.c_[x[:idx1], y[:idx1]].T
line.set_data(xy_data)
line.set_3d_properties(z[:idx1])
ani = animation.FuncAnimation(fig, animate, frames=timesteps, interval=1, blit=False, repeat=False)
plt.show()

Categories

Resources