Colorplot of 2D array matplotlib - python

So, I thought this was going to be really simple, but I've been having a lot of difficult finding exactly what I'm looking for in a comprehensible example.
Basically I want to make phase plots, so assuming I have a 2d array, how can I get matplotlib to convert this to a plot that I can attach titles, axes, and legends (color bars) to.
I'm looking for an extremely simple bare bones solution that only uses what is required that will work with any 2D array.
I'm certain this is simple and I'm just being thick somehow, but I'm really having a lot of trouble with this.
I have been tooling with the examples, but they don't seem well suited to what I'm trying to do: I like the general appearance of this graph, I'd just like to be able to pass in a 2dArray and have this same result:
import numpy as np
import matplotlib as ml
import matplotlib.pyplot as plt
H = [[1,2,3,4][5,6,7,8][9,10,11,12][13,14,15,16]]
fig = plt.figure(figsize=(6, 3.2))
ax = fig.add_subplot(111)
ax.set_title('colorMap')
X,Y = np.meshgrid(xedges, yedges)
plt.pcolormesh(X, Y, H)
ax.set_aspect('equal')
cax = fig.add_axes([0.12, 0.1, 0.78, 0.8])
cax.get_xaxis().set_visible(False)
cax.get_yaxis().set_visible(False)
cax.patch.set_alpha(0)
cax.set_frame_on(False)
plt.colorbar(orientation='vertical')
plt.show()

I'm afraid your posted example is not working, since X and Y aren't defined. So instead of pcolormesh let's use imshow:
import numpy as np
import matplotlib.pyplot as plt
H = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]]) # added some commas and array creation code
fig = plt.figure(figsize=(6, 3.2))
ax = fig.add_subplot(111)
ax.set_title('colorMap')
plt.imshow(H)
ax.set_aspect('equal')
cax = fig.add_axes([0.12, 0.1, 0.78, 0.8])
cax.get_xaxis().set_visible(False)
cax.get_yaxis().set_visible(False)
cax.patch.set_alpha(0)
cax.set_frame_on(False)
plt.colorbar(orientation='vertical')
plt.show()

Here is the simplest example that has the key lines of code:
import numpy as np
import matplotlib.pyplot as plt
H = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]])
plt.imshow(H, interpolation='none')
plt.show()
EDIT: (1/2023) Still working with Python 3.9.13

Related

Is it possible to change the frequency of ticks on a pyplot INDEPENDENT of length of data set and zoom?

When I plot data using matplotlib I always have 5-9 ticks on my x-axis independent of the range I plot, and if I zoom on the x-axis the tick spacing decreases, so I still see 5-9 ticks.
however, I would like 20-30 ticks on my x-axis!
I can achieve this with the following:
from matplotlib import pyplot as plt
import numpy as np
x = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50]
y = [1, 4, 3, 2, 7, 6, 9, 8, 10, 5]
number_of_ticks_on_x_axis = 20
plt.plot(x, y)
plt.xticks(np.arange(min(x), max(x)+1, (max(x) - min(x))/number_of_ticks_on_x_axis))
plt.show()
If I now zoom on the x-axis, no new ticks appear between the existing ones. I would like to still have ~20 ticks however much I zoom.
Assuming that you want to fix the no. of ticks on the X axis
...
from matplotlib.ticker import MaxNLocator
...
fig, ax = plt.subplots()
ax.xaxis.set_major_locator(MaxNLocator(15, min_n_ticks=15))
...
Please look at the docs for MaxNLocator
Example
In [36]: import numpy as np
...: import matplotlib.pyplot as plt
In [37]: from matplotlib.ticker import MaxNLocator
In [38]: fig, ax = plt.subplots(figsize=(10,4))
In [39]: ax.grid()
In [40]: ax.xaxis.set_major_locator(MaxNLocator(min_n_ticks=15))
In [41]: x = np.linspace(0, 1, 51)
In [42]: y = x*(1-x)
In [43]: plt.plot(x, y)
Out[43]: [<matplotlib.lines.Line2D at 0x7f9eab409e10>]
gives
and when I zoom into the maximum of the curve I get
You can link a callback function to an event in the canvas. In you case you can trigger a function that updates the axis when a redraw occurs.
from matplotlib import pyplot as plt
import numpy as np
x = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50]
y = [1, 4, 3, 2, 7, 6, 9, 8, 10, 5]
n = 20
plt.plot(x, y)
plt.xticks(np.arange(min(x), max(x)+1, (max(x) - min(x))/n), rotation=90)
def on_zoom(event):
ax = plt.gca()
fig = plt.gcf()
x_min, x_max = ax.get_xlim()
ax.set_xticks(np.linspace(x_min, x_max, n))
# had to add flush_events to get the ticks to redraw on the last update.
fig.canvas.flush_events()
fig = plt.gcf()
fig.canvas.mpl_disconnect(cid)
cid = fig.canvas.mpl_connect('draw_event', on_zoom)

