Python Contour Plot/HeatMap - python

I have x and y coordinates in a df from LoL matches and i want to create a contour plot or heat map to show where the player normally moves in a match.
Does any one know how can I do it?

A contour plot or heat map needs 3 values. You have to provide x, y and z values in order to plot a contour since x and y give the position and z gives the value of the variable you want to show the contour of as a variable of x and y.
If you want to show the movement of the players as a function of time you should look at matplotlib's animations. Or if you want to show the "players density field" you have to calculate it.

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import scipy
from scipy.stats.kde import gaussian_kde
from scipy import ndimage
from matplotlib import cm
#select the x and y coordinates
x = df['x']
y = df['y']
nbins= 512
k = gaussian_kde(np.vstack([x,y]))
xi, yi = np.mgrid[0:512, 0:512] #size of the image/map in px
zi = k(np.vstack([xi.flatten(), yi.flatten()]))
im = mpimg.imread("map.png")#Put he background image
fig = plt.figure(figsize=(9,9))
ax2 = fig.add_subplot()
ax2.contourf(xi, yi, zi.reshape(xi.shape), alpha=0.5, cmap=cm.jet, extent=[1, -1, 1, -1])
ax2.set_xlim(0, 512)
ax2.set_ylim(0, 512)
ax2.axis('off')
plt.imshow(im, extent=[0, 512, 0, 512])
plt.savefig(f'Enemies/Clausura/{team}/{team} Stats/{summoner[1]} Early.png', dpi=None, bbox_inches='tight', pad_inches=0)

Related

How to convert a matrix to heatmap image in torch [duplicate]

Using Matplotlib, I want to plot a 2D heat map. My data is an n-by-n Numpy array, each with a value between 0 and 1. So for the (i, j) element of this array, I want to plot a square at the (i, j) coordinate in my heat map, whose color is proportional to the element's value in the array.
How can I do this?
The imshow() function with parameters interpolation='nearest' and cmap='hot' should do what you want.
Please review the interpolation parameter details, and see Interpolations for imshow and Image antialiasing.
import matplotlib.pyplot as plt
import numpy as np
a = np.random.random((16, 16))
plt.imshow(a, cmap='hot', interpolation='nearest')
plt.show()
Seaborn is a high-level API for matplotlib, which takes care of a lot of the manual work.
seaborn.heatmap automatically plots a gradient at the side of the chart etc.
import numpy as np
import seaborn as sns
import matplotlib.pylab as plt
uniform_data = np.random.rand(10, 12)
ax = sns.heatmap(uniform_data, linewidth=0.5)
plt.show()
You can even plot upper / lower left / right triangles of square matrices. For example, a correlation matrix, which is square and is symmetric, so plotting all values would be redundant.
corr = np.corrcoef(np.random.randn(10, 200))
mask = np.zeros_like(corr)
mask[np.triu_indices_from(mask)] = True
with sns.axes_style("white"):
ax = sns.heatmap(corr, mask=mask, vmax=.3, square=True, cmap="YlGnBu")
plt.show()
I would use matplotlib's pcolor/pcolormesh function since it allows nonuniform spacing of the data.
Example taken from matplotlib:
import matplotlib.pyplot as plt
import numpy as np
# generate 2 2d grids for the x & y bounds
y, x = np.meshgrid(np.linspace(-3, 3, 100), np.linspace(-3, 3, 100))
z = (1 - x / 2. + x ** 5 + y ** 3) * np.exp(-x ** 2 - y ** 2)
# x and y are bounds, so z should be the value *inside* those bounds.
# Therefore, remove the last value from the z array.
z = z[:-1, :-1]
z_min, z_max = -np.abs(z).max(), np.abs(z).max()
fig, ax = plt.subplots()
c = ax.pcolormesh(x, y, z, cmap='RdBu', vmin=z_min, vmax=z_max)
ax.set_title('pcolormesh')
# set the limits of the plot to the limits of the data
ax.axis([x.min(), x.max(), y.min(), y.max()])
fig.colorbar(c, ax=ax)
plt.show()
For a 2d numpy array, simply use imshow() may help you:
import matplotlib.pyplot as plt
import numpy as np
def heatmap2d(arr: np.ndarray):
plt.imshow(arr, cmap='viridis')
plt.colorbar()
plt.show()
test_array = np.arange(100 * 100).reshape(100, 100)
heatmap2d(test_array)
This code produces a continuous heatmap.
You can choose another built-in colormap from here.
Here's how to do it from a csv:
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
# Load data from CSV
dat = np.genfromtxt('dat.xyz', delimiter=' ',skip_header=0)
X_dat = dat[:,0]
Y_dat = dat[:,1]
Z_dat = dat[:,2]
# Convert from pandas dataframes to numpy arrays
X, Y, Z, = np.array([]), np.array([]), np.array([])
for i in range(len(X_dat)):
X = np.append(X, X_dat[i])
Y = np.append(Y, Y_dat[i])
Z = np.append(Z, Z_dat[i])
# create x-y points to be used in heatmap
xi = np.linspace(X.min(), X.max(), 1000)
yi = np.linspace(Y.min(), Y.max(), 1000)
# Interpolate for plotting
zi = griddata((X, Y), Z, (xi[None,:], yi[:,None]), method='cubic')
# I control the range of my colorbar by removing data
# outside of my range of interest
zmin = 3
zmax = 12
zi[(zi<zmin) | (zi>zmax)] = None
# Create the contour plot
CS = plt.contourf(xi, yi, zi, 15, cmap=plt.cm.rainbow,
vmax=zmax, vmin=zmin)
plt.colorbar()
plt.show()
where dat.xyz is in the form
x1 y1 z1
x2 y2 z2
...
Use matshow() which is a wrapper around imshow to set useful defaults for displaying a matrix.
a = np.diag(range(15))
plt.matshow(a)
https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.matshow.html
This is just a convenience function wrapping imshow to set useful defaults for displaying a matrix. In particular:
Set origin='upper'.
Set interpolation='nearest'.
Set aspect='equal'.
Ticks are placed to the left and above.
Ticks are formatted to show integer indices.
Here is a new python package to plot complex heatmaps with different kinds of row/columns annotations in Python: https://github.com/DingWB/PyComplexHeatmap

