How to create colour map from 3 arrays in python - python

I'm trying to create a colour plot in python of two arrays t1 and t2 with the colours being set by a third one v, but I can't get the colour bar to be in terms of the v array, it is instead in terms of t1. This is my code:
import matplotlib.pyplot as plt
import numpy as np
t1 = [75, 76, 77, 78]
t2 = [75, 76, 77, 78]
v = [0.5, 0.5, 0.8, 0.8]
image_data = np.column_stack([t1, t2, v])
plt.imshow(image_data)
plt.colorbar()
plt.show()
It produces this figure:
Any help would be much appreciated.

You cannot use imshow to set x and y coordinates, and color as 3rd.
It is to show a matrix image, where there are X*Y values, and all these values represent color.
Perhaps you want to use scatter.
E.g. you can try:
import matplotlib.pyplot as plt
t1 = [0,1,2,3]
t2 = [0, 10, 20, 30]
v = [0.5, 0.5, 0.8, 0.8]
plt.scatter(t1, t2, c=v, cmap='Greens')
plt.colorbar()
plt.show()
You can check which colormap is most suitable for you.

Related

Matplotlib Plot curve logistic regression

I am trying to plot the trained curve in matplotlib. However I am getting this thing:
The scatter works fine:
How can I create the curve using plot?
It may be that the order of your X_train data is wrong. Try to sort them out. For instance, if X_train is just a list of numbers, you could say:
X_train.sort()
You can plot a smooth line curve by first determining the spline curve’s coefficients using the scipy.interpolate.make_interp_spline():
import numpy as np
import numpy as np
from scipy.interpolate import make_interp_spline
import matplotlib.pyplot as plt
# Dataset
x = np.array([1, 2, 3, 4, 5, 6, 7, 8])
y = np.array([20, 30, 5, 12, 39, 48, 50, 3])
X_Y_Spline = make_interp_spline(x, y)
# Returns evenly spaced numbers
# over a specified interval.
X_ = np.linspace(x.min(), x.max(), 500)
Y_ = X_Y_Spline(X_)
# Plotting the Graph
plt.plot(X_, Y_)
plt.title("Plot Smooth Curve Using the scipy.interpolate.make_interp_spline() Class")
plt.xlabel("X")
plt.ylabel("Y")
plt.show()
Result:
It seems, that you have unsorted values in X_train. For instance, if
In [1]: X_train
Out [1]: array([30, 20, 50, 40])
then
In [2]: model.predict_proba(X_train)
Out [2]: array([0.2, 0.1, 0.8, 0.5])
Here, plt.plot will try to plot lines from point [30, 0.2] to point [20, 0.1], then from [20, 0.1] to [50, 0.8], then from [50, 0.8] to [40, 0.5].
Thus, the solution to your problem is to sort X_train before plotting =)
import numpy as np
X_train_sorted = np.sort(X_train)
y_train_sorted = model.predict_proba(X_train_sorted)
plt.scatter(X_train_sorted, y_train_sorted)
plt.plot(X_train_sorted, y_train_sorted)

How to plot the following figure?

dears. I am a totally beginner to the python community and I would like to draw the below picture in python as a 3D.
I have made a try, but I could not reach any successful results.
This is my data
This is below my try:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
fig = plt.figure()
ax1 = fig.add_subplot(111, projection='3d')
# data
x = [86, 91, 97]
y = [82, 88, 94]
z = [80, 85, 89]
ax1.plot(x,y,z)
plt.show()
Shape of your data is not correct. You provide 3 flat lists, what you should provide are x, y, z coordinates for each bar.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.cm as cm
import numpy as np
# create data
data_2d = [[729, 575, 528],
[805, 768, 667],
[841, 773, 724],
[899, 857, 787]]
# Convert it into an numpy array.
data_array = np.array(data_2d)
# Create a figure for plotting the data as a 3D histogram.
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Create an X-Y mesh of the same dimension as the 2D data. The floor of the plot.
x_data, y_data = np.meshgrid( np.arange(data_array.shape[1]),
np.arange(data_array.shape[0]) )
# Flatten out the arrays so that they may be passed to "ax.bar3d".
# ax.bar3d expects three one-dimensional arrays:
# x_data, y_data, z_data. The following call boils down to picking
# one entry from each array and plotting a bar to from
# (x_data[i], y_data[i], 0) to (x_data[i], y_data[i], z_data[i]).
x_data = x_data.flatten()
y_data = y_data.flatten()
z_data = data_array.flatten()
dz = z_data
offset = dz + np.abs(dz.min())
fracs = offset.astype(float)/offset.max()
norm = colors.Normalize(fracs.min(), fracs.max())
color_values = cm.jet(norm(fracs.tolist()))
ax.bar3d( x_data, y_data, np.zeros(len(z_data)), 0.6, 0.6, z_data, color=color_values)
# Labels
ax.set_xlabel("Grid Size")
ax.set_ylabel("Bézier")
ax.set_zlabel("Success Rate")
# Ticks
ax.set_zticks(range(0,1200,200))
# Shape of the 3D cube
ax.set_box_aspect(aspect=(8,8,10))
output:

