How to convert scatterplot to a heat map - python

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)

Related

matplotlib fill in between step function

I need to plot a step function in matplotlib (because that's the correct interpretation of my data) and would like to fill between the x-axis and the step curve.
Something like fill_between, only that this one does not work with drawstyle.
See minimal example below:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(2)
x = np.arange(50)
y = np.random.rand(50)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y, drawstyle='steps-post')
ax.fill_between(x, y, drawstyle='steps-post') # does not work
plt.show()
You can use ax.fill_between(x, y, step='post'). fill_between doesn't have the parameter of drawstyle.

Matplotlib bar chart or similar with bars located at a specific x,y,angle

Is there a way to create a bar chart using matplotlib such that the bars are located at a specific x,y and at a specific angle? In the screenshot below, I just drew thick lines (to represent thin bars) in PowerPoint on top of the scatterplot.
It doesn't have to be a barchart necessarily, I just don't know the name of a plot that is like this. I thought about trying to mimic this with a quiver plot but wasn't sure how. Reason for wanting this is densely spaced points that have variable values (not monotonically increasing like in this example), and just coloring the scatter plot isn't visually elucidating trends of interest, even with different colormaps.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(25)
y = -x
z = x
plt.scatter(x, y, c=z, cmap='viridis')
I don't know of a canned way to do this, but you could, in a pinch, create your own function that draws rectangles to create this plot. For example:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Rectangle
x = np.arange(25)
y = -x
z = x
plt.scatter(x, y, c=z, cmap='viridis')
def slanted_bars(x, y, z, angle, ax):
for xi, yi, zi in zip(x, y, z):
ax.add_patch(Rectangle((xi, yi), 1, zi, angle))
fig, ax = plt.subplots(1, 1)
ax.scatter(x, y, c=z, cmap='viridis')
slanted_bars(x, y, z, -45, ax)
You'd have to play with the color and shape of the rectangles to get something appealing, but it can do what you want.

Color as the third axis in seaborn jointplots

I have three quantities, x, y, z, which I would like to see the distribution of two of them and have the value of the third one as color of each point. I use seaborn.jointplot to plot distributions of x and y and use the z as the color parameter in the jointplot. But, still I need to change the color palette and add a colorbar somewhere outside the plot. This is a minimal example of what I did:
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
x = np.random.normal(loc=0, scale=1, size=1000)
y = np.random.normal(loc=0, scale=1, size=1000)
z = x**2 + y**2
plt.figure(num=1, figsize=(8, 5))
sns.jointplot(x=x, y=y, c=z, joint_kws={"color":None})
plt.show()
Thanks in advance for your comments.
by "changing the color palette", do you mean changing the colormap? If so, that can be done simply by passing the relevant info to joint_kws:
g = sns.jointplot(x=x, y=y, c=z, joint_kws={"color":None, 'cmap':'viridis'})
For the colorbar, it all depends on where you want it. Here is a solution that lets the axes to be resized automatically in order to make room. See the documentation for colorbar() to adjust the parameters as needed:
g.fig.colorbar(g.ax_joint.collections[0], ax=[g.ax_joint, g.ax_marg_y, g.ax_marg_x], use_gridspec=True, orientation='horizontal')
full code:
plt.figure(num=1, figsize=(8, 5))
g = sns.jointplot(x=x, y=y, c=z, joint_kws={"color":None, 'cmap':'viridis'})
g.fig.colorbar(g.ax_joint.collections[0], ax=[g.ax_joint, g.ax_marg_y, g.ax_marg_x], use_gridspec=True, orientation='horizontal')
plt.show()

Generate a loglog heatmap in MatPlotLib using a scatter data set

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:

Scatter plot and Color mapping in Python

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

Categories

Resources