Interpolation for 3D surface

I have my data in an ndarray of size 21 by 30; it contains velocity values at each point. I have made a 3D surface plot to visualize it but the data is not so smooth. In order to interpolate the data, so that I have smooth peaks, I tried the function griddata but it does not seem to work.
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
vel = np.genfromtxt(r'velocity.txt')
x = np.arange(0, 21, 1)
y = np.arange(0, 30, 1)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X,Y = np.meshgrid(x, y)
surf = ax.plot_surface(x, y, vel, cmap="RdBu")
fig.set_size_inches(10, 10)
plt.show()
From what I can understand from the question, what you need to do is grid interpolation. It is possible to do that using RegularGridInterpolator from scipy here. Just make a finer mesh, interpolate on that grid, and plot.
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import RegularGridInterpolator
vel=np.random.random((21,30))
#grid old
x=np.arange(0,21,1)
y=np.arange(0,30,1)
grid_old=(x,y)
#grid new
# the limits of the interpolated x and y val have to be less than the original grid
x_new=np.arange(0.1,19.9,0.1)
y_new=np.arange(0.1,28.9,0.1)
grid_new = np.meshgrid(x_new, y_new)
grid_flattened = np.transpose(np.array([k.flatten() for k in grid_new]))
#Interpolation onto a finer grid
grid_interpol = RegularGridInterpolator(grid_old,vel,method='linear')
vel_interpol = grid_interpol(grid_flattened)
#Unflatten the interpolated velocities and store into a new variable.
index=0
vel_new=np.zeros((len(x_new),len(y_new)))
for i in range(len(x_new)):
for j in range(len(y_new)):
vel_new[i,j] =vel_interpol[index]
index+=1
fig=plt.figure()
ax=fig.add_subplot(111,projection='3d')
surf=ax.plot_surface(grid_new[0],grid_new[1],vel_new.T, cmap="RdBu")
fig.set_size_inches(10,10)
plt.show()

Confidence Interval 3 dimensional plot