Use of "extend" in a contourf plot with a discrete colorbar not working

I would like to create a contourf plot with an imposed maximum value and with everything above that value shaded with the last color of the colorbar. In the example code below, which reproduces my problem in my setup, I would like the colorbar to range between -1 and 1, with an extend arrow indicating that values above 1.0 will be shaded with the last color of the colorbar. However, although I have tried several solutions from various stackexchange discussions, the colorbar ranges between -4 and 4, and there is no extend arrow. Please see the minimum reproducible example below.
# import matplotlib (v 3.1.1)
import matplotlib.colors as colors
import matplotlib.pyplot as plt
import matplotlib.path as mpath
import matplotlib as mpl
# import numpy (v 1.17.2)
import numpy as np
# define grid
lon = np.linspace(start = 0, stop = 359, num = 360)
lat = np.linspace(start = -78, stop = -25, num = 52)
[X,Y] = np.meshgrid(lon, lat)
# generate random gaussian data for example purposes
mean = [0, 0]
cov = [[1, 0], [0, 100]]
zz = np.random.multivariate_normal(mean, cov, (np.size(lon),np.size(lat))).T
Z = zz[0,:,:]
# illutrate the maximum value of Z
np.max(Z)
# create plot
plt.figure(figsize=(10, 12))
# select plotting levels (missing min/max on purpose)
mylevs = [-1.0, -0.5, 0, 0.5, 1.0]
# colormap
cmap_cividis = plt.cm.get_cmap('cividis',len(mylevs))
mycolors = list(cmap_cividis(np.arange(len(mylevs))))
cmap = colors.ListedColormap(mycolors[:-1], "")
# set over-color to last color of list
cmap.set_over(mycolors[-1])
# contour plot: random pattern
C1 = plt.contourf(X, Y, Z, cmap = cmap, vmin=-1.0, vmax=1.0,
norm = colors.BoundaryNorm(mylevs, ncolors=len(mylevs)-1, clip=False))
# create colorbar
cbar = plt.colorbar(C1, orientation="horizontal", extend='max')
cbar.ax.tick_params(labelsize=20)
cbar.set_label('Random field', size='xx-large')
I would like the colorbar to stop at 1.0, with an extend arrow pointing to the right, shaded by the last color of the colorbar. Thanks in advance for any help you can provide.
Link to example image produced by the above code
Does this solve it?
fig,ax = plt.subplots()
mylevs = [-1.0, -0.5, 0, 0.5, 1.0]
C1 = ax.contourf(X, Y, Z, cmap = cmap, vmin=-1.0, vmax=1.0,levels=mylevs,extend='both')
fig.colorbar(C1)

Single stacked bar chart with custom gradient coloring

