I'm creating the heat map of a function with tuneable exponent. Here is my code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons
from matplotlib.colors import LogNorm
alpha0 = 2.
fig, ax = plt.subplots()
plt.subplots_adjust(left=0.25, bottom=0.25)
bining = np.logspace(1, 10, 1000)
x = y = bining
X, Y = np.meshgrid(x, y)
Z = [[0 for i in xrange(len(x) - 1)] for j in xrange(len(y) - 1) ]
for i in xrange(len(x) - 1):
for j in xrange(len(y) - 1):
Z[i][j] = 1./((x[i]+y[j])**(2+alpha0))
Z = np.array(Z)
im = plt.pcolormesh(X,Y,Z, cmap = plt.cm.Spectral, norm=LogNorm())
plt.xscale('log')
plt.yscale('log')
plt.axes().set_aspect('equal')
axcolor = 'lightgoldenrodyellow'
axexp = plt.axes([0.25, 0.15, 0.65, 0.03], axisbg=axcolor)
sexp = Slider(axexp, r"$\alpha$", 0.1, 10.0, valinit=alpha0)
def update(val):
alpha = sexp.val
Z = [[0 for i in xrange(len(x) - 1)] for j in xrange(len(y) - 1) ]
for i in xrange(len(x) - 1):
for j in xrange(len(y) - 1):
Z[i][j] = 1./((x[i]+y[j])**(2+alpha))
Z = np.array(Z)
plt.pcolormesh(X,Y,Z, cmap = plt.cm.Spectral, norm=LogNorm())
fig.canvas.draw_idle()
sexp.on_changed(update)
It creates the figure and the slider, but when I try to change the exponent value, the heat map is not affected.
So my question, why is it not working and how can I solve it ? Also, widgets can be saved ? In what format ? Eventually I would use in a Beamer (LaTeX) presentation.
Thank you !
Related
I am plotting a graph using matplotlib.
Here is the code:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_title("Grid search results - " + model_name)
ax.set_xlabel("Log10(Wight decay)")
ax.set_ylabel("Log10(Learning rate)")
ax.set_zlabel("Batch size")
ax.set_xticks(weightdecay)
ax.set_yticks(learningrate)
ax.set_zticks(trainbatchsize)
scat_plot = ax.scatter(xs=weightdecay, ys=learningrate, zs=trainbatchsize, c=f1, cmap="bwr")
ax.text(top_score[0], top_score[1], top_score[2], top_score[3], color="black")
cb = plt.colorbar(scat_plot, pad=0.2)
cb.ax.set_xlabel('F1 score')
plt.plot(top_score[0], top_score[1], top_score[2], marker="o", markersize=15, markerfacecolor="yellow")
path = Path(output_dir)
plt.savefig(str(path.absolute()) + '/grid_search_plot_' + model_name + ".pdf")
plt.show()
The graph I am getting looks like:
What I would like to do is to use a more granular color-bar. For example for my F1-score (colour-bar), show in:
color1 scores < 0.5
color2 scores 0.5 - 0.75
color3 scores 0.75 - 0.80
color4 scores 0.8 - 0.85
color5 scores 0.85-1
I was trying to re-use some code to create a custom cmap but nothing was working as expected.
One cheap/quick solution might be to create a "categorical color value", like this:
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib.colors import ListedColormap
import numpy as np
N = 40
x = np.random.uniform(0, 1, N)
y = np.random.uniform(0, 1, N)
z = np.random.uniform(0, 1, N)
# color values
c = np.random.uniform(0, 1, N)
# new color values
new_col = c.copy()
new_col[c < 0.5] = 0
new_col[(c >= 0.5) & (c < 0.75)] = 1
new_col[(c >= 0.75) & (c < 0.8)] = 2
new_col[(c >= 0.8) & (c < 0.85)] = 3
new_col[c >= 0.85] = 4
new_col = new_col / new_col.max()
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
scatter = ax.scatter(x, y, z, c=new_col, cmap=cm.get_cmap("tab10", 5))
cb = fig.colorbar(scatter)
cb.ax.set_yticklabels([0, 0.5, 0.75, 0.80, 0.85, 1])
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.set_zlim(0, 1)
EDIT to accommodate comments. The following should be able to deal with cases in which a category doesn't have any element:
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib.colors import ListedColormap
import numpy as np
N = 40
x = np.random.uniform(0, 1, N)
y = np.random.uniform(0, 1, N)
z = np.random.uniform(0, 1, N)
# color values
c = np.random.uniform(0, 1, N)
# number of categories
NC = 5
# new color values
new_col = c.copy()
new_col[c < 0.5] = 0
new_col[(c >= 0.5) & (c < 0.75)] = 1
new_col[(c >= 0.75) & (c < 0.8)] = 2
new_col[(c >= 0.8) & (c < 0.85)] = 3
new_col[c >= 0.85] = 4
new_col = new_col / NC
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
cmap = ListedColormap(["red", "green", "blue", "magenta", "cyan"])
scatter = ax.scatter(x, y, z, c=cmap(new_col))
cb = fig.colorbar(cm.ScalarMappable(cmap=cmap))
cb.ax.set_yticks(np.linspace(0, 1, NC+1), [0, 0.5, 0.75, 0.80, 0.85, 1])
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.set_zlim(0, 1)
I want to build a graph that will look like this, - for each point I have a single value and there is a maximum that reaches the border.
All I can find is how to have hexbin in a scatterplot with seaborn or similar - any ideas, is there some ready solution maybe or I would need to code my way through it?
You could use tripcolor to show 6 shaded triangles. Scaling the outer vectors can adapt the triangles to show the desired proportions.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as tri
proportions = [0.6, 0.75, 0.8, 0.9, 0.7, 0.8]
labels = ['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta']
N = len(proportions)
proportions = np.append(proportions, 1)
theta = np.linspace(0, 2 * np.pi, N, endpoint=False)
x = np.append(np.sin(theta), 0)
y = np.append(np.cos(theta), 0)
triangles = [[N, i, (i + 1) % N] for i in range(N)]
triang_backgr = tri.Triangulation(x, y, triangles)
triang_foregr = tri.Triangulation(x * proportions, y * proportions, triangles)
cmap = plt.cm.rainbow_r # or plt.cm.hsv ?
colors = np.linspace(0, 1, N + 1)
plt.tripcolor(triang_backgr, colors, cmap=cmap, shading='gouraud', alpha=0.4)
plt.tripcolor(triang_foregr, colors, cmap=cmap, shading='gouraud', alpha=0.8)
plt.triplot(triang_backgr, color='white', lw=2)
for label, color, xi, yi in zip(labels, colors, x, y):
plt.text(xi * 1.05, yi * 1.05, label, # color=cmap(color),
ha='left' if xi > 0.1 else 'right' if xi < -0.1 else 'center',
va='bottom' if yi > 0.1 else 'top' if yi < -0.1 else 'center')
plt.axis('off')
plt.gca().set_aspect('equal')
plt.show()
The code allows for different numbers of triangles. Here are examples with 5 or 6 triangles:
I have a code like this, and it will present a figure with the x-axis from 1 to 200, and the y-axis also from 1 to 200. But I would like to make the two axes both from -1.5 to 1.5 with 0.5 space.
I have already tried "plt.xticks" and "set_xlim", but I still cannot make it.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
from scipy.stats import multivariate_normal
fig, main_ax = plt.subplots(figsize=(5, 5))
divider = make_axes_locatable(main_ax)
top_ax = divider.append_axes("top", 1.05, pad=0.1,sharex=main_ax)
top_ax.xaxis.set_tick_params(labelbottom=False)
main_ax.set_xlabel('dim 1')
main_ax.set_ylabel('dim 2')
top_ax.set_ylabel('Z profile')
x, y = np.mgrid[-1:1:.01, -1:1:.01]
pos = np.empty(x.shape + (2,))
pos[:, :, 0] = x; pos[:, :, 1] = y
rv = multivariate_normal([-0.2, 0.2], [[1, 1.5], [0.25, 0.25]])
z = rv.pdf(pos)
z_max = z.max()
plt.set_cmap(plt.cm.gist_earth)
cur_x = 100
cur_y = 100
main_ax.imshow(z, origin='lower')
main_ax.autoscale(enable=False)
top_ax.autoscale(enable=False)
top_ax.set_ylim(top=z_max)
v_line = main_ax.axvline(cur_x, color='r')
h_line = main_ax.axhline(cur_y, color='y')
v_prof, = top_ax.plot(np.arange(x.shape[1])[::-1], z[:,int(cur_x)], 'r-')
h_prof, = top_ax.plot(np.arange(x.shape[0]), z[int(cur_y),:], 'y-')
plt.show()
You can simply use this code.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
from scipy.stats import multivariate_normal
fig, main_ax = plt.subplots(figsize=(5, 5))
divider = make_axes_locatable(main_ax)
top_ax = divider.append_axes("top", 1.05, pad=0.1,sharex=main_ax)
top_ax.xaxis.set_tick_params(labelbottom=False)
main_ax.set_xlabel('dim 1')
main_ax.set_ylabel('dim 2')
top_ax.set_ylabel('Z profile')
x, y = np.mgrid[-1:1:.01, -1:1:.01]
pos = np.empty(x.shape + (2,))
pos[:, :, 0] = x; pos[:, :, 1] = y
rv = multivariate_normal([-0.2, 0.2], [[1, 1.5], [0.25, 0.25]])
z = rv.pdf(pos)
z_max = z.max()
plt.set_cmap(plt.cm.gist_earth)
# For y axis
main_ax.set_yticks(np.linspace(0,200,7))
main_ax.set_yticklabels(np.linspace(-1.5,1.5,7))
# For x axis
plt.xticks(np.linspace(0,200,7),np.linspace(-1.5,1.5,7))
cur_x = 100
cur_y = 100
main_ax.imshow(z, origin='lower')
main_ax.autoscale(enable=False)
top_ax.autoscale(enable=False)
top_ax.set_ylim(top=z_max)
v_line = main_ax.axvline(cur_x, color='r')
h_line = main_ax.axhline(cur_y, color='y')
v_prof, = top_ax.plot(np.arange(x.shape[1])[::-1], z[:,int(cur_x)], 'r-')
h_prof, = top_ax.plot(np.arange(x.shape[0]), z[int(cur_y),:], 'y-')
I have an array of shape(512,512).
Looks like, (row=x, column=y, density=z=the number of the array)
[[0.012825 0.020408 0.022976 ... 0.015938 0.02165 0.024357]
[0.036332 0.031904 0.025462 ... 0.031095 0.019812 0.024523]
[0.015831 0.027392 0.031939 ... 0.016249 0.01697 0.028686]
...
[0.024545 0.011895 0.022235 ... 0.033226 0.03223 0.030235]]
I had already drawn it into a 2D density plot. My goal is to find the center of the circle and draw a vertical and horizontal cross-section in one figure.
Now, I have the trouble to find the center of the circle and combine two cross-sections in one figure.
Please help.
This is my code:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import scipy.ndimage
data = pd.read_csv('D:/BFP.csv', header=None)
# create data
data = np.array(data)
print(data)
#plot data
side = np.linspace(-1.5,1.5,512)
x,y = np.meshgrid(side,side)
z = [[data[i][j] for i in range(len(data[0]))]for j in range(len(data))]
#-- Extract the line...
# Make a line with "num" points...
x0, y0 = 270, 0 # These are in _pixel_ coordinates!!
x1, y1 = 270, 500
num = 512
x_, y_ = np.linspace(x0, x1, num), np.linspace(y0, y1, num)
# Extract the values along the line, using cubic interpolation
zi = scipy.ndimage.map_coordinates(z, np.vstack((x_,y_)))
#-- Plot...
fig, axes = plt.subplots(nrows=2)
axes[0].imshow(z,origin='lower')
axes[0].plot([x0, x1], [y0, y1], 'ro-')
#axes[0].axis('image')
axes[1].plot(zi)
plt.savefig('D:/vertical.png')
plt.show()
image here:
I cannot help you with finding the center of the circle, but you can create a nice visualization of the cross section by creating 3 axes in a grid. Usually, I would use GridSpec for this, but imhsow has a tendency to mess up the relative size of the axes to maintain square pixels. Thankfully, the AxesGrid toolkit can help.
The base of the code is inspired by this matplotlib example.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
from scipy.stats import multivariate_normal
import scipy
fig, main_ax = plt.subplots(figsize=(5, 5))
divider = make_axes_locatable(main_ax)
top_ax = divider.append_axes("top", 1.05, pad=0.1, sharex=main_ax)
right_ax = divider.append_axes("right", 1.05, pad=0.1, sharey=main_ax)
# make some labels invisible
top_ax.xaxis.set_tick_params(labelbottom=False)
right_ax.yaxis.set_tick_params(labelleft=False)
main_ax.set_xlabel('dim 1')
main_ax.set_ylabel('dim 2')
top_ax.set_ylabel('Z profile')
right_ax.set_xlabel('Z profile')
x, y = np.mgrid[-1:1:.01, -1:1:.01]
pos = np.empty(x.shape + (2,))
pos[:, :, 0] = x; pos[:, :, 1] = y
rv = multivariate_normal([-0.2, 0.2], [[1, 1.5], [0.25, 0.25]])
z = rv.pdf(pos)
z_max = z.max()
cur_x = 110
cur_y = 40
main_ax.imshow(z, origin='lower')
main_ax.autoscale(enable=False)
right_ax.autoscale(enable=False)
top_ax.autoscale(enable=False)
right_ax.set_xlim(right=z_max)
top_ax.set_ylim(top=z_max)
v_line = main_ax.axvline(cur_x, color='r')
h_line = main_ax.axhline(cur_y, color='g')
v_prof, = right_ax.plot(z[:,int(cur_x)],np.arange(x.shape[1]), 'r-')
h_prof, = top_ax.plot(np.arange(x.shape[0]),z[int(cur_y),:], 'g-')
plt.show()
Just for fun, you can even make it interactive
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
from scipy.stats import multivariate_normal
import scipy
fig, main_ax = plt.subplots(figsize=(5, 5))
divider = make_axes_locatable(main_ax)
top_ax = divider.append_axes("top", 1.05, pad=0.1, sharex=main_ax)
right_ax = divider.append_axes("right", 1.05, pad=0.1, sharey=main_ax)
# make some labels invisible
top_ax.xaxis.set_tick_params(labelbottom=False)
right_ax.yaxis.set_tick_params(labelleft=False)
main_ax.set_xlabel('dim 1')
main_ax.set_ylabel('dim 2')
top_ax.set_ylabel('Z profile')
right_ax.set_xlabel('Z profile')
x, y = np.mgrid[-1:1:.01, -1:1:.01]
pos = np.empty(x.shape + (2,))
pos[:, :, 0] = x; pos[:, :, 1] = y
rv = multivariate_normal([-0.2, 0.2], [[1, 1.5], [0.25, 0.25]])
z = rv.pdf(pos)
z_max = z.max()
main_ax.imshow(z, origin='lower')
main_ax.autoscale(enable=False)
right_ax.autoscale(enable=False)
top_ax.autoscale(enable=False)
right_ax.set_xlim(right=z_max)
top_ax.set_ylim(top=z_max)
v_line = main_ax.axvline(np.nan, color='r')
h_line = main_ax.axhline(np.nan, color='g')
v_prof, = right_ax.plot(np.zeros(x.shape[1]),np.arange(x.shape[1]), 'r-')
h_prof, = top_ax.plot(np.arange(x.shape[0]),np.zeros(x.shape[0]), 'g-')
def on_move(event):
if event.inaxes is main_ax:
cur_x = event.xdata
cur_y = event.ydata
v_line.set_xdata([cur_x,cur_x])
h_line.set_ydata([cur_y,cur_y])
v_prof.set_xdata(z[:,int(cur_x)])
h_prof.set_ydata(z[int(cur_y),:])
fig.canvas.draw_idle()
fig.canvas.mpl_connect('motion_notify_event', on_move)
plt.show()
NB: the lag is just due to the convertion in gif, the update is much smoother on my machine
I have the following (example) code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1, n_lines + 1)
norm = mpl.colors.Normalize(vmin=c.min(), vmax=c.max())
cmap = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.jet)
cmap.set_array([])
fig, ax = plt.subplots(dpi=100)
for i, yi in enumerate(y.T):
ax.plot(x, yi, c=cmap.to_rgba(i + 1))
fig.colorbar(cmap, ticks=c)
plt.show();
I would like to find a substirute for cmap.to_rgba that makes the colour of each line come out as a differnet shade of blue. Basically I want to keep the same layout as the result of this code, but using the colour map Blues.
How can I do it?
You need to change your colormap that you are using from jet to Blues.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1, n_lines + 1)
norm = mpl.colors.Normalize(vmin=c.min(), vmax=c.max())
cmap = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.Blues)
cmap.set_array([])
fig, ax = plt.subplots(dpi=100)
for i, yi in enumerate(y.T):
ax.plot(x, yi, c=cmap.to_rgba(i + 1))
fig.colorbar(cmap, ticks=c)
plt.show()
This produces: