matplotlib - mask portion of standalone colorbar - matplotlib

Below is the code to build a standalone continuous colorbar. I would like to mask, with black, all values between -3 and 3.
import matplotlib.pyplot as plt
import matplotlib as mpl
fig, ax = plt.subplots(figsize=(8, .25))
cmap = mpl.cm.twilight
norm = mpl.colors.Normalize(vmin=-9.6, vmax=9.6)
cbar = mpl.colorbar.ColorbarBase(ax, cmap=cmap, norm=norm, orientation='horizontal', ticks=[-3,3])

The function colors.ListedColormap creates a new colormap from a list of colors. The following code retrieves these colors from an existing map and makes the desired modifications:
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
cmap = mpl.cm.get_cmap('twilight', 256)
norm = mpl.colors.Normalize(vmin=-9.6, vmax=9.6)
maskedcolors = cmap(np.linspace(0, 1, 256))
black = np.array([0, 0, 0, 1])
maskedcolors[int(round(norm(-3) * 256)) : int(round(norm(3) * 256)) + 1] = black
maskedcmp = mpl.colors.ListedColormap(maskedcolors)
fig, ax = plt.subplots(figsize=(8, .5))
cbar = mpl.colorbar.ColorbarBase(ax, cmap=maskedcmp, norm=norm, orientation='horizontal', ticks=[-3, 3])
fig.subplots_adjust(bottom=0.5)
plt.show()

Related

Colorbar in plots with embedded plots

While I managed to put a plot inside a plot (see the question here), I am finding trouble putting a colorbar to the larger (outside) plot. The code below is as simple as it gets, but for some reason it places the colorbar in the wrong axis:
import numpy as np
from numpy import random
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
# Canvas
fig, ax1 = plt.subplots(figsize=(12, 10))
left, bottom, width, height = [0.65, 0.15, 0.32, 0.30]
ax2 = fig.add_axes([left, bottom, width, height])
# Labels
xlabel = 'x'
ylabel = 'y'
cbarlabel = 'Color'
cmap = plt.get_cmap('turbo')
# Data
x, y, z = np.random.rand(3,200)
# Plotting
sc = ax1.scatter(x, y, marker='o', c=z, cmap=cmap)
ax2.scatter(x, y, c=z, cmap=cmap)
#
ax1.set_xlabel(xlabel)
ax1.set_ylabel(ylabel)
ax1.legend(fontsize=12, loc='upper left')
plt.tight_layout()
# Colormap
ax1 = plt.gca()
divider = make_axes_locatable(plt.gca())
cax = divider.append_axes("right", "2%", pad="1%")
cbar = plt.colorbar(sc, cax=cax) # Colorbar
cbar.set_label(cbarlabel, rotation=270, labelpad=30)
sc.set_clim(vmin=min(z), vmax=max(z))
#
plt.show()
I have also tried inset_axes as in the documentation example, to no avail.
The trick is to actually set active axes with plt.sca(ax1) and then create colorbar. I also simplified a code little bit.
Here is modified code putting colormap to the large plot:
import matplotlib.pyplot as plt
import numpy as np
from numpy import random
# Canvas
fig, ax1 = plt.subplots(figsize=(12, 10))
left, bottom, width, height = [0.45, 0.15, 0.32, 0.30]
ax2 = fig.add_axes([left, bottom, width, height])
# Labels
xlabel = 'x'
ylabel = 'y'
cbarlabel = 'Color'
cmap = plt.get_cmap('turbo')
# Data
x, y, z = np.random.rand(3,200)
# Plotting
sc = ax1.scatter(x, y, marker='o', c=z, cmap=cmap)
ax2.scatter(x, y, c=z, cmap=cmap)
# Set active axes
plt.sca(ax1)
cbar = plt.colorbar(sc) # Colorbar
cbar.set_label(cbarlabel, rotation=270, labelpad=30)
sc.set_clim(vmin=min(z), vmax=max(z))
#
ax1.set_xlabel(xlabel)
ax1.set_ylabel(ylabel)
ax1.legend(fontsize=12, loc='upper left')
plt.tight_layout()
plt.show()
Resulting in:

Interactive matplotlib : generate and display a new image each time slider bar is moved

So, I created an ML model that takes 4 variables as inputs, that range from -1 to 1 (e.g.variables= [0.5, 0.4, -0.3, 0.9 ].
Each combination of these variables generates a different image, which I can then plot.
gen_imgs = gen_mdl.predict([variables])
# Rescale images 0 - 1
gen_imgs = 0.5 * gen_imgs + 0.5
image=255-(gen_imgs[0,:,:,0]*255)
plt.figure(figsize=(3,4))
plt.imshow(image1, cmap='gray')
plt.axis('off')
plt.show()
I've tried editing the following code to get the results I'm looking for but keep hitting errors.
%matplotlib notebook
from ipywidgets import *
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
line, = ax.plot(x, np.sin(x))
def update(w = 1.0):
line.set_ydata(np.sin(w * x))
fig.canvas.draw()
interact(update)
UPDATE: I figured it out. Only thing I can't seem to figure out is how to limit the latent variable slider between ranges -1 to 1. This is my code:
%matplotlib notebook
from ipywidgets import *
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(4,2))
ax = fig.add_subplot(1, 1, 1)
line = ax.imshow(image1, cmap='gray')
plt.axis('off')
def update(lv_1 = 1.0):
noise[0][0]=lv_1
gen_imgs = gen_mdl.predict([noise,vfs])
gen_imgs = 0.5 * gen_imgs + 0.5
updated_image=255-(gen_imgs[0,:,:,0]*255)
line.set_data(updated_image)
fig.canvas.draw()
interact(update)

Show evaluation metrics in decision boundary plot