Here's what I came up with by plotting thick line segments.
The coloration is blue, with varying alpha, 0 < alpha < 1.
My workaround doens't work as I'd like because I don't have a legend (I want a legend that shows a gradient of the blue at varying alpha).
Additionally, I've found that matplotlib scales funny. There should be no overlap of the bars, but if I adjust the window size, the gap between the line segments will change.This is the same figure as the earlier one, just after I've resized the figure window with my mouse.
I'm not sure if there's a better way to go about accomplishing this, or if there's a different package I can use.
Here's the snippet of code that I'm using.
import matplotlib.pyplot as plt
x1 =[0, 19, 39, 46, 60, 79]
x2 = [19, 39, 46, 60, 79, 90]
alpha_list = [-0.8402, -0.6652, 0.0, -0.5106, -0.8074, 0.0]
plt.figure()
for idx,x in enumerate(x1):
plt.plot([x1[idx],x2[idx]],[0,0],color = 'blue',alpha=alpha_list[idx],linewidth =20)
plt.show()
I suppose alpha is just a workaround for using different shades of blue? In that case the Blues colormap can be used instead.
Several lines can be plotted using a LineCollection.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
x1 =[0, 19, 39, 46, 60, 79]
x2 = [19, 39, 46, 60, 79, 90]
alpha_list = [-0.8402, -0.6652, 0.0, -0.5106, -0.8074, 0.0]
verts = np.dstack((np.c_[x1, x2], np.zeros((len(x1), 2))))
fig, ax = plt.subplots()
lc = LineCollection(verts, linewidth=40, cmap="Blues_r", array=np.array(alpha_list))
ax.add_collection(lc)
ax.autoscale()
ax.set_ylim(-1,1)
fig.colorbar(lc)
plt.show()
I think a workaround would be to use plt.barh. Here is an example using normalized color maps. Each color gets converted to RGBA before it can be passed to plt.barh.
import matplotlib.pyplot as plt
from matplotlib import colors
import matplotlib.cm as cmx
x1 =[0, 19, 39, 46, 60, 79]
x2 = [19, 39, 46, 60, 79, 90]
values = range(len(x1))
jet = cm = plt.get_cmap('jet')
cNorm = colors.Normalize(vmin=0, vmax=values[-1])
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
fig, ax = plt.subplots()
for idx, x, y in zip(values,x1, x2):
colorVal = scalarMap.to_rgba(values[idx])
start = x
end = y
width=end-start
ax.barh(y = 0, width = width, left=start, height = 0.1, label = str(idx), color=colorVal)
ax.set_ylim(-.5,0.5)
ax.legend()
which returns:
If you really want to just change the alpha transparency of a single color, you would just have to input alpha_list[idx] for the last element to the RGBA tuple colorVal. For some reason, RGBA did not like negative alpha values, so notice I changed them all to positive
fig, ax = plt.subplots()
alpha_list = [0.8402, 0.6652, 0.01, 0.5106, 0.8074, 0.0]
for idx, x, y in zip(values,x1, x2):
colorVal = (0.0, 0.3, 1.0, alpha_list[idx])
start = x
end = y
width=end-start
ax.barh(y = 0, width = width, left=start, height = 0.1, label = str(idx), color=colorVal)
ax.set_ylim(-.5,0.5)
ax.legend()

Creating a Surface of Revolution

I have a 3d plot of a disk, here is the code:
ri = 100
ra = 300
h=20
# input xy coordinates
xy = np.array([[ri,0],[ra,0],[ra,h],[ri,h],[ri,0]])
# radial component is x values of input
r = xy[:,0]
# angular component is one revolution of 30 steps
phi = np.linspace(0, 2*np.pi, 50)
# create grid
R,Phi = np.meshgrid(r,phi)
# transform to cartesian coordinates
X = R*np.cos(Phi)
Y = R*np.sin(Phi)
# Z values are y values, repeated 30 times
Z = np.tile(xy[:,1],len(Y)).reshape(Y.shape)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection='3d')
ax.set_zlim(0,200)
ax.plot_surface(X, Y, Z, alpha=0.5, color='grey', rstride=1, cstride=1)
I get this nice plot:
Further I have this plot:
The code is:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
arr = np.array([[100, 15],
[114.28, 17],
[128.57, 18],
[142.85, 19],
[157.13, 22],
[171.13, 24],
[185.69, 25],
[199.97, 27],
[214.25, 28],
[228.53, 30],
[242.81, 31],
[257.09, 35],
[271.37, 36],
[288.65, 37],
[300, 38]])
#interpolating between the single values of the arrays
new_x = np.concatenate([np.linspace(arr[i,0],arr[i+1,0], num=50)
for i in range(len(arr)-1)])
new_y = np.interp(new_x, arr[:,0], arr[:,1])
t=np.arange(700)
p = plt.scatter(new_x,new_y,c=t, cmap="jet")
#inserting colorbar
cax, _ = mpl.colorbar.make_axes(plt.gca(), shrink=0.8)
cbar = mpl.colorbar.ColorbarBase(cax, cmap='jet', label='testvalues',
norm=mpl.colors.Normalize(15, 40))
plt.show()
Now my question:
Is there a way to plot this 2d graph into my 3d environment? Further is it possible to create a surface out of this line (points) by rotating them around the middlepoint ? I tried it the same way like I did it with my disk but I failed because I think I need a closed contour ? Here is a picture to understand better what I want:
I'm not sure how you want to include your 2d plot, so here's how you do it as a surface of revolution.
Your new_x corresponds to radial distance, new_y corresponds to height. So we need to generate an array of angles for which to generate the "cone":
from matplotlib import cm
tmp_phi = np.linspace(0,2*np.pi,50)[:,None] # angle data
linesurf_x = new_x*np.cos(tmp_phi)
linesurf_y = new_x*np.sin(tmp_phi)
linesurf_z = np.broadcast_to(new_y, linesurf_x.shape)
linesurf_c = np.broadcast_to(t, linesurf_x.shape) # color according to t
colors = cm.jet(linesurf_c/linesurf_c.max()) # grab actual colors for the surface
ax.plot_surface(linesurf_x, linesurf_y, linesurf_z, facecolors=colors,
rstride=1, cstride=1)
Result:

Categories