I have a 3-dimensional plot and I am able to plot it with the code written below.
Considering that my point distribution is represented by a 100x100 matrix, is it possible to plot a confidence interval on my data? In the code below, my data are called "result", while the upper bound and lower bound that I want to show are called "upper_bound" and "lower_bound".
For example, I am asking if exist something like this, but in 3 dimension (instead of 2 dimension like the picture below)
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
interval = np.random.normal(0, 1, size=(100, 100))
x = np.arange(0.1,1.1,0.01)
y = np.linspace(-np.pi,np.pi,100)
X,Y = np.meshgrid(x,y)
result = []
for i,j in zip(X,Y):
result.append(np.log(i)+np.sin(j))
upper_bound = np.array(result)+interval
lower_bound = np.array(result)-interval
fig = plt.figure()
fig.set_figwidth(20)
fig.set_figheight(6)
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, np.array(result))
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
Check out this 3d surface plot using plotly graph objects:
import plotly.graph_objects as go
import numpy as np
x = np.arange(0.1,1.1,0.01)
y = np.linspace(-np.pi,np.pi,100)
X,Y = np.meshgrid(x,y)
result = []
for i,j in zip(X,Y):
result.append(np.log(i)+np.sin(j))
upper_bound = np.array(result)+1
lower_bound = np.array(result)-1
fig = go.Figure(data=[
go.Surface(z=result),
go.Surface(z=upper_bound, showscale=False, opacity=0.3,colorscale='purp'),
go.Surface(z=lower_bound, showscale=False, opacity=0.3,colorscale='purp'),
])
fig.show()
This plots 3 surfaces, the one for your results and the 2 bounds. However if you'd like something that looks more like a filled volume you'd have to add volume graphs with scaling opacity.

Python/Matplotlib: 2d random walk with kde joint density contour in a 3d plot