I am working on imbalanced classification. I wanted to add g-mean, and accuracy in my decision boundary plot. It would be nice to see the differences of these scoring metrics in plot. I don't see any option to compute these scores within this decision boundary plot. Is there way I can add this extra information in my decision boundary plot. I appreciate your time. Thanks!
import numpy as np
import matplotlib.pyplot as plt
from mlxtend.plotting import plot_decision_regions
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_blobs
from sklearn.metrics import make_scorer
from imblearn.metrics import geometric_mean_score
from mlxtend.plotting import plot_decision_regions
import matplotlib.gridspec as gridspec
import itertools
gmean = make_scorer(geometric_mean_score, greater_is_better=True)
scoring = {'G-mean': gmean, 'Accuracy':'accuracy'}
X, y = make_blobs(n_samples=[1000, 10],centers=[[0.0, 0.0], [2.0, 2.0]],cluster_std= [1.5, 0.5],random_state=0, shuffle=False)
clf1 = LogisticRegression(max_iter=100000)
clf2 = LogisticRegression(class_weight="balanced",max_iter=100000)
gs = gridspec.GridSpec(2, 2)
fig = plt.figure(figsize=(10,8))
labels = ['Logistic Regression', 'Weighted Logistic Regression']
for clf, lab, grd in zip([clf1, clf2],
labels,
itertools.product([0, 1], repeat=2)):
clf.fit(X, y)
ax = plt.subplot(gs[grd[0], grd[1]])
fig = plot_decision_regions(X=X, y=y, clf=clf, legend=2)
plt.title(lab)
plt.show()
You can use plt.text() to add g-mean, and accuracy in your decision boundary plot.
For example:
gs = gridspec.GridSpec(2, 2)
fig = plt.figure(figsize=(15, 8))
labels = ['Logistic Regression', 'Weighted Logistic Regression']
for clf, lab, grd in zip([clf1, clf2],
labels,
itertools.product([0, 1], repeat=2)):
clf.fit(X, y)
ax = plt.subplot(gs[grd[0], grd[1]])
ax.text(6, 4, "gmean : ", fontsize=10)
ax.text(6, 2, "accuracy : ", fontsize=10)
fig = plot_decision_regions(X=X, y=y, clf=clf, legend=2)
plt.title(lab)
plt.show()

height of colorbar in subplot (matplotlib)

We can change the height and width and position of colorbar by using :
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
fig = plt.figure()
ax = plt.subplot(111)
im = ax.imshow(np.arange(100).reshape((10, 10)))
c = plt.colorbar(im, cax = fig.add_axes([0.78, 0.5, 0.03, 0.38]))
from here,
I am going to use this in subplots with add_axes and transorm:
fig, axs = plt.subplots(nrows=1, ncols=2)
im0 = axs[0].imshow(np.arange(100).reshape((10, 10)), cmap='afmhot')
c = plt.colorbar(im0, cax=fig.add_axes([0.45, 0.52, 0.03, 0.2],
transform=axs[0].transAxes))
# transform=axs[0].transAxes) does not make any difference
im1 = axs[1].imshow(np.arange(100).reshape((10, 10)), cmap='afmhot_r')
c = plt.colorbar(im1, cax=fig.add_axes([0.87, 0.52, 0.03, 0.2]))
I am going to use transform (transAxes) option to set the location from axes not the figure, but it does not work.
First of all, from the add_axes documentation,
rect : sequence of float
The dimensions [left, bottom, width, height] of the new axes. All quantities are in
fractions of figure width and height.
This is the reason your code doesn't work.
You may instead use an inset_axes.
inset_axes(self, bounds, transform=None, ...)
bounds : [x0, y0, width, height]
Lower-left corner of inset axes, and its width and height.
transform : Transform
Defaults to ax.transAxes, i.e. the units of rect are in axes-relative coordinates.
Here the bounds default to units of axes coordinates, but can be changed if needed.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
im = ax.imshow(np.arange(100).reshape((10, 10)))
cax = ax.inset_axes([0.78, 0.5, 0.03, 0.38])
cb = fig.colorbar(im, cax = cax)
plt.show()
An alternative to the above is to use mpl_toolkits.axes_grid1.inset_locator.inset_axes.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
import numpy as np
fig, ax = plt.subplots()
im = ax.imshow(np.arange(100).reshape((10, 10)))
cax = inset_axes(ax, "100%", "100%", bbox_to_anchor=[0.78, 0.5, 0.03, 0.38],
bbox_transform=ax.transAxes, borderpad=0)
cb = fig.colorbar(im, cax = cax)
plt.show()

Record interactive plot

The following code works fine to save an animation to file:
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation
Writer = animation.writers['ffmpeg']
writer = Writer(fps=15, bitrate=1800)
fig, ax = plt.subplots()
ims = []
x = np.linspace(0, np.pi,200)
for theta in np.linspace(0, np.pi, 50):
plot = ax.plot(x, np.sin(x + theta))
ims.append(plot)
im_ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True)
im_ani.save('im.mp4', writer=writer)
Now, I would like to view the animation interactively as the plots are generated, while still saving it to file. I therefore tried the following code:
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation
Writer = animation.writers['ffmpeg']
writer = Writer(fps=15, bitrate=1800)
plt.ion()
fig, ax = plt.subplots()
ims = []
x = np.linspace(0, np.pi, 200)
for theta in np.linspace(0, np.pi, 50):
ax.clear()
plot = ax.plot(x, np.sin(x + theta))
ims.append(plot)
plt.draw()
plt.pause(0.01)
im_ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True)
im_ani.save('im.mp4', writer=writer)
which lets me view the animation interactively, but the resulting video file contains only blank frames.
Is is possible to view an animation interactively and save it to file at the same time? What is the issue with my code?