Issues when using subplots with yellowbrick and losing legend and titles - legend

I'm having issues when putting multiple yellowbrick charts into a subplot arrangement. The title and legend only show for the last chart. I've tried multiple ways to write the code but can't get all of them to show the legends and titles. I'm sure its straightforward to get to work.
Here's a piece of code:
f, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2,figsize=(14, 10))
viz = FeatureImportances(LinearRegression(), ax=ax1)
viz.fit(X_train, y_train)
viz = LearningCurve(LinearRegression(), scoring='r2',cv=10, ax=ax2)
viz.fit(X_train, y_train)
viz = ResidualsPlot(clf, ax=ax3)
viz.fit(X_train, y_train)
viz = PredictionError(LinearRegression(), ax=ax4)
viz.fit(X_train, y_train)
viz.score(X_test, y_test)
viz.poof()
image of plots

#chris-mangum sorry that you have struggled with this. Besides show we have another method called finalize In this case, finalize is better than show -- show calls finalize and then either show or savefig which concludes the figure, so in a multi-axes plot like you have, you don't want to call poof.
f, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2,figsize=(14, 10))
viz = FeatureImportances(LinearRegression(), ax=ax1)
viz.fit(X_train, y_train)
viz.finalize()
viz = LearningCurve(LinearRegression(), scoring='r2',cv=10, ax=ax2)
viz.fit(X_train, y_train)
viz.finalize()
viz = ResidualsPlot(clf, ax=ax3)
viz.fit(X_train, y_train)
viz.finalize()
viz = PredictionError(LinearRegression(), ax=ax4)
viz.fit(X_train, y_train)
viz.score(X_test, y_test)
viz.finalize()

Related

updating subplots in real time using pyplot

I recently came across a way to refresh a plot with an incoming data stream.
The gist of the script is shown below.
plt.show(block=False) fig = plt.figure()
ax = plt.imshow(data_array, cmap='Greens', interpolation='None',clim=[0, 1], origin='lower', extent=extent, aspect='auto')
for i in range(100):
updating data_array...
ax.set_array(data_array)
fig.canvas.draw()
fig.canvas.flush_events()
This worked very well for a single plot and I wanted to apply this to have two subplots being refreshed in real time.
Below is what I tried.
plt.show(block=False)
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
ax1 = plt.imshow(data_array_1, cmap='Greens', interpolation='None',clim=[0, 1], origin='lower', extent=extent, aspect='auto')
ax2 = plt.imshow(data_array_2, cmap='Greens', interpolation='None',clim=[0, 1], origin='lower', extent=extent, aspect='auto')
for i in range(100):
updating data_array_1... and data_array_2
ax1.set_array(data_array_1)
ax2.set_array(data_array_2)
fig.canvas.draw()
fig.canvas.flush_events()
Unfortunately, this ended up not working as I hoped.

Get a sample of one image per class with image_dataset_from_directory

I am trying to visualize Skin Cancer Images using Keras. I have imported the images in my notebook and have created batch datasets using Keras.image_dataset_from_directory. The code is as follows:
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="training",
seed=1337,
image_size=image_size,
batch_size=batch_size)
Now, I have been trying to visualize the images. However, I want one image from each class (there are 9 classes in the dataset). I have used the below code:
plt.figure(figsize = (10,10))
for images, labels in train_ds.take(1):
for i in range(9):
ax = plt.subplot(3,3,i+1)
plt.imshow(images[i].numpy().astype("uint8"))
plt.title(class_names[labels[i]])
plt.axis("off")
This code gets me a lot of duplicate classes. How do I get one value for each class (in this case I have 9 classes. I want one plot for each of those 9 classes). I am not sure how to fetch unique images and their labels from a BatchDataset!
for i in range(len(class_names)):
filtered_ds = train_ds.filter(lambda x, l: tf.math.equal(l[0], i))
for image, label in filtered_ds.take(1):
ax = plt.subplot(3, 3, i+1)
plt.imshow(image[0].numpy().astype('uint8'))
plt.title(class_names[label.numpy()[0]])
plt.axis('off')
You could loop through and filter on each label.
Example:
import tensorflow as tf
# fake images
imgs = tf.random.normal([100, 64, 64, 3])
# fake labels
labels = tf.random.uniform([100], minval=0, maxval=10, dtype=tf.int32)
# make dataset
ds = tf.data.Dataset.from_tensor_slices((imgs, labels))
for i in range(9):
filtered = ds.filter(lambda _, l: tf.math.equal(l, i))
for img, label in filtered.take(1):
assert label.numpy() == i
# plot image
Try Following Code - This works perfectly to display one image from each of the 10 categories of cifar10:
import numpy as np
import matplotlib.pyplot as plt
from tensorflow import keras
(x_train, y_train), (x_test, y_test)= keras.datasets.cifar10.load_data()
fig, ax= plt.subplots(nrows= 2, ncols= 5, figsize= (18,5))
plt.suptitle('displaying one image of each category in train set'.upper(),
y= 1.05, fontsize= 16)
i= 0
for j in range(2):
for k in range(5):
ax[j,k].imshow(x_train[list(y_train).index(i)])
ax[j,k].axis('off')
ax[j,k].set_title(i)
i+=1
plt.tight_layout()
plt.show()

Plotting 3D Decision Boundary From MLPClassifier By Using make_classification Dataset

I used make_classification library and MLPClassifier from sklearn. However, I could not make my points separated like on this screenshot. And this screenshot is what my plot shows. Could you help me to separate the points or what is the problem?
My code is:
from sklearn.datasets import make_classification
X,y=make_classification(n_samples=550, n_features=10, n_informative=2,random_state=0)
from sklearn.model_selection import train_test_split
X_train,X_test , y_train , y_test = train_test_split(X, y, test_size=0.3, random_state=1)
from sklearn.neural_network import MLPClassifier
mlp= MLPClassifier(hidden_layer_sizes=(), max_iter=300, random_state=0)
clf = mlp.fit(X_test, y_test)
z = lambda x,y: (-clf.intercepts_[0]-clf.coefs_[0][0]*x -clf.coefs_[0][1]*y) / clf.coefs_[0][2]
tmp = np.linspace(-5,5,30)
x,y = np.meshgrid(tmp,tmp)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X_test[y_test==0,0]+2, X_test[y_test==0,1]-2, X_test[y_test==0,2]-5, c='b', marker='^')
ax.scatter(X_test[y_test==1,0]-2, X_test[y_test==1,1]+2, X_test[y_test==1,2]+5, c='r', marker='o')
ax.plot_surface(x, y, z(x,y))
ax.view_init(30, 60)
plt.show()
There is nothing (seriously) wrong on your code. You need to set some parameters to get what you desire. First, you may need larger figure.
# To set figure size other than the default value, specify width and height
fig = plt.figure( figsize=(8,8) )
Secondly, for the size of markers in scatter() function:
# To set marker size, use `s=number` as an option
ax.scatter(X_test[y_test==0,0]+2, X_test[y_test==0,1]-2, X_test[y_test==0,2]-5, \
c='b', marker='^', s=3)
ax.scatter(X_test[y_test==1,0]-2, X_test[y_test==1,1]+2, X_test[y_test==1,2]+5, \
c='r', marker='o', s=3)
The plot should be similar to this:

Three plot in one figure using Matplotlib

I want my plot to look like the image below, how can I achieve that using Matplotlib?
And thanks
You can use GridSpec similar to this tutorial. Possibly there will be not enough space for the y tick labels, which can be mitigated by increasing the default wspace.
import matplotlib.pyplot as plt
fig, axs = plt.subplots(ncols=4, nrows=2, figsize=(12, 7), gridspec_kw={'wspace': 0.4})
gs = axs[0, 0].get_gridspec()
for ax in axs.ravel():
ax.remove()
ax1 = fig.add_subplot(gs[0, :2])
ax1.set_ylabel('A')
ax2 = fig.add_subplot(gs[0, 2:])
ax2.set_ylabel('B')
ax3 = fig.add_subplot(gs[1, 1:3])
ax3.set_ylabel('C')
for ax in (ax1, ax2, ax3):
ax.set_xlabel('D')
ax.legend(handles=[], title='legend', loc='upper right', frameon=False)
plt.show()

