If you look in the logarithmic radar chart below, there are two changes I would like, if anyone knows the correct way to code:
1)Display a ytick label for the max value (51.81), as it currently gives the top value as 31.62
2)A way to set all values below 0.1 to 0, without causing divide by zero errors.
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, polar=True)
np.seterr(divide = 'warn')
sample = samplelistmalshare
get_mag = lambda x: 10**min(np.floor(np.log10(x)))
init_mag = get_mag(sample)
print("init_mag")
print(init_mag)
print("gm")
print(get_mag)
sample = np.array(sample) / get_mag(sample)
N = len(sample)
theta = np.arange(0, 2 * np.pi, 2 * np.pi / N)
bars = ax.bar(theta, np.log10(sample), width=0.4, color = '#003F5C')
ax.set_xticks(theta)
ax.set_xticklabels([' Delayed\n Execution', ' File\n Opening', 'Firewall\nModification', 'Permission \nModification ', 'Persistence ', 'Proxied \nExecution ', 'Reconnaissance ', ' Registry\n Modification', ' Task\n Stopping'], visible=False)
dat = np.log10(sample)
print(max(dat))
#exit()
ax.set_ylim(0,max(dat))
ax.xaxis.grid(False)
ax.yaxis.grid(True)
precision = 2 # Change to your desired decimal precision
ax.set_yticklabels([str(round((10 ** x) * init_mag, precision)) for x in ax.get_yticks()])
for test in ax.get_yticks():
print(test)
for test in ax.get_ymajorticklabels():
print(test)
ax.set_rlabel_position(50)
plt.savefig('radarchartingmalshare.pdf',bbox_inches='tight')
fig.clf()
plt.clf()
One solution is to set yticks and yticklabels manually
right_end = 51.81
ax.set_ylim(0,np.log10(right_end / init_mag))
y_ticks = np.linspace(0,np.log10(right_end/init_mag),10)
ax.set_yticks(y_ticks)
y_ticklabels = ['%.2f' % (init_mag*10**x) if x !=0 else '0.00' for x in ax.get_yticks()]
ax.set_yticklabels(y_ticklabels)
With this manually set ticks and the labels
import numpy as np
from matplotlib import pyplot as plt
fig = plt.figure(figsize=(8, 8));
ax = fig.add_subplot(111, polar=True)
np.seterr(divide = 'warn')
sample = [35.417256011315416,0.028288543140028287,1.3578500707213579,3.3663366336633667,
0.8203677510608205,35.445544554455445,3.3946251768033946,19.46251768033946,0.7072135785007072,]
get_mag = lambda x: 10**min(np.floor(np.log10(x)))
init_mag = get_mag(sample)
sample = np.array(sample) / get_mag(sample)
dat = np.log10(sample)
N = len(sample)
theta = np.arange(0, 2 * np.pi, 2 * np.pi / N)
bars = ax.bar(theta, dat, width=0.4, color = 'deepskyblue')
ax.set_xticks(theta)
ax.xaxis.grid(False)
right_end = 51.81
ax.set_ylim(0,np.log10(right_end / init_mag))
ax.yaxis.grid(True)
y_ticks = np.linspace(0,np.log10(right_end/init_mag),10)
ax.set_yticks(y_ticks)
y_ticklabels = ['%.2f' % (init_mag*10**x) if x !=0 else '0.00' for x in ax.get_yticks()]
ax.set_yticklabels(y_ticklabels)
ax.tick_params(axis='y',colors='darkviolet')
plt.show()
I'm drawing several contour lines over a basemap projection as shown in the following figure:.
There are 3 contours that are not drawn completely (in Oregon, Washington and California) and seems like there is this line that has cut all 3 of them in the same latitude. I'm not sure how to solve this problem.
I added the number of interpolation points, didn't help. changed the ll and ur points to include more area didn't help.
The code is below (not reproducible but might help):
def visualise_bigaus(mus, sigmas, corxys , output_type='pdf', **kwargs):
lllat = 24.396308
lllon = -124.848974
urlat = 49.384358
urlon = -66.885444
fig = plt.figure(figsize=(4, 2.5))
ax = fig.add_subplot(111, axisbg='w', frame_on=False)
m = Basemap(llcrnrlat=lllat,
urcrnrlat=urlat,
llcrnrlon=lllon,
urcrnrlon=urlon,
resolution='i', projection='cyl')
m.drawmapboundary(fill_color = 'white')
#m.drawcoastlines(linewidth=0.2)
m.drawcountries(linewidth=0.2)
m.drawstates(linewidth=0.2, color='lightgray')
#m.fillcontinents(color='white', lake_color='#0000ff', zorder=2)
#m.drawrivers(color='#0000ff')
m.drawlsmask(land_color='gray',ocean_color="#b0c4de", lakes=True)
lllon, lllat = m(lllon, lllat)
urlon, urlat = m(urlon, urlat)
mlon, mlat = m(*(mus[:,1], mus[:,0]))
numcols, numrows = 1000, 1000
X = np.linspace(mlon.min(), urlon, numcols)
Y = np.linspace(lllat, urlat, numrows)
X, Y = np.meshgrid(X, Y)
m.scatter(mlon, mlat, s=0.2, c='red')
shp_info = m.readshapefile('./data/us_states_st99/st99_d00','states',drawbounds=True, zorder=0)
printed_names = []
ax = plt.gca()
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
for spine in ax.spines.itervalues():
spine.set_visible(False)
for k in xrange(mus.shape[0]):
#here x is longitude and y is latitude
#apply softplus to sigmas (to make them positive)
sigmax=np.log(1 + np.exp(sigmas[k][1]))
sigmay=np.log(1 + np.exp(sigmas[k][0]))
mux=mlon[k]
muy=mlat[k]
corxy = corxys[k]
#apply the soft sign
corxy = corxy / (1 + np.abs(corxy))
#now given corxy find sigmaxy
sigmaxy = corxy * sigmax * sigmay
#corxy = 1.0 / (1 + np.abs(sigmaxy))
Z = mlab.bivariate_normal(X, Y, sigmax=sigmax, sigmay=sigmay, mux=mux, muy=muy, sigmaxy=sigmaxy)
#Z = maskoceans(X, Y, Z)
con = m.contour(X, Y, Z, levels=[0.02], linewidths=0.5, colors='darkorange', antialiased=True)
'''
num_levels = len(con.collections)
if num_levels > 1:
for i in range(0, num_levels):
if i != (num_levels-1):
con.collections[i].set_visible(False)
'''
contour_labels = False
if contour_labels:
plt.clabel(con, [con.levels[-1]], inline=True, fontsize=10)
'''
world_shp_info = m.readshapefile('./data/CNTR_2014_10M_SH/Data/CNTR_RG_10M_2014','world',drawbounds=False, zorder=100)
for shapedict,state in zip(m.world_info, m.world):
if shapedict['CNTR_ID'] not in ['CA', 'MX']: continue
poly = MplPolygon(state,facecolor='gray',edgecolor='gray')
ax.add_patch(poly)
'''
if iter:
iter = str(iter).zfill(3)
else:
iter = ''
plt.tight_layout()
plt.savefig('./maps/video/gaus_' + iter + '.' + output_type, frameon=False, dpi=200)
The problem is the meshgrid not covering the complete map. The meshgrid simply doesn't have any points at the positions where you want to draw the gaussian contour line.
An example to reproduce this behaviour is the following, where the meshgrid in x directio starts at -1, such that points lower than that are not drawn.
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import numpy as np
fig, ax=plt.subplots()
ax.plot([-2,2],[-2,-2], alpha=0)
X,Y = np.meshgrid(np.linspace(-1,2),np.linspace(-2,2))
Z = mlab.bivariate_normal(X, Y, sigmax=1., sigmay=1., mux=0.1, muy=0.1, sigmaxy=0)
con = ax.contour(X, Y, Z, levels=[Z.max()/3, Z.max()/2., Z.max()*0.8],colors='darkorange')
plt.show()
A similar problem occurs in the code from the question.
While in Y direction, you use the complete map, Y = np.linspace(lllat, urlat, numrows), in X direction you restrict the mesh to start at mlon.min(),
X = np.linspace(mlon.min(), urlon, numcols)
The solution would of course be not to start the mesh in Portland, but somewhere in the ocean, i.e. at the edge of the shown map.
I know the question is not very informative.. but as I do not know the name of his type of plot, I can not be more informative..
[EDIT] I changed the title, and now it is more informative...
You can do something similar with seaborn.swarmplot. I also use seaborn.boxplot (with the whiskers and caps turned off) to plot the mean and range:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style("whitegrid")
tips = sns.load_dataset("tips")
ax = sns.swarmplot(x="day", y="total_bill", data=tips)
ax = sns.boxplot(x="day", y="total_bill", data=tips,
showcaps=False,boxprops={'facecolor':'None'},
showfliers=False,whiskerprops={'linewidth':0})
plt.show()
If (for whatever reason) you don't want to use seaborn, you can have a go at making them yourself (see e.g. this explanation: https://www.flerlagetwins.com/2020/11/beeswarm.html ).
A simple version is:
#!/usr/bin/env python3
import matplotlib.pyplot as plt
import numpy as np
def simple_beeswarm(y, nbins=None):
"""
Returns x coordinates for the points in ``y``, so that plotting ``x`` and
``y`` results in a bee swarm plot.
"""
y = np.asarray(y)
if nbins is None:
nbins = len(y) // 6
# Get upper bounds of bins
x = np.zeros(len(y))
ylo = np.min(y)
yhi = np.max(y)
dy = (yhi - ylo) / nbins
ybins = np.linspace(ylo + dy, yhi - dy, nbins - 1)
# Divide indices into bins
i = np.arange(len(y))
ibs = [0] * nbins
ybs = [0] * nbins
nmax = 0
for j, ybin in enumerate(ybins):
f = y <= ybin
ibs[j], ybs[j] = i[f], y[f]
nmax = max(nmax, len(ibs[j]))
f = ~f
i, y = i[f], y[f]
ibs[-1], ybs[-1] = i, y
nmax = max(nmax, len(ibs[-1]))
# Assign x indices
dx = 1 / (nmax // 2)
for i, y in zip(ibs, ybs):
if len(i) > 1:
j = len(i) % 2
i = i[np.argsort(y)]
a = i[j::2]
b = i[j+1::2]
x[a] = (0.5 + j / 3 + np.arange(len(b))) * dx
x[b] = (0.5 + j / 3 + np.arange(len(b))) * -dx
return x
fig = plt.figure(figsize=(2, 4))
fig.subplots_adjust(0.2, 0.1, 0.98, 0.99)
ax = fig.add_subplot(1, 1, 1)
y = np.random.gamma(20, 10, 100)
x = simple_beeswarm(y)
ax.plot(x, y, 'o')
fig.savefig('bee.png')
I have points plotted in 3D space, with four polygons that slice through the data cube at angles to the y and x axes.
I would like to, for each black data point in the box, work out the coordinates of the vertices of a square centred on the data point. Using these coordinates I can draw a polgyon, in the same way that I am doing now. The dimensions of this square would need to be the same as the width value defined on line 7. The square drawn must be inclined so it lies exactly on the existing plotted plane.
Does anybody know the best way to approach this? The other difficult thing would be that, if the square leaves the box, it should wrap round the other side of the box. The box can be stacked horizontallyand vertically with identical boxes, tiling infinitely.
My code can be found belw (sorry it's messy):
import matplotlib.pyplot as pyplot
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
angle = np.arctan2(1,4)
xangle = np.arctan2(1,4)
width = 100/np.cos(angle)
print 'angle:', angle*(180/np.pi)
print 'xangle:', xangle*(180/np.pi)
print 'width:', width
x1 = [0, 0, 0, 0, 50, 50, 50, 50]
y1 = [50,50,50,50,50,50,50,50]
z1 = [12.5,37.5,62.5,87.5,25,50,75,0]
x2 = [0,0,0,0,0,0,0,0,50,50,50,50,50,50,50,50]
y2 = [0,50,0,50,0,50,0,50,0,50,0,50,0,50,0,50]
z2 = [0,12.5,25,37.5,50,62.5,75,87.5,12.5,25,37.5,50,62.5,75,87.5,0]
fig = pyplot.figure()
ax = fig.add_subplot(111, projection = '3d')
ax.set_xlim(0,100)
ax.set_ylim(0,100)
ax.set_zlim(0,100)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
#ax.view_init(elev=90, azim=90)
#ax.scatter(x1, y1, z1, zdir='z', s=20, c='g')
ax.scatter(x2, y2, z2, zdir='z', s=20, c='r') #THESE ARE RICHARD'S COORDINATES notice how they do not lie on the plane
xa = [0,100,100,0]
ya = [0,0,100,100]
za = [0,-6.25,18.75,25]
verts = [zip(xa,ya,za)]
ax.add_collection3d(Poly3DCollection(verts))
xb = [0,100,100,0]
yb = [0,0,100,100]
zb = [25,-6.25+25,18.75+25,50]
verts = [zip(xb,yb,zb)]
ax.add_collection3d(Poly3DCollection(verts))
xc = [0,100,100,0]
yc = [0,0,100,100]
zc = [50,-6.25+25*2,18.75+25*2,75]
verts = [zip(xc,yc,zc)]
ax.add_collection3d(Poly3DCollection(verts))
xd = [0,100,100,0]
yd = [0,0,100,100]
zd = [75,-6.25+25*3,18.75+25*3,100]
verts = [zip(xd,yd,zd)]
ax.add_collection3d(Poly3DCollection(verts))
#pyplot.show()
x = [0]
y = [0]
z = [0]
for i in range(1,100):
new_x = x[(len(x)-1)] + 50
new_y = y[(len(y)-1)] + 12.5
new_z = z[(len(z)-1)]
if new_x >= 100:
new_x = new_x - 100
new_z = new_z + 6.25
if new_y >= 100:
new_y = new_y - 100
if new_z >= 100:
new_z = new_z - 100
if new_x == 0 and new_y == 0 and new_z == 0:
print 'done!', i
x.append(new_x)
y.append(new_y)
z.append(new_z)
ax.scatter(x, y, z, zdir='z', s=20, c='k', zorder=1)
pyplot.show()
Done! (Without wrapping around the box though..)
import matplotlib.pyplot as pyplot
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import random
angle = np.arctan2(1,4)
xangle = np.arctan2(1,4)
width = 100/np.cos(angle)
print 'angle:', angle*(180/np.pi)
print 'xangle:', xangle*(180/np.pi)
print 'width:', width
def totuple(a):
try:
return tuple(totuple(i) for i in a)
except TypeError:
return a
def plotSquare(ax,cx,cy,cz, yaw, pitch, diameter):
colour1 = random.randint(0,255)/256.0
colour2 = random.randint(0,255)/256.0
colour3 = random.randint(0,255)/256.0
centre = np.array([cx,cy,cz])
radius = diameter/2
#0,0,0 to 100,25,125 diff
#100,25,125 /2
#50,12.5,62.5 /50
#1.0,0.25,1.25
d1offset = np.array([np.cos(pitch)*radius,(np.cos(yaw)*radius)+(np.sin(pitch)*radius),np.sin(yaw)*radius])
c1 = centre - d1offset
c2 = centre + d1offset
#100,0,25 to 0,25,100 diff
#-100,25,75 /2
#-50,12.5,37.5 /50
#-1.0,0.25,0.75
d2offset = np.array([-np.cos(yaw)*radius,(np.cos(pitch)*radius)-(np.sin(yaw)*radius),np.sin(pitch)*radius])
c3 = centre - d2offset
c4 = centre + d2offset
verts = [[totuple(c1),totuple(c3),totuple(c2),totuple(c4)]]
ax.add_collection3d(Poly3DCollection(verts, facecolors=[colour1,colour2,colour3]))
x1 = [0, 0, 0, 0, 50, 50, 50, 50]
y1 = [50,50,50,50,50,50,50,50]
z1 = [12.5,37.5,62.5,87.5,25,50,75,0]
x2 = [0,0,0,0,0,0,0,0,50,50,50,50,50,50,50,50]
y2 = [0,50,0,50,0,50,0,50,0,50,0,50,0,50,0,50]
z2 = [0,12.5,25,37.5,50,62.5,75,87.5,12.5,25,37.5,50,62.5,75,87.5,0]
fig = pyplot.figure()
ax = fig.add_subplot(111, projection = '3d')
ax.set_xlim(0,100)
ax.set_ylim(0,100)
ax.set_zlim(0,100)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
#ax.view_init(elev=90, azim=90)
#ax.scatter(x1, y1, z1, zdir='z', s=20, c='g')
ax.scatter(x2, y2, z2, zdir='z', s=20, c='r') #EXISTING COORDINATES notice how they do not lie on the plane
xa = [0,100,100,0]
ya = [0,0,100,100]
za = [0,-6.25,18.75,25]
verts = [zip(xa,ya,za)]
ax.add_collection3d(Poly3DCollection(verts))
xb = [0,100,100,0]
yb = [0,0,100,100]
zb = [25,-6.25+25,18.75+25,50]
verts = [zip(xb,yb,zb)]
ax.add_collection3d(Poly3DCollection(verts))
xc = [0,100,100,0]
yc = [0,0,100,100]
zc = [50,-6.25+25*2,18.75+25*2,75]
verts = [zip(xc,yc,zc)]
ax.add_collection3d(Poly3DCollection(verts))
xd = [0,100,100,0]
yd = [0,0,100,100]
zd = [75,-6.25+25*3,18.75+25*3,100]
verts = [zip(xd,yd,zd)]
ax.add_collection3d(Poly3DCollection(verts))
x = [0]
y = [0]
z = [0]
for i in range(1,100):
new_x = x[(len(x)-1)] + 50
new_y = y[(len(y)-1)] + 12.5
new_z = z[(len(z)-1)]
if new_x >= 100:
new_x = new_x - 100
new_z = new_z + 6.25
#new_y = new_y + (50-12.5)
if new_y >= 100:
new_y = new_y - 100
if new_z >= 100:
new_z = new_z - 100
if new_x == 0 and new_y == 0 and new_z == 0:
print 'done!', i
x.append(new_x)
y.append(new_y)
z.append(new_z)
ax.scatter(x, y, z, zdir='z', s=20, c='k', zorder=1)
storedcoordinates = zip(x,y,z)
for x,y,z in storedcoordinates:
plotSquare(ax,x,y,z,xangle,angle, width/2)
pyplot.show()
I have been researching on how to animate multiple lines for a flight path. The object it that I read multiple GPS files time sync them them animate each path with respect to time. I found how to animate one line using append in the animate functions. Now I need to add a second and third for as many files are imported.
I know the problem is somewhere in how I perform the set_data with the lines. I ahve seen multiple example but I do not understand what structure is required to set up multiple lines. Yes I am a newbie.
fig = plt.figure()
ax1 = plt.axes(xlim=(-108, -104), ylim=(31,34))
line, = ax1.plot([], [], lw=2)
plt.xlabel('Longitude')
plt.ylabel('Latitude')
plotlays, plotcols = [2], ["black","red"]
lines = []
for index in range(2):
lobj = ax1.plot([],[],lw=2,color=plotcols[index])[0]
lines.append(lobj)
def init():
for line in lines:
line.set_data([],[])
return lines
x1,y1 = [],[]
x2,y2 = [],[]
frame_num = len(gps_data[0])
# animation function. This is called sequentially
def animate(i):
x = gps_data[0][i,3]
y = gps_data[0][i,2]
x1.append(x)
y1.append(y)
x = gps_data[1][i,3]
y = gps_data[1][i,2]
x2.append(x)
y2.append(y)
#X = np.array(x1, x2)
#Y = np.array(y1, y2)
#for index in range(0,1):
for lnum,line in enumerate(lines):
line.set_data([x1,y1, x2,y2])
return lines,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=frame_num, interval=1, blit=True)
plt.show()
The Matplotlib documentation for the line2d artist explains how set_data works. It "ACCEPTS: 2D array (rows are x, y) or two 1D arrays." It also works with lists. You've given it a four element list instead. You need to set the x and y data of each line separately. I've included an example with fake data below.
import matplotlib.pyplot as plt
from matplotlib import animation
from numpy import random
fig = plt.figure()
ax1 = plt.axes(xlim=(-108, -104), ylim=(31,34))
line, = ax1.plot([], [], lw=2)
plt.xlabel('Longitude')
plt.ylabel('Latitude')
plotlays, plotcols = [2], ["black","red"]
lines = []
for index in range(2):
lobj = ax1.plot([],[],lw=2,color=plotcols[index])[0]
lines.append(lobj)
def init():
for line in lines:
line.set_data([],[])
return lines
x1,y1 = [],[]
x2,y2 = [],[]
# fake data
frame_num = 100
gps_data = [-104 - (4 * random.rand(2, frame_num)), 31 + (3 * random.rand(2, frame_num))]
def animate(i):
x = gps_data[0][0, i]
y = gps_data[1][0, i]
x1.append(x)
y1.append(y)
x = gps_data[0][1,i]
y = gps_data[1][1,i]
x2.append(x)
y2.append(y)
xlist = [x1, x2]
ylist = [y1, y2]
#for index in range(0,1):
for lnum,line in enumerate(lines):
line.set_data(xlist[lnum], ylist[lnum]) # set data for each line separately.
return lines
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=frame_num, interval=10, blit=True)
plt.show()
fig, ax1 = plt.subplots(figsize=(20,10))
plt.xticks()
ax1.set_xlabel("time")
ax1.set_ylabel("amp")
ax1.grid(True)
ox = get_data_o("/tmp/bf_ox.npy")
oy = get_data_o("/tmp/bf_oy.npy")
graphic_data = []
graphic_data.append(ax1.plot(ox, oy,"b-")[0])
sx = get_data_o("/tmp/bf_sx.npy")
i = 1
for p in sp.procs:
c = get_c(i)
sy = get_data_o("/tmp/bf_" + p + ".npy")
graphic_data.append(ax1.plot(sx, sy,c + "-")[0])
i = i + 1
def animate(i):
print ("frame")
ox = get_data_o("/tmp/bf_ox.npy")
oy = get_data_o("/tmp/bf_oy.npy")
i = 0
graphic_data[i].set_xdata(ox)
graphic_data[i].set_ydata(oy)
i = 1
sx = get_data_o("/tmp/bf_sx.npy")
for p in sp.procs:
sy = get_data_o("/tmp/bf_" + p + ".npy")
graphic_data[i].set_xdata(sx)
graphic_data[i].set_ydata(sy)
i = i + 1
return graphic_data
ani = animation.FuncAnimation(fig, animate, interval=2000, blit=True)
plt.show()