Draw path on heatmap Python - python

I have a vector x with length N=n**2=625 which I simply plot with imshow by reshaping into a matrix, which is essentially a 2D topographical map.
plt.imshow(x.reshape((n,n)),cmap="magma",origin="lower")
I also have a given connected path with the some indices of the vector x, e.g
path = np.array([1, 2, 27, 28, 54,55,56,81,106,131])
I want to display this on top of the heatmap with lines, to indicate the path. Any ideas on how I can to this?

IIUC, you can use numpy.unravel_index to convert your coordinates:
import matplotlib.pyplot as plt
n=25
x = np.arange(n**2)
ax = plt.imshow(x.reshape((n,n)),cmap="magma",origin="lower", alpha=0.2)
X, Y = np.unravel_index(np.array([1, 2, 27, 28, 54,55,56,81,106,131]), (n, n))
plt.plot(Y, X)
Example:

Related

How to numerically compute the mass map and density map for a collection of masses?

Good day to everyone. I was wondering if there is any way to extract a mass map and a mass density map for a scatter plot of mass distributions.
Developing the code for the mass distributions:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy.ndimage.filters import gaussian_filter
from numpy.random import rand
# Finds nran number of random points in two dimensions
def randomizer(nran):
arr = rand(nran, 2)
return arr
# Calculates a sort of 'density' plot. Using this from a previous StackOverflow Question: https://stackoverflow.com/questions/2369492/generate-a-heatmap-in-matplotlib-using-a-scatter-data-set
def myplot(x, y, s, bins = 1000):
plot, xedges, yedges = np.histogram2d(x, y, bins = bins)
plot = gaussian_filter(plot, sigma = s)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
return plot.T, extent
Trying out an example:
arr = randomizer(1000)
plot, extent = myplot(arr[:, 0], arr[:, 1], 20)
fig, ax = plt.subplots(1, 2, figsize = (15, 5))
ax[0].scatter(arr[:, 0], arr[:, 1])
ax[0].set_aspect('equal')
ax[0].set_xlabel('x')
ax[0].set_ylabel('y')
ax[0].set_title('Scatter Plot')
img = ax[1].imshow(plot)
ax[1].set_title('Density Plot?')
ax[1].set_aspect('equal')
ax[1].set_xlabel('x')
ax[1].set_ylabel('y')
plt.colorbar(img)
This yields a scatter plot and what I think kind of represents a density plot (please correct if wrong). Now, suppose that each dot has a mass of 50 kg. Does the "density plot" represent a map of the total mass distribution (if that makes sense?)since the colorbar has a max value much less than 50. Then, using this, how can I compute a mass density for this mass distribution? I would really appreciate if someone could help. Thank you.
Edit: Added the website from where I got the heatmap function.
Okay, I think I've got the solution. I've been meaning to upload this for quite an amount of time. Here it goes:
# Importing packages
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from numpy.random import random
from scipy.stats import binned_statistic_2d
# Finds nran number of random points in two dimensions
def randomizer(nran):
arr_x = []
arr_y = []
for i in range(nran):
arr_x += [10 * random()] # Since random() only produces floats in (0, 1), I multiply by 10 (for illustrative purposes)
arr_y += [10 *random()] # Since random() only produces floats in (0, 1), I multiply by 10 (for illustrative purposes)
return arr_x, arr_y
# Computing weight array
def weights_array(weight, length):
weights = np.array([weight] * length)
return weights
# Computes a weighted histogram and divides it by the total grid area to get the density
def histogramizer(x_array, y_array, weights, num_pixels, Dimension):
Range = [0, Dimension] # Assumes the weights are distributed in a square area
grid, _, _, _ = binned_statistic_2d(x_array, y_array, weights, 'sum', bins=num_pixels, range=[Range,Range])
area = int(np.max(x_array)) * int(np.max(y_array))
density = grid/area
return density
Then, actually implementing this, one finds:
arr_x, arr_y = randomizer(1000000)
weights = []
for i in range(len(arr_x)):
weights += [50]
density = histogramizer(arr_x, arr_y, weights, [400,400], np.max(arr_x))
fig, ax = plt.subplots(figsize = (15, 5))
plt.imshow(density, extent = [0, int(np.max(arr_x)), 0, int(np.max(arr_x))]);
plt.colorbar(label = '$kg m^-2$');
The result I got for this was the following plot (I know it's generally not recommended to add a photo, but I wanted to add it for sake of showing my code's output):

