Say I have a simple pyplot:
import matplotlib.pyplot as plt
plt.plot([-1, -4.5, 3.14, 1])
plt.show()
Which generates the following:
How do I show all Integer points in the graph, so it looks like:
You can use plt.xlim/plt.ylim to get the limits and numpy.meshgrid to generate the points, then plt.scatter to plot them:
import matplotlib.pyplot as plt
plt.plot([-1, -4.5, 3.14, 1])
x0,x1 = plt.xlim()
y0,y1 = plt.ylim()
import numpy as np
X,Y = np.meshgrid(np.arange(round(x0), round(x1)+1),
np.arange(round(y0), round(y1)+1))
plt.scatter(X,Y)
output:
Here's a very primitive method.
import matplotlib.pyplot as plt
import numpy as np
plt.plot([-1, -4.5, 3.14, 1])
# Get interger points of x and y within the axes
xlim = np.round(plt.xlim(), 0)
list_x = np.arange(xlim[0], xlim[1]+1)
ylim = np.round(plt.ylim(), 0)
list_y = np.arange(ylim[0], ylim[1]+1)
# Get mesh grids for the points
mesh_x, mesh_y = np.meshgrid(list_x, list_y)
# Make grids to vectors
list_x = mesh_x.flatten()
list_y = mesh_y.flatten()
# Plot points
plt.plot(list_x, list_y, ls="none", marker=".")
plt.show()
import matplotlib.pyplot as plt
l = [-1, -4.5, 3.14, 1]
plt.plot(l)
integers = [[x, y] for x in range(len(l)) for y in range(math.floor(min(l)), math.ceil(max(l)))]
x_int_points, y_int_points = list(zip(*integers))
plt.scatter(x=x_int_points, y=y_int_points)
plt.show()
Generalized:
def plot_with_grid(l):
integers = [[x, y] for x in range(len(l)) \
for y in range(math.floor(min(l)),
math.ceil(max(l)))]
x_int_points, y_int_points = list(zip(*integers))
plt.plot(l)
plt.scatter(x=x_int_points, y=y_int_points)
plt.show()
Related
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)
I would like to generate a series of histogram shown below:
The above visualization was done in tensorflow but I'd like to reproduce the same visualization on matplotlib.
EDIT:
Using plt.fill_between suggested by #SpghttCd, I have the following code:
colors=cm.OrRd_r(np.linspace(.2, .6, 10))
plt.figure()
x = np.arange(100)
for i in range(10):
y = np.random.rand(100)
plt.fill_between(x, y + 10-i, 10-i,
facecolor=colors[i]
edgecolor='w')
plt.show()
This works great, but is it possible to use histogram instead of a continuous curve?
EDIT:
joypy based approach, like mentioned in the comment of october:
import pandas as pd
import joypy
import numpy as np
df = pd.DataFrame()
for i in range(0, 400, 20):
df[i] = np.random.normal(i/410*5, size=30)
joypy.joyplot(df, overlap=2, colormap=cm.OrRd_r, linecolor='w', linewidth=.5)
for finer control of colors, you can define a color gradient function which accepts a fractional index and start and stop color tuples:
def color_gradient(x=0.0, start=(0, 0, 0), stop=(1, 1, 1)):
r = np.interp(x, [0, 1], [start[0], stop[0]])
g = np.interp(x, [0, 1], [start[1], stop[1]])
b = np.interp(x, [0, 1], [start[2], stop[2]])
return (r, g, b)
Usage:
joypy.joyplot(df, overlap=2, colormap=lambda x: color_gradient(x, start=(.78, .25, .09), stop=(1.0, .64, .44)), linecolor='w', linewidth=.5)
Examples with different start and stop tuples:
original answer:
You could iterate over your dataarrays you'd like to plot with plt.fill_between, setting colors to some gradient and the line color to white:
creating some sample data:
import numpy as np
t = np.linspace(-1.6, 1.6, 11)
y = np.cos(t)**2
y2 = lambda : y + np.random.random(len(y))/5-.1
plot the series:
import matplotlib.pyplot as plt
import matplotlib.cm as cm
colors = cm.OrRd_r(np.linspace(.2, .6, 10))
plt.figure()
for i in range(10):
plt.fill_between(t+i, y2()+10-i/10, 10-i/10, facecolor = colors[i], edgecolor='w')
If you want it to have more optimized towards your example you should perhaps consider providing some sample data.
EDIT:
As I commented below, I'm not quite sure if I understand what you want - or if you want the best for your task. Therefore here a code which plots besides your approach in your edit two smples of how to present a bunch of histograms in a way that they are better comparable:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.cm as cm
N = 10
np.random.seed(42)
colors=cm.OrRd_r(np.linspace(.2, .6, N))
fig1 = plt.figure()
x = np.arange(100)
for i in range(10):
y = np.random.rand(100)
plt.fill_between(x, y + 10-i, 10-i,
facecolor=colors[i],
edgecolor='w')
data = np.random.binomial(20, .3, (N, 100))
fig2, axs = plt.subplots(N, figsize=(10, 6))
for i, d in enumerate(data):
axs[i].hist(d, range(20), color=colors[i], label=str(i))
fig2.legend(loc='upper center', ncol=5)
fig3, ax = plt.subplots(figsize=(10, 6))
ax.hist(data.T, range(20), color=colors, label=[str(i) for i in range(N)])
fig3.legend(loc='upper center', ncol=5)
This leads to the following plots:
your plot from your edit:
N histograms in N subplots:
N histograms side by side in one plot:
I have a set of Cartesian coordinates pairs, along with a binary variable for each of the pairs. I am plotting a heatmap, where in each bin, I compute the fraction of coordinates falling into this bin where the binary variable is 1.
My problem is with the axis. As can be seen in the picture below, the resulting axis are strings, that stand for bin boundaries. I would like the axis to be Cartesian coordinates. Is there a simple way to change this?
import numpy as np
import pandas as pd
import seaborn as sb
np.random.seed(0)
x = np.random.uniform(0,100, size=200)
y = np.random.uniform(0,100, size=200)
z = np.random.choice([True, False], size=200, p=[0.3, 0.7])
df = pd.DataFrame({"x" : x, "y" : y, "z":z})
binsx = 8
binsy = 5
res = df.groupby([pd.cut(df.y, binsy),pd.cut(df.x,binsx)])['z'].mean().unstack()
ax = sb.heatmap(res)
ax.axis('equal')
ax.invert_yaxis()
The following creates a scale by using the bins for histogramming as the extents of the image.
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
np.random.seed(0)
x = np.random.uniform(0,100, size=200)
y = np.random.uniform(0,100, size=200)
z = np.random.choice([True, False], size=200, p=[0.3, 0.7])
df = pd.DataFrame({"x" : x, "y" : y, "z":z})
binsx = np.arange(0,112.5,12.5)
binsy = np.arange(0,120,20)
res = df.groupby([pd.cut(df.y, binsy),pd.cut(df.x,binsx)])['z'].mean().unstack()
plt.imshow(res, cmap=plt.cm.Reds,
extent=[binsx.min(), binsx.max(),binsy.min(),binsy.max()])
plt.xticks(binsx)
plt.yticks(binsy)
plt.colorbar()
plt.grid(False)
plt.show()
I am trying to plot the comun distribution of two normal distributed variables.
The code below plots one normal distributed variable. What would the code be for plotting two normal distributed variables?
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.mlab as mlab
import math
mu = 0
variance = 1
sigma = math.sqrt(variance)
x = np.linspace(-3, 3, 100)
plt.plot(x,mlab.normpdf(x, mu, sigma))
plt.show()
It sounds like what you're looking for is a Multivariate Normal Distribution. This is implemented in scipy as scipy.stats.multivariate_normal. It's important to remember that you are passing a covariance matrix to the function. So to keep things simple keep the off diagonal elements as zero:
[X variance , 0 ]
[ 0 ,Y Variance]
Here is an example using this function and generating a 3D plot of the resulting distribution. I add the colormap to make seeing the curves easier but feel free to remove it.
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import multivariate_normal
from mpl_toolkits.mplot3d import Axes3D
#Parameters to set
mu_x = 0
variance_x = 3
mu_y = 0
variance_y = 15
#Create grid and multivariate normal
x = np.linspace(-10,10,500)
y = np.linspace(-10,10,500)
X, Y = np.meshgrid(x,y)
pos = np.empty(X.shape + (2,))
pos[:, :, 0] = X; pos[:, :, 1] = Y
rv = multivariate_normal([mu_x, mu_y], [[variance_x, 0], [0, variance_y]])
#Make a 3D plot
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, rv.pdf(pos),cmap='viridis',linewidth=0)
ax.set_xlabel('X axis')
ax.set_ylabel('Y axis')
ax.set_zlabel('Z axis')
plt.show()
Giving you this plot:
Edit the method used below was deprecated in Matplotlib v2.2 and removed in v3.1
A simpler version is available through matplotlib.mlab.bivariate_normal
It takes the following arguments so you don't need to worry about matrices
matplotlib.mlab.bivariate_normal(X, Y, sigmax=1.0, sigmay=1.0, mux=0.0, muy=0.0, sigmaxy=0.0)
Here X, and Y are again the result of a meshgrid so using this to recreate the above plot:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.mlab import bivariate_normal
from mpl_toolkits.mplot3d import Axes3D
#Parameters to set
mu_x = 0
sigma_x = np.sqrt(3)
mu_y = 0
sigma_y = np.sqrt(15)
#Create grid and multivariate normal
x = np.linspace(-10,10,500)
y = np.linspace(-10,10,500)
X, Y = np.meshgrid(x,y)
Z = bivariate_normal(X,Y,sigma_x,sigma_y,mu_x,mu_y)
#Make a 3D plot
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z,cmap='viridis',linewidth=0)
ax.set_xlabel('X axis')
ax.set_ylabel('Y axis')
ax.set_zlabel('Z axis')
plt.show()
Giving:
The following adaption to #Ianhi's code above returns a contour plot version of the 3D plot above.
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')
import numpy as np
from scipy.stats import multivariate_normal
#Parameters to set
mu_x = 0
variance_x = 3
mu_y = 0
variance_y = 15
x = np.linspace(-10,10,500)
y = np.linspace(-10,10,500)
X,Y = np.meshgrid(x,y)
pos = np.array([X.flatten(),Y.flatten()]).T
rv = multivariate_normal([mu_x, mu_y], [[variance_x, 0], [0, variance_y]])
fig = plt.figure(figsize=(10,10))
ax0 = fig.add_subplot(111)
ax0.contour(X, Y, rv.pdf(pos).reshape(500,500))
plt.show()
While the other answers are great, I wanted to achieve similar results while also illustrating the distribution with a scatter plot of the sample.
More details can be found here: Python 3d plot of multivariate gaussian distribution
The results looks like:
And is generated using the following code:
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from scipy.stats import multivariate_normal
# Sample parameters
mu = np.array([0, 0])
sigma = np.array([[0.7, 0.2], [0.2, 0.3]])
rv = multivariate_normal(mu, sigma)
sample = rv.rvs(500)
# Bounds parameters
x_abs = 2.5
y_abs = 2.5
x_grid, y_grid = np.mgrid[-x_abs:x_abs:.02, -y_abs:y_abs:.02]
pos = np.empty(x_grid.shape + (2,))
pos[:, :, 0] = x_grid
pos[:, :, 1] = y_grid
levels = np.linspace(0, 1, 40)
fig = plt.figure()
ax = fig.gca(projection='3d')
# Removes the grey panes in 3d plots
ax.xaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
ax.yaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
ax.zaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
# The heatmap
ax.contourf(x_grid, y_grid, 0.1 * rv.pdf(pos),
zdir='z', levels=0.1 * levels, alpha=0.9)
# The wireframe
ax.plot_wireframe(x_grid, y_grid, rv.pdf(
pos), rstride=10, cstride=10, color='k')
# The scatter. Note that the altitude is defined based on the pdf of the
# random variable
ax.scatter(sample[:, 0], sample[:, 1], 1.05 * rv.pdf(sample), c='k')
ax.legend()
ax.set_title("Gaussian sample and pdf")
ax.set_xlim3d(-x_abs, x_abs)
ax.set_ylim3d(-y_abs, y_abs)
ax.set_zlim3d(0, 1)
plt.show()
I have a data set which looks like this:
Intensity = ( [1, 2, 3, 4], [6, 7, 9, 10] )
Xposition = (0.1, 0.2, 0.3, 0.4)
Yposition = (1E^-9, 1.2E^-9)
So, for each Yposition, we have an 1D array stored in Intensity, corresponding to each Xposition.
Now I want to plot Xposition (X-axis), Yposition (Y-axis) and Intensity along Z to generate a 3D plot. How can I do this using matplotlib?
There are nice tutorials on matplotlib page. Looking at two examples and slightly tweaking the code:
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = (0.1,0.2,0.3,0.4)
y = (10**-9, 1.2*10**-9)
x,y = np.meshgrid(x,y)
z = ( [1,2,3,4], [6,7,9,10] )
ax.scatter(x, y, z)
plt.show()