I have a 2D power-law like dataset:
import numpy as np
X = 1 / np.random.power(2, size=1000)
Y = 1 / np.random.power(2, size=1000)
I can plot it using a scatter plot in loglog scale
import matplotlib.pyplot as plt
plt.figure()
plt.scatter(X, Y, alpha=0.3)
plt.loglog()
plt.show()
getting:
However, it does not show properly the data near the origin where the density is high. Hence, I converted this plot in a heatmap. I did that:
from matplotlib.colors import LogNorm
heatmap, xedges, yedges = np.histogram2d(X, Y, bins=np.logspace(0, 2, 30))
plt.figure()
plt.imshow(heatmap.T, origin='lower', norm=LogNorm())
plt.colorbar()
plt.show()
getting:
The plot looks great but the axis ticks are not good. To change the scale I tried to add extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]] in the imshow but it only does an affine transformation, the scale is still linear not logarithmic. Do you know how can I get the heatmap plot but with ticks of the scatter one?
You can use pcolormesh like JohanC advised.
Here is an example with you code using pcolormesh:
import numpy as np
import matplotlib.pyplot as plt
X = 1 / np.random.power(2, size=1000)
Y = 1 / np.random.power(2, size=1000)
heatmap, xedges, yedges = np.histogram2d(X, Y, bins=np.logspace(0, 2, 30))
fig = plt.figure()
ax = fig.add_subplot(111)
ax.pcolormesh(xedges, yedges, heatmap)
ax.loglog()
ax.set_xlim(1, 50)
ax.set_ylim(1, 50)
plt.show()
And the output is:
Related
I am trying to plot a heat map contour graph like the following: https://i.stack.imgur.com/XrCOe.png
It uses a 6x5 grid for the x and y coordinates. I then have probability values to plot at each of the 30 points. How can I do this?
edit:
import matplotlib.pyplot as plt
import numpy as np
grid = np.zeros((5,5))
grid[0,0]=0.9189
grid[1,0]=0.0767
grid[2,0]=0.01459
grid[3,0]=0.1157
grid[4,0]=0.207
heatmap = plt.imshow(grid, cmap='jet', interpolation='lanczos')
plt.grid(which='major', axis='both', linestyle='-', color='k', linewidth=1)
x=[1,2,3,4,5]
y=[1,2,3,4,5]
plt.xticks(range(0,5),x)
plt.yticks(range(0,5),y)
plt.colorbar(heatmap)
plt.show()
https://i.stack.imgur.com/kzl0b.png
Tell Matplotlib to interpret your grid as an image with interpolation other than the default nearest:
import matplotlib.pyplot as plt
import numpy as np
grid = np.random.uniform(0, 1, (5, 6))
heatmap = plt.imshow(grid, cmap='jet', interpolation='lanczos')
plt.grid(which='major', axis='both', linestyle='-', color='k', linewidth=1)
plt.colorbar(heatmap)
plt.show()
The output is e.g.
I am working on a project for my final year design.
I have a data-set i have managed to collect that i would like to plot as a heat map over an image.
What i have managed to do so far is shown by this image.
The code i used to make this image is
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde
# Generate fake data
x = dd['B']
y = dd['C']
# Calculate the point density
xy = np.vstack([x,y])
z = gaussian_kde(xy)(xy)
# fig, ax = plt.subplots()
# ax.scatter(x, y, c=z, s=1)
# plt.show()
plt.figure()
plt.imshow(cap)
# plt.scatter(dd['B'],dd['C'],c=dd['A'].apply(lambda x: color(x)),s=2, alpha=0.1)
plt.scatter(x, y, c=z, cmap='Reds', s=1, alpha=0.1)
so my question is how can make a plot like this for the data-set(just an x and y point ) that i have.
Thank you.
Try the following : plt.imshow(z)
I try to plot a 2d histogram of data with very different ranges using the following code. However, because of the different data ranges, the x data overlaps like the following figure. Is there any solution that plots x and y data with the same axis length?
import numpy as np
from matplotlib import pyplot as plt
plt.clf()
x = np.random.randint(low=0, high=10, size=8873)
y = np.random.randint(low=100000,high=600000, size=8873)
heatmap, xedges, yedges = np.histogram2d(x, y, bins=50)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
plt.imshow(heatmap.T, extent=extent, origin='lower')
plt.show()
Note that imshow() sets the aspect to 1 by default, changing it to auto should solve your problem. You can also calculate your own aspect based on extent to get for example a square image.
aspect = (extent[1] - extent[0]) / (extent[3] - extent[2])
plt.imshow(heatmap.T, extent=extent, origin='lower', aspect=aspect)
# plt.imshow(heatmap.T, extent=extent, origin='lower', aspect='auto')
I want to use a scatter plot to describe the relationship between X, Y and Z. Z is p-value so it is better to denote it as log values.
Following the instructions here, I can plot a logarithmic scatter plot, but the color bar seems wrong. The color bar is almost totally blue, but there should be some red! Below is the figure and my codes.
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.colors import LogNorm
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ax1.set_title("P-value")
Z1 = pos_spearmanr['pval']
X = pos_spearmanr['X']
Y = pos_spearmanr['Y']
im = ax1.scatter(X,
Y,
edgecolors=None,
c=Z1,
norm=LogNorm(),
cmap=plt.get_cmap('bwr'), alpha=0.2)
ax1.set_xlabel('X')
ax1.set_ylabel('Y')
ax1.set_xlim(0, 1)
ax1.set_ylim(0, 1)
cbar = fig.colorbar(im,ax=ax1)
I have a range of points x and y stored in numpy arrays.
Those represent x(t) and y(t) where t=0...T-1
I am plotting a scatter plot using
import matplotlib.pyplot as plt
plt.scatter(x,y)
plt.show()
I would like to have a colormap representing the time (therefore coloring the points depending on the index in the numpy arrays)
What is the easiest way to do so?
Here is an example
import numpy as np
import matplotlib.pyplot as plt
x = np.random.rand(100)
y = np.random.rand(100)
t = np.arange(100)
plt.scatter(x, y, c=t)
plt.show()
Here you are setting the color based on the index, t, which is just an array of [1, 2, ..., 100].
Perhaps an easier-to-understand example is the slightly simpler
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(100)
y = x
t = x
plt.scatter(x, y, c=t)
plt.show()
Note that the array you pass as c doesn't need to have any particular order or type, i.e. it doesn't need to be sorted or integers as in these examples. The plotting routine will scale the colormap such that the minimum/maximum values in c correspond to the bottom/top of the colormap.
Colormaps
You can change the colormap by adding
import matplotlib.cm as cm
plt.scatter(x, y, c=t, cmap=cm.cmap_name)
Importing matplotlib.cm is optional as you can call colormaps as cmap="cmap_name" just as well. There is a reference page of colormaps showing what each looks like. Also know that you can reverse a colormap by simply calling it as cmap_name_r. So either
plt.scatter(x, y, c=t, cmap=cm.cmap_name_r)
# or
plt.scatter(x, y, c=t, cmap="cmap_name_r")
will work. Examples are "jet_r" or cm.plasma_r. Here's an example with the new 1.5 colormap viridis:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(100)
y = x
t = x
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.scatter(x, y, c=t, cmap='viridis')
ax2.scatter(x, y, c=t, cmap='viridis_r')
plt.show()
Colorbars
You can add a colorbar by using
plt.scatter(x, y, c=t, cmap='viridis')
plt.colorbar()
plt.show()
Note that if you are using figures and subplots explicitly (e.g. fig, ax = plt.subplots() or ax = fig.add_subplot(111)), adding a colorbar can be a bit more involved. Good examples can be found here for a single subplot colorbar and here for 2 subplots 1 colorbar.
To add to wflynny's answer above, you can find the available colormaps here
Example:
import matplotlib.cm as cm
plt.scatter(x, y, c=t, cmap=cm.jet)
or alternatively,
plt.scatter(x, y, c=t, cmap='jet')
Subplot Colorbar
For subplots with scatter, you can trick a colorbar onto your axes by building the "mappable" with the help of a secondary figure and then adding it to your original plot.
As a continuation of the above example:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y = x
t = x
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.scatter(x, y, c=t, cmap='viridis')
ax2.scatter(x, y, c=t, cmap='viridis_r')
# Build your secondary mirror axes:
fig2, (ax3, ax4) = plt.subplots(1, 2)
# Build maps that parallel the color-coded data
# NOTE 1: imshow requires a 2-D array as input
# NOTE 2: You must use the same cmap tag as above for it match
map1 = ax3.imshow(np.stack([t, t]),cmap='viridis')
map2 = ax4.imshow(np.stack([t, t]),cmap='viridis_r')
# Add your maps onto your original figure/axes
fig.colorbar(map1, ax=ax1)
fig.colorbar(map2, ax=ax2)
plt.show()
Note that you will also output a secondary figure that you can ignore.
Single colorbar for multiple subplots
sometimes it is preferable to have a single colorbar to indicate data values visualised on multiple subplots.
In this case, a Normalize() object needs to be created using the minimum and maximum data values across both plots.
Then a colorbar object can be created from a ScalarMappable() object, which maps between scalar values and colors.
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y = x
t1 = x # Colour data for first plot
t2 = 2*x # Color data for second plot
all_data = np.concatenate([t1, t2])
# Create custom Normalise object using the man and max data values across both subplots to ensure colors are consistent on both plots
norm = plt.Normalize(np.min(all_data), np.max(all_data))
fig, axs = plt.subplots(1, 2)
axs[0].scatter(x, y, c=t1, cmap='viridis', norm=norm)
axs[1].scatter(x**2, y, c=t2, cmap='viridis', norm=norm)
# Create the colorbar
smap = plt.cm.ScalarMappable(cmap='viridis', norm=norm)
cbar = fig.colorbar(smap, ax=axs, fraction=0.1, shrink = 0.8)
cbar.ax.tick_params(labelsize=11)
cbar.ax.set_ylabel('T', rotation=0, labelpad = 15, fontdict = {"size":14})
plt.show()
subplots_colorbar