how to generate histogram from a bin?

I have some data as numpy arrays x, y, v as shown in the code below.
This is actually dummy data for velocity (v) of dust particles in a x-y plane.
I have binned my data into 4 bins and for each bin I have calculated mean of entries in each bin and made a heat map.
Now what I want to do is make a histogram/distribution of v in each bin with 0 as the centre of the histogram.
I do not want to plot the mean anymore, just want to divide my data into the same bins as this code and for each bin I want to generate a histogram of the values in the bins.
How should I do it?
I think this is a way to model the spectrum of an emission line from the gas particles. Any help is appreciated! Thanks!
from scipy import stats
import numpy as np
import matplotlib.pyplot as plt
x = np.array([-10,-2,4,12,3,6,8,14,3])
y = np.array([5,5,-6,8,-20,10,2,2,8])
v = np.array([4,-6,-10,40,22,-14,20,8,-10])
x_bins = np.linspace(-20, 20, 3)
y_bins = np.linspace(-20, 20, 3)
H, xedges, yedges = np.histogram2d(x, y, bins = [x_bins, y_bins], weights = v)
pstat = stats.binned_statistic_2d(x, y, v, statistic='mean', bins = [x_bins, y_bins])
plt.xlabel("x")
plt.ylabel("y")
plt.imshow(pstat.statistic.T, origin='lower', cmap='RdBu',
extent=[xedges[0], xedges[-1], yedges[0], yedges[-1]])
plt.colorbar().set_label('mean', rotation=270)
EDIT: Please note that my original data is huge. My arrays for x,y, v are very large and I am using 30x30 grid, that is, not just 4quadrants but 900 bins. I might also need to increase the bin number. So, we want to find a way to automatically divide the 'v' data into the regularly spaced bins and then be able to plot the histograms of the 'v' data in each bin.
I would iterate over the zipped x and y, then flag if v is inside the quadrant and append them to a quadrant list. after, you can plot whatever you'd like:
x = np.array([-10,-2,4,12,3,6,8,14,3])
y = np.array([5,5,-6,8,-20,10,2,2,8])
v = np.array([4,-6,-10,40,22,-14,20,8,-10])
q1 = []
q2 = []
q3 = []
q4 = []
for i, (x1,y1) in enumerate(zip(x,y)):
if x1<0 and y1>=0:
q1.append(v[i])
elif x1>=0 and y1>=0:
q2.append(v[i])
elif x1>=0 and y1<0:
q3.append(v[i])
elif x1<0 and y1<0:
q4.append(v[i])
print(q1)
print(q2)
print(q3)
print(q4)
#[4, -6]
#[40, -14, 20, 8, -10]
#[-10, 22]
#[]
plt.hist(q1, density=True)
plt.hist(q2, density=True)
plt.hist(q3, density=True)
#q4 is empty

How to plot specific parts of a matrix in matplotlib?