I'm struggling with creating a quite complex 3d figure in python, specifically using iPython notebook. I can partition the content of the graph into two sections:
The (x,y) plane: Here a two-dimensional random walk is bobbing around, let's call it G(). I would like to plot part of this trajectory on the (x,y) plane. Say, 10% of all the data points of G(). As G() bobs around, it visits some (x,y) pairs more frequently than others. I would like to estimate this density of G() using a kernel estimation approach and draw it as contour lines on the (x,y) plane.
The (z) plane: Here, I would like to draw a mesh or (transparent) surface plot of the information theoretical surprise of a bivariate normal. Surprise is simply -log(p(i)) or the negative (base 2) logarithm of outcome i. Given the bivariate normal, each (x,y) pair has some probability p(x,y) and the surprise of this is simply -log(p(x,y)).
Essentially these two graphs are independent. Assume the interval of the random walk G() is [xmin,xmax],[ymin,ymax] and of size N. The bivariate normal in the z-plane should be drawn from the same interval, such that for each (x,y) pair in the random walk, I can draw a (dashed) line from some subset of the random walk n < N to the bivariate normal. Assume that G(10) = (5,5) then I would like to draw a dashed line from (5,5) up the Z-axes, until it hits the bivariate normal.
So far, I've managed to plot G() in a 3-d space, and estimate the density f(X,Y) using scipy.stats.gaussian_kde. In another (2d) graph, I have the sort of contour lines I want. What I don't have, is the contour lines in the 3d-plot using the estimated KDE density. I also don't have the bivariate normal plot, or the projection of a few random points from the random walk, to the surface of the bivariate normal. I've added a hand drawn figure, which might ease intuition (ignore the label on the z-axis and the fact that there is no mesh.. difficult to draw!)
Any input, even just partial, such as how to draw the contour lines in the (x,y) plane of the 3d graph, or a mesh of a bivariate normal would be much appreciated.
Thanks!
import matplotlib as mpl
import matplotlib.pyplot as plt
import random
import numpy as np
import seaborn as sns
import scipy
from mpl_toolkits.mplot3d import Axes3D
%matplotlib inline
def randomwalk():
mpl.rcParams['legend.fontsize'] = 10
xyz = []
cur = [0, 0]
for _ in range(400):
axis = random.randrange(0, 2)
cur[axis] += random.choice([-1, 1])
xyz.append(cur[:])
x, y = zip(*xyz)
data = np.vstack([x,y])
kde = scipy.stats.gaussian_kde(data)
density = kde(data)
fig1 = plt.figure()
ax = fig1.gca(projection='3d')
ax.plot(x, y, label='Random walk')
sns.kdeplot(data[0,:], data[1,:], 0)
ax.scatter(x[-1], y[-1], c='b', marker='o') # End point
ax.legend()
fig2 = plt.figure()
sns.kdeplot(data[0,:], data[1,:])
Calling randomwalk() initialises and plots this:
Edit #1:
Made some progress, actually the only thing I need is to restrict the height of the dashed vertical lines to the bivariate. Any ideas?
import matplotlib as mpl
import matplotlib.pyplot as plt
import random
import numpy as np
import seaborn as sns
import scipy
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.mlab import bivariate_normal
%matplotlib inline
# Data for random walk
def randomwalk():
mpl.rcParams['legend.fontsize'] = 10
xyz = []
cur = [0, 0]
for _ in range(40):
axis = random.randrange(0, 2)
cur[axis] += random.choice([-1, 1])
xyz.append(cur[:])
# Get density
x, y = zip(*xyz)
data = np.vstack([x,y])
kde = scipy.stats.gaussian_kde(data)
density = kde(data)
# Data for bivariate gaussian
a = np.linspace(-7.5, 7.5, 20)
b = a
X,Y = np.meshgrid(a, b)
Z = bivariate_normal(X, Y)
surprise_Z = -np.log(Z)
# Get random points from walker and plot up z-axis to the gaussian
M = data[:,np.random.choice(20,5)].T
# Plot figure
fig = plt.figure(figsize=(10, 7))
ax = fig.gca(projection='3d')
ax.plot(x, y, 'grey', label='Random walk') # Walker
ax.scatter(x[-1], y[-1], c='k', marker='o') # End point
ax.legend()
surf = ax.plot_surface(X, Y, surprise_Z, rstride=1, cstride=1,
cmap = plt.cm.gist_heat_r, alpha=0.1, linewidth=0.1)
#fig.colorbar(surf, shrink=0.5, aspect=7, cmap=plt.cm.gray_r)
for i in range(5):
ax.plot([M[i,0], M[i,0]],[M[i,1], M[i,1]], [0,10],'k--',alpha=0.8, linewidth=0.5)
ax.set_zlim(0, 50)
ax.set_xlim(-10, 10)
ax.set_ylim(-10, 10)
Final code,
import matplotlib as mpl
import matplotlib.pyplot as plt
import random
import numpy as np
import seaborn as sns
import scipy
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.mlab import bivariate_normal
%matplotlib inline
# Data for random walk
def randomwalk():
mpl.rcParams['legend.fontsize'] = 10
xyz = []
cur = [0, 0]
for _ in range(50):
axis = random.randrange(0, 2)
cur[axis] += random.choice([-1, 1])
xyz.append(cur[:])
# Get density
x, y = zip(*xyz)
data = np.vstack([x,y])
kde = scipy.stats.gaussian_kde(data)
density = kde(data)
# Data for bivariate gaussian
a = np.linspace(-7.5, 7.5, 100)
b = a
X,Y = np.meshgrid(a, b)
Z = bivariate_normal(X, Y)
surprise_Z = -np.log(Z)
# Get random points from walker and plot up z-axis to the gaussian
M = data[:,np.random.choice(50,10)].T
# Plot figure
fig = plt.figure(figsize=(10, 7))
ax = fig.gca(projection='3d')
ax.plot(x, y, 'grey', label='Random walk') # Walker
ax.legend()
surf = ax.plot_surface(X, Y, surprise_Z, rstride=1, cstride=1,
cmap = plt.cm.gist_heat_r, alpha=0.1, linewidth=0.1)
#fig.colorbar(surf, shrink=0.5, aspect=7, cmap=plt.cm.gray_r)
for i in range(10):
x = [M[i,0], M[i,0]]
y = [M[i,1], M[i,1]]
z = [0,-np.log(bivariate_normal(M[i,0],M[i,1]))]
ax.plot(x,y,z,'k--',alpha=0.8, linewidth=0.5)
ax.scatter(x, y, z, c='k', marker='o')

how to rotate a 3D surface in matplotlib