How to animate multiple histograms simultaneously using incremental visualization with matplotlib? [duplicate]

I have the following animated subplots that simulate histograms of four different distributions:
import numpy
from matplotlib.pylab import *
import matplotlib.animation as animation
n = 100
# generate 4 random variables from the random, gamma, exponential, and uniform distributions
x1 = np.random.normal(-2.5, 1, 10000)
x2 = np.random.gamma(2, 1.5, 10000)
x3 = np.random.exponential(2, 10000)+7
x4 = np.random.uniform(14,20, 10000)
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)
def updateData(curr):
if curr == n:
a.event_source.stop()
ax1.hist(x1[:curr], normed=True, bins=20, alpha=0.5)
ax2.hist(x2[:curr], normed=True, bins=20, alpha=0.5)
ax3.hist(x3[:curr], normed=True, bins=20, alpha=0.5)
ax4.hist(x4[:curr], normed=True, bins=20, alpha=0.5)
simulation = animation.FuncAnimation(fig, updateData, interval=20, repeat=False)
plt.show()
It works, but for some reason the normed=True is being ignored for the y-axis scaling. If I take these plots out of the animation, they scale properly. How do I get proper scaling in the animation?
EDIT
Instead of having a scale like this (outside of animation):
I get (inside of animation):
The normed = True argument to the histogram makes the histogram plot the density of the distribution. From the documentation:
normed : boolean, optional
If True, the first element of the return tuple will be the counts normalized to form a probability density, i.e., n/(len(x)`dbin), i.e., the integral of the histogram will sum to 1. If stacked is also True, the sum of the histograms is normalized to 1.
Default is False
This means that the hight of the histogram bar depends on the bin width. If only one data point is plotted as is the case at the beginning of the animation the bar height will be 1./binwidth. If the bin width is smaller than zero, the bar height might become very large.
It's therefore a good idea to fix the bins and use them throughout the animation.
It's also reasonable to clear the axes such that there are not 100 different histograms being plotted.
import numpy as np
from matplotlib.pylab import *
import matplotlib.animation as animation
# generate 4 random variables from the random, gamma, exponential, and uniform distribution
x1 = np.random.normal(-2.5, 1, 10000)
x2 = np.random.gamma(2, 1.5, 10000)
x3 = np.random.exponential(2, 10000)+7
x4 = np.random.uniform(14,20, 10000)
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)
def updateData(curr):
if curr <=2: return
for ax in (ax1, ax2, ax3, ax4):
ax.clear()
ax1.hist(x1[:curr], normed=True, bins=np.linspace(-6,1, num=21), alpha=0.5)
ax2.hist(x2[:curr], normed=True, bins=np.linspace(0,15,num=21), alpha=0.5)
ax3.hist(x3[:curr], normed=True, bins=np.linspace(7,20,num=21), alpha=0.5)
ax4.hist(x4[:curr], normed=True, bins=np.linspace(14,20,num=21), alpha=0.5)
simulation = animation.FuncAnimation(fig, updateData, interval=50, repeat=False)
plt.show()
Yeah!! I also faced the same problem,
if you are getting such kind of problem don't forget to clear the axis before displaying each frame of the animation.
use
plt.cla()
or
ax.clear()(in your case)
for each axis
before doing the plot in the function defined for animation
Got it!
My iterating over n was the culprit. This does what I expected:
def updateData(curr):
curr2=100+curr*5
#if curr == n:
# a.event_source.stop()
ax1.hist(x1[:curr2], normed=True, bins=20, alpha=0.5)
ax2.hist(x2[:curr2], normed=True, bins=20, alpha=0.5)
ax3.hist(x3[:curr2], normed=True, bins=20, alpha=0.5)
ax4.hist(x4[:curr2], normed=True, bins=20, alpha=0.5)
simulation = animation.FuncAnimation(fig, updateData, frames=900, interval=10)
plt.show()