I have a matrix that represents temperature distribution in a hollow square plate (hope the attached figure helps). The problem is with the hollow part in the plate which doesn't represent any solid material so I need to exclude this part from the plot.
The simulation returns an np.array() with the temperature results (except of course for the hollow part). and this is the part where I define dimensions of the grid:
import numpy as np
plate_height = 0.4 #meters
hollow_square_height = 0.2 #meters
#discretization data
delta_x = delta_y = 0.05 #meters
grid_points_n = (plate_height/delta_x) + 1
grid = np.zeros(shape=(grid_points_n, grid_points_n))
# the simulation assures that the hollow part will remain zero valued.
So, how do I approach this?
Instead of changing the original data, you can mask the values that you don't want to be used in calculations, plots, etc.:
import matplotlib.pyplot as plt
import numpy as np
data = [
[11, 11, 12, 13],
[9, 0, 0, 12],
[8, 0, 0, 11],
[8, 9, 10, 11]
]
#Here's what you have:
data_array = np.array(data)
#Mask every position where there is a 0:
masked_data = np.ma.masked_equal(data_array, 0)
#Plot the matrix:
fig = plt.figure()
ax = fig.gca()
ax.matshow(masked_data, cmap=plt.cm.autumn_r) #_r => reverse the standard color map
plt.show()
#plt.savefig('heatmap.png')
Replace zeros by nan, nan values are ignored in any plot. For example:
import matplotlib.pyplot as plt
from numpy import nan,matrix
M = matrix([
[20,30,25,20,50],
[22,nan,nan,nan,27],
[30,nan,nan,nan,20],
[33,nan,nan,nan,31],
[21,28,29,23,36]])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.matshow(M, cmap=plt.cm.jet) # Show matrix color
plt.show()
You can replace zeros by nan in a matrix as follow:
from numpy import nan
A[A==0.0]=nan # A is your matrix

How to plot multiple lines in single graph python