I have written code to plot a 3D surface of a parabaloid in matplotlib.
How would I rotate the figure so that the figure remains in place (i.e. no vertical or horizontal shifts) however it rotates around the line y = 0 and z = 0 through an angle of theta ( I have highlighted the line about which the figure should rotate in green). Here is an illustration to help visualize what I am describing:
For example, If the figure were rotated about the line through an angle of 180 degrees then this would result in the figure being flipped 'upside down' so that the point at the origin would be now be the maximum point.
I would also like to rotate the axis so that the colormap is maintained.
Here is the code for drawing the figure:
#parabaloid
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#creating grid
y = np.linspace(-1,1,1000)
x = np.linspace(-1,1,1000)
x,y = np.meshgrid(x,y)
#set z values
z = x**2+y**2
#label axes
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
#plot figure
ax.plot_surface(x,y,z,linewidth=0, antialiased=False, shade = True, alpha = 0.5)
plt.show()
Something like this?
ax.view_init(-140, 30)
Insert it just before your plt.show() command.
Following my comment:
import mayavi.mlab as mlab
import numpy as np
x,y = np.mgrid[-1:1:0.001, -1:1:0.001]
z = x**2+y**2
s = mlab.mesh(x, y, z)
alpha = 30 # degrees
mlab.view(azimuth=0, elevation=90, roll=-90+alpha)
mlab.show()
or following #Tamas answer:
#parabaloid
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from math import sin, cos, pi
import matplotlib.cm as cm
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#creating grid
y = np.linspace(-1,1,200)
x = np.linspace(-1,1,200)
x,y = np.meshgrid(x,y)
#set z values
z0 = x**2+y**2
# rotate the samples by pi / 4 radians around y
a = pi / 4
t = np.transpose(np.array([x,y,z0]), (1,2,0))
m = [[cos(a), 0, sin(a)],[0,1,0],[-sin(a), 0, cos(a)]]
x,y,z = np.transpose(np.dot(t, m), (2,0,1))
# or `np.dot(t, m)` instead `t # m`
#label axes
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
#plot figure
ax.plot_surface(x,y,z,linewidth=0, antialiased=False, shade = True, alpha = 0.5, facecolors=cm.viridis(z0))
plt.show()
The best I could come up with is to rotate the data itself.
#parabaloid
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from math import sin, cos, pi
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#creating grid
y = np.linspace(-1,1,200)
x = np.linspace(-1,1,200)
x,y = np.meshgrid(x,y)
#set z values
z = x**2+y**2
# rotate the samples by pi / 4 radians around y
a = pi / 4
t = np.transpose(np.array([x,y,z]), (1,2,0))
m = [[cos(a), 0, sin(a)],[0,1,0],[-sin(a), 0, cos(a)]]
x,y,z = np.transpose(t # m, (2,0,1))
# or `np.dot(t, m)` instead `t # m`
#label axes
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
#plot figure
ax.plot_surface(x,y,z,linewidth=0, antialiased=False, shade = True, alpha = 0.5)
plt.show()
I can't seem to add a comment just yet but I wanted to make an amendment to Tamas' implementation. There is an issue where the surface is not rotated counter-clockwise to the axis (the y-axis in this case) where the y-axis is coming out of the page. Rather, it's rotated clockwise.
In order to rectify this, and to make it more straightforward, I construct the x, y and z grids and reshape them into straightforward lists on which we perform the rotation. Then I reshape them into grids in order to use the plot_surface() function:
import numpy as np
from matplotlib import pyplot as plt
from math import sin, cos, pi
import matplotlib.cm as cm
num_steps = 50
# Creating grid
y = np.linspace(-1,1,num_steps)
x = np.linspace(-1,1,num_steps)
x,y = np.meshgrid(x,y)
# Set z values
z = x**2+y**2
# Work with lists
x = x.reshape((-1))
y = y.reshape((-1))
z = z.reshape((-1))
# Rotate the samples by pi / 4 radians around y
a = pi / 4
t = np.array([x, y, z])
m = [[cos(a), 0, sin(a)],[0,1,0],[-sin(a), 0, cos(a)]]
x, y, z = np.dot(m, t)
ax = plt.axes(projection='3d')
# Label axes
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
# Plot the surface view it with y-axis coming out of the page.
ax.view_init(30, 90)
# Plot the surface.
ax.plot_surface(x.reshape(num_steps,num_steps), y.reshape(num_steps,num_steps), z.reshape(num_steps,num_steps));
here is the best solution:
- First, you have to perform your python script in the Spyder environment which is easy to get by downloading Anaconda. Once you perform your script in Spyder, all you have to do is to follow the next instructions:
Click on “Tools”.
Click on “Preferences”.
Click on “IPython console”.
Click on “Graphics”.
Here you’ll find an option called “Backend”, you have to change it from “Inline” to “Automaticlly”.
Finally, apply the performed changes, then Click on “OK”, and reset spyder!!!!.
Once you perform the prior steps, in theory, if you run your script, then the graphics created will appear in a different windows and you could interact with them through zooming and panning. In the case of 3d plots (3d surface) you will be able to orbit it.

Categories