drawing grid lines beween points in python

I have 6 points in the (x,y) plane: x=[x1,x2,x3,x4,x5,x6] and y=[y1,y2,y3,y4,y5,y6]
import matplotlib.pyplot as plt
x = [0, 2, 4, 0, 2, 4, 0, 2, 4]
y = [0, 0, 0, 3, 3, 3, 7, 7, 7]
plt.scatter(x, y)
plt.show()
I want to between the points, draw entirely parallel lines on each axis x,y(like photo). and how to hide x and y axis on diagram. I want to draw a 2D view of the beams and columns of 3 story building; does matplotlib bring me to my goal or should I go to other libraries?
Absolutely matplotlib can do this. Take a look at their Rectangle Patch:
Example usage (you'll have to modify this to your needs):
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig = plt.figure()
ax = fig.add_subplot()
rect = patches.Rectangle(
(0.1, 0.1),
0.5,
0.5,
fill=False
)
ax.add_patch(rect)
fig.show()

Seaborn Heatmap without lines between cells

I´m trying to create a heatmap with seaborn with a transparent colormap since an image should be displayed in the background. The heatmap creation works fine so far, however some lines between the cells are still visible even though the linewidth of the heatmap is set to 0.0.
The code for the creation of the heatmap looks like the following:
ax = sns.heatmap(image, cmap="rocket_r", linewidths=0.0)
ax.collections[0].set_alpha(0.5)
Where image is 64x64 numpy array. The resulting heatmap looks like this:
Heatmap (sorry not enough repuation for embedding pictures)
The problem are the thin lines between the cells. Strangely they aren´t at every edge.
Anyone knows how to get rid of those lines?
Many Thanks
Update 1 (Complete working example):
image = np.array([[1, 1, 2, 2], [3, 3, 3, 3], [4, 5, 4, 5], [6, 6, 6, 6]])
ax = sns.heatmap(image, cmap="rocket_r", linewidths=0.0)
ax.collections[0].set_alpha(0.5)
plt.show()
Results is this heatmap:
Here you can see that there are thin lines between every column but there isn´t any line between the first and second row.
The lines are the overlapping of semitransparent patches which cannot be perfectly aligned on the pixel grid.
alpha blending
An option is to not use transparency, but instead create opaque colors with alpha blending.
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import numpy as np
import seaborn as sns
def get_alpha_blend_cmap(cmap, alpha):
cls = plt.get_cmap(cmap)(np.linspace(0,1,256))
cls = (1-alpha) + alpha*cls
return ListedColormap(cls)
image = np.array([[1, 1, 2, 2], [3, 3, 3, 3], [4, 5, 4, 5], [6, 6, 6, 6]])
ax = sns.heatmap(image, cmap=get_alpha_blend_cmap("rocket_r", 0.5), linewidths=0.0)
plt.show()
An obvious advantage of this is that the colorbar has the same colors as the heatmap.
increase dpi
If the above is not an option you may increase the dpi when saving.
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
image = np.array([[1, 1, 2, 2], [3, 3, 3, 3], [4, 5, 4, 5], [6, 6, 6, 6]])
ax = sns.heatmap(image, cmap="rocket_r", linewidths=0.0, edgecolor="none", alpha=0.5)
plt.savefig("test.png", dpi=1000)
This does of course not have any effect on the figure shown on screen though.
imshow
Finally, consider not using seaborn here, but instead a matplotlib imshow plot.
import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use("seaborn-dark")
plt.rcParams["axes.facecolor"] = "white"
import numpy as np
image = np.array([[1, 1, 2, 2], [3, 3, 3, 3], [4, 5, 4, 5], [6, 6, 6, 6]])
im = plt.imshow(image, cmap="rocket_r", alpha=0.5)
plt.colorbar(im)
plt.gca().set(xticks=(range(image.shape[1])),yticks=(range(image.shape[0])))
plt.show()
I have just come across this problem. I need to upload the plot to overleaf, so I do not like the dpi solutions. Here is what I came up with, based on the solution of OP:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
image = np.array([[1, 1, 2, 2], [3, 3, 3, 3], [4, 5, 4, 5], [6, 6, 6, 6]])
ax = sns.heatmap(image, cmap="rocket_r", linewidths=0.1)
colors = ax.collections[0].get_facecolors()
ax.collections[0].set_edgecolors(colors)
plt.imshow()
The idea is to create a thin edge around each cell with the cell's facecolor. This removes the lines without changing the original cell colors.

Control order of plotting on Seaborn plot in Python

I am trying to plot residuals on a linear regression plot. It works, with only one caveat. There is an unpleasant looking overlap between residuals and data points. Is there a way to tell matplotlib to plot the residuals first followed by Seaborn plot. I tried changing the order of code, but it didn't help.
import numpy as np
import pandas as pd
import seaborn as sns
from pylab import *
from sklearn.linear_model import LinearRegression
x = np.array([1, 2, 3, 4, 5, 7, 8, 9, 10])
y = np.array([-3, 0, 4, 5, 9, 5, 7, 7, 12])
dat = pd.DataFrame({'x': x, 'y': y})
x = x.reshape(-1,1)
y = y.reshape(-1,1)
linear_model = LinearRegression()
linear_model.fit(X=x, y=y)
pred = linear_model.predict(x)
for ix in range(len(x)):
plot([x[ix], x[ix]], [pred[ix], y[ix]], '#C9B97D')
g = sns.regplot(x='x', y='y', data=dat, ci=None, fit_reg=True)
sns.set(font_scale=1.1)
g.figure.set_size_inches(6, 6)
sns.set_style('ticks')
sns.despine()
The argument you are looking for is zorder. This allows you to control which object appears on top in your figure.
For regplot you have to use the argument scatter_kws which is a dictionary of arguments to be passed to plt.scatter which is used under the hood.
Your sns.regplot becomes:
g = sns.regplot(x='x', y='y', data=dat, ci=None, fit_reg=True,
scatter_kws={"zorder":10, "alpha":1})
Note that I've set alpha to 1 so that the markers are not transparent

Connect points in a three dimensional plot

I have an algorithm that can be controlled by two parameters so now I want to plot the runtime of the algorithm depending on these parameters.
My Code:
from matplotlib import pyplot
import pylab
from mpl_toolkits.mplot3d import Axes3D
fig = pylab.figure()
ax = Axes3D(fig)
sequence_containing_x_vals = [5,5,5,5,10,10,10,10,15,15,15,15,20,20,20,20]
sequence_containing_y_vals = [1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4]
sequence_containing_z_vals = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
ax.scatter(sequence_containing_x_vals, sequence_containing_y_vals, sequence_containing_z_vals)
pyplot.show()
This will plot all the points in the space but I want them connected and have something like this:
(The coloring would be nice but not necessary)
To plot the surface you need to use plot_surface, and have the data as a regular 2D array (that reflects the 2D geometry of the x-y plane). Usually meshgrid is used for this, but since your data already has the x and y values repeated appropriately, you just need to reshape them. I did this with numpy reshape.
from matplotlib import pyplot, cm
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
fig = pyplot.figure()
ax = Axes3D(fig)
sequence_containing_x_vals = np.array([5,5,5,5,10,10,10,10,15,15,15,15,20,20,20,20])
X = sequence_containing_x_vals.reshape((4,4))
sequence_containing_y_vals = np.array([1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4])
Y = sequence_containing_y_vals.reshape((4,4))
sequence_containing_z_vals = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
Z = sequence_containing_z_vals.reshape((4,4))
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.hot)
pyplot.show()
Note that X, Y = np.meshgrid([1,2,3,4], [5, 10, 15, 20]) will give the same X and Y as above but more easily.
Of course, the surface shown here is just a plane since your data is consistent with z = x + y - -5, but this method will work with generic surfaces, as can be seen in the many matplotlib surface examples.

Categories

Resources