I have a three-dimensional array.
The first dimension has 4 elements.
The second dimension has 10 elements.
The third dimension has 5 elements.
I want to plot the contents of this array as follows.
Each element of the first dimension gets its own graph (four graphs on the page)
The values of the second dimension correspond to the y values of the graphs. (there are 10 lines on each graph)
The values of the third dimension correspond to the x values of the graphs (each of the 10 lines has 5 x values)
I'm pretty new to python, and even newer to graphing.
I figured out how to correctly load my array with the data...and I'm not even trying to get the 'four graphs on one page' aspect working.
For now I just want one graph to work correctly.
Here's what I have so far (once my array is set up, and I've correctly loaded my arrays. Right now the graph shows up, but it's blank, and the x-axis includes negative values. None of my data is negative)
for n in range(1):
for m in range(10):
for o in range(5):
plt.plot(quadnumcounts[n][m][o])
plt.xlabel("Trials")
plt.ylabel("Frequency")
plt.show()
Any help would be really appreciated!
Edit. Further clarification. Let's say my array is loaded as follows:
myarray[0][1][0] = 22
myarray[0][1][1] = 10
myarray[0][1][2] = 15
myarray[0][1][3] = 25
myarray[0][1][4] = 13
I want there to be a line, with the y values 22, 10, 15, 25, 13, and the x values 1, 2, 3, 4, 5 (since it's 0 indexed, I can just +1 before printing the label)
Then, let's say I have
myarray[0][2][0] = 10
myarray[0][2][1] = 17
myarray[0][2][2] = 9
myarray[0][2][3] = 12
myarray[0][2][4] = 3
I want that to be another line, following the same rules as the first.
Here's how to make the 4 plots with 10 lines in each.
import matplotlib.pyplot as plt
for i, fig_data in enumerate(quadnumcounts):
# Set current figure to the i'th subplot in the 2x2 grid
plt.subplot(2, 2, i + 1)
# Set axis labels for current figure
plt.xlabel('Trials')
plt.ylabel('Frequency')
for line_data in fig_data:
# Plot a single line
xs = [i + 1 for i in range(len(line_data))]
ys = line_data
plt.plot(xs, ys)
# Now that we have created all plots, show the result
plt.show()
Here is the example of creating subplots of your data. You have not provided the dataset so I used x to be an angle from 0 to 360 degrees and the y to be the trigonemetric functions of x (sine and cosine).
Code example:
import numpy as np
import pylab as plt
x = np.arange(0, 361) # 0 to 360 degrees
y = []
y.append(1*np.sin(x*np.pi/180.0))
y.append(2*np.sin(x*np.pi/180.0))
y.append(1*np.cos(x*np.pi/180.0))
y.append(2*np.cos(x*np.pi/180.0))
z = [[x, y[0]], [x, y[1]], [x, y[2]], [x, y[3]]] # 3-dimensional array
# plot graphs
for count, (x_data, y_data) in enumerate(z):
plt.subplot(2, 2, count + 1)
plt.plot(x_data, y_data)
plt.xlabel('Angle')
plt.ylabel('Amplitude')
plt.grid(True)
plt.show()
Output:
UPDATE:
Using the sample date you provided in your update, you could proceed as follows:
import numpy as np
import pylab as plt
y1 = (10, 17, 9, 12, 3)
y2 = (22, 10, 15, 25, 13)
y3 = tuple(reversed(y1)) # generated for explanation
y4 = tuple(reversed(y2)) # generated for explanation
mydata = [y1, y2, y3, y4]
# plot graphs
for count, y_data in enumerate(mydata):
x_data = range(1, len(y_data) + 1)
print x_data
print y_data
plt.subplot(2, 2, count + 1)
plt.plot(x_data, y_data, '-*')
plt.xlabel('Trials')
plt.ylabel('Frequency')
plt.grid(True)
plt.show()
Note that the dimensions are slightly different from yours. Here they are such that mydata[0][0] == 10, mydata[1][3] == 25 etc. The output is show below:

plotting/marking seleted points from a 1D array

this seems a simple question but I have tried it for a really long time.
I got a 1d array data(named 'hightemp_unlocked', after I found the peaks(an array of location where the peaks are located) of it, I wanted to mark the peaks on the plot.
import matplotlib
from matplotlib import pyplot as plt
.......
plt.plot([x for x in range(len(hightemp_unlocked))],hightemp_unlocked,label='200 mk db ramp')
plt.scatter(peaks, hightemp_unlocked[x in peaks], marker='x', color='y', s=40)
for some reason, it keeps telling me that x, y must be the same size
it shows:
File "period.py", line 86, in <module>
plt.scatter(peaks, hightemp_unlocked[x in peaks], marker='x', color='y', s=40)
File "/usr/local/lib/python2.6/dist-packages/matplotlib/pyplot.py", line 2548, in scatter
ret = ax.scatter(x, y, s, c, marker, cmap, norm, vmin, vmax, alpha, linewidths, faceted, verts, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/matplotlib/axes.py", line 5738, in scatter
raise ValueError("x and y must be the same size")
I don't think hightemp_unlocked[x in peaks] is what you want. Here x in peaks reads as the conditional statement "is x in peaks?" and will return True or False depending on what was last stored in x. When parsing hightemp_unlocked[x in peaks], True or False is interpreted as 0 or 1, which returns only the first or second element of hightemp_unlocked. This explains the array size error.
If peaks is an array of indexes, then simply hightemp_unlocked[peaks] will return the corresponding values.
You are almost on the right track, but hightemp_unlocked[x in peaks] is not what you are looking for. How about something like:
from matplotlib import pyplot as plt
# dummy temperatures
temps = [10, 11, 14, 12, 10, 8, 5, 7, 10, 12, 15, 13, 12, 11, 10]
# list of x-values for plotting
xvals = list(range(len(temps)))
# say our peaks are at indices 2 and 10 (temps of 14 and 15)
peak_idx = [2, 10]
# make a new list of just the peak temp values
peak_temps = [temps[i] for i in peak_idx]
# repeat for x-values
peak_xvals = [xvals[i] for i in peak_idx]
# now we can plot the temps
plt.plot(xvals, temps)
# and add the scatter points for the peak values
plt.scatter(peak_xvals, peak_temps)

Categories