Insert a png image in a matplotlib figure - python-3.x

I'm trying to insert a png image in matplotlib figure (ref)
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.figure import Figure
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
ax = plt.subplot(111)
ax.plot(
[1, 2, 3], [1, 2, 3],
'go-',
label='line 1',
linewidth=2
)
arr_img = plt.imread("stinkbug.png")
im = OffsetImage(arr_img)
ab = AnnotationBbox(im, (1, 0), xycoords='axes fraction')
ax.add_artist(ab)
plt.show()
Inset image:
Output obtained:
I'd like to know how to resize the image that has to be inserted to avoid overlaps.
EDIT:
Saving the figure
ax.figure.savefig("output.svg", transparent=True, dpi=600, bbox_inches="tight")

You can zoom the image and the set the box alignment to the lower right corner (0,1) plus some extra for the margins:
im = OffsetImage(arr_img, zoom=.45)
ab = AnnotationBbox(im, (1, 0), xycoords='axes fraction', box_alignment=(1.1,-0.1))
You may also want to use data coordinates, which is the default, and use the default box_alignment to the center, e.g. ab = AnnotationBbox(im, (2.6, 1.45)). See the xycoords parameter doc for more information about various coordinate options.

Related

Color Matplotlib Histogram Subplots by a Categorical Variable

I am trying to create histogram subplots whose values I want to color by a second, categorical variable.
A small subset of the data is below
data = {'ift': [0.031967, 0.067416, 0.091275, 0.046852, 0.100406],
'ine': [0.078384, 0.09554, 0.234695, 0.182821, 0.190237],
'ift_out': [1, 1, 0, 1, 0],
'ine_out': [1, 1, 0, 0, 1]}
xyz = pd.DataFrame(data)
xyz
My initial stab at it is also below. A bit stumped on the inclusion of the categorical columns as colors
fig, axs = plt.subplots(nrows=2, ncols=1, sharey=True, tight_layout=True)
axs[0].hist(xyz['ift']) # color = xyz['ift_out']
axs[1].hist(xyz['ine']) # color = xyz['ine_out']
plt.show()
Sample output is attached below
Following #JohanC's answer, I made the some changes to my original code as shown below, and that worked they way I wanted
import matplotlib.pyplot as plt
import seaborn as sns
sns.color_palette("tab10")
sns.set(style="darkgrid")
fig, axs = plt.subplots(nrows=1, ncols=2, tight_layout=True)
g = sns.histplot(data=xyz, x='ift',
hue='ift_out', palette=['skyblue','tomato'], multiple='stack', ax=axs[0])
g = sns.histplot(data=xyz, x='ine',
hue='ine_out', palette=['skyblue','tomato'], multiple='stack', ax=axs[1])

Renaming a single plot i a sequence of 5 plots

I have the 5 plots generated by the code below. What i need is a quick way to only rename the title of the 3th plot from dataset(100,33) to dataset-trial. Whats the fasted way to do that?
import numpy as np
import matplotlib.pyplot as plt
ratios = [(100, 2), (100, 20),(100,33),(100, 40), (100, 80)]
plt.figure(figsize = (20,6))
for j,i in enumerate(ratios):
plt.subplot(1, 5, j+1)
X_p=np.random.normal(0,0.05,size=(i[0],2))
X_n=np.random.normal(0.13,0.02,size=(i[1],2))
y_p=np.array([1]*i[0]).reshape(-1,1)
y_n=np.array([0]*i[1]).reshape(-1,1)
X=np.vstack((X_p,X_n))
y=np.vstack((y_p,y_n))
plt.title("dataset" + str(j+1) +str(i))
plt.scatter(X_p[:,0],X_p[:,1])
plt.scatter(X_n[:,0],X_n[:,1],color='red')
plt.show()
Thanks

How to visualize a list of strings on a colorbar in matplotlib

I have a dataset like
x = 3,4,6,77,3
y = 8,5,2,5,5
labels = "null","exit","power","smile","null"
Then I use
from matplotlib import pyplot as plt
plt.scatter(x,y)
colorbar = plt.colorbar(labels)
plt.show()
to make a scatter plot, but cannot make colorbar showing labels as its colors.
How to get this?
I'm not sure, if it's a good idea to do that for scatter plots in general (you have the same description for different data points, maybe just use some legend here?), but I guess a specific solution to what you have in mind, might be the following:
from matplotlib import pyplot as plt
# Data
x = [3, 4, 6, 77, 3]
y = [8, 5, 2, 5, 5]
labels = ('null', 'exit', 'power', 'smile', 'null')
# Customize colormap and scatter plot
cm = plt.cm.get_cmap('hsv')
sc = plt.scatter(x, y, c=range(5), cmap=cm)
cbar = plt.colorbar(sc, ticks=range(5))
cbar.ax.set_yticklabels(labels)
plt.show()
This will result in such an output:
The code combines this Matplotlib demo and this SO answer.
Hope that helps!
EDIT: Incorporating the comments, I can only think of some kind of label color dictionary, generating a custom colormap from the colors, and before plotting explicitly grabbing the proper color indices from the labels.
Here's the updated code (I added some additional colors and data points to check scalability):
from matplotlib import pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import numpy as np
# Color information; create custom colormap
label_color_dict = {'null': '#FF0000',
'exit': '#00FF00',
'power': '#0000FF',
'smile': '#FF00FF',
'addon': '#AAAAAA',
'addon2': '#444444'}
all_labels = list(label_color_dict.keys())
all_colors = list(label_color_dict.values())
n_colors = len(all_colors)
cm = LinearSegmentedColormap.from_list('custom_colormap', all_colors, N=n_colors)
# Data
x = [3, 4, 6, 77, 3, 10, 40]
y = [8, 5, 2, 5, 5, 4, 7]
labels = ('null', 'exit', 'power', 'smile', 'null', 'addon', 'addon2')
# Get indices from color list for given labels
color_idx = [all_colors.index(label_color_dict[label]) for label in labels]
# Customize colorbar and plot
sc = plt.scatter(x, y, c=color_idx, cmap=cm)
c_ticks = np.arange(n_colors) * (n_colors / (n_colors + 1)) + (2 / n_colors)
cbar = plt.colorbar(sc, ticks=c_ticks)
cbar.ax.set_yticklabels(all_labels)
plt.show()
And, the new output:
Finding the correct middle point of each color segment is (still) not good, but I'll leave this optimization to you.

Masking annotations in seaborn heatmap

I would like to make a heatmap that has annotation only in specific cells. I though one way to do this would be to make a heatmap with annotations in all cells and then overlay another heatmap that has no annotation but that is masked in the regions that I want the original annotations to be visible:
import numpy as np
import seaborn as sns
par_corr_p = np.array([[1, 2], [3, 4]])
masked_array = np.ma.array(par_corr_p, mask=par_corr_p<2)
fig, ax = plt.subplots()
sns.heatmap(par_corr_p, ax=ax, cmap ='RdBu_r', annot = par_corr_p, center=0, vmin=-5, vmax=5)
sns.heatmap(par_corr_p, mask = masked_array.mask, ax=ax, cmap ='RdBu_r', center=0, vmin=-5, vmax=5)
However, this is not working - the second heatmap is not covering up the first one:
Please advise
I tried a few things, including using numpy.nan or "" in the annot array. Unfortunately they don't work.
This is probably the easiest way. It involves grabbing the texts of the axes, which should only be the labels in annot which sns.heatmap puts there.
import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns
par_corr_p = np.array([[1, 2], [3, 4]])
data = par_corr_p
show_annot_array = data >= 2
fig, ax = plt.subplots()
sns.heatmap(
ax=ax,
data=data,
annot=data,
cmap ='RdBu_r', center=0, vmin=-5, vmax=5
)
for text, show_annot in zip(ax.texts, (element for row in show_annot_array for element in row)):
text.set_visible(show_annot)
plt.show()

matplotlib plot rotation 90 degree is not happening

I am finding the edges of the images using matplotlib.I have done almost.And i want to rotate the image as 90 degree in plot.But it is not working for me.I have tried many things.Below is my code what i have tried.
from scipy import misc
from skimage import color,measure
import matplotlib.pyplot as plt
from skimage.draw import ellipse
from skimage.measure import find_contours, approximate_polygon, subdivide_polygon
from PIL import Image
import numpy as np
filename = r"images/5601.jpg"
fimg = misc.imread(filename)
gimg = color.colorconv.rgb2grey(fimg)
contours = measure.find_contours(gimg, 0.8)
for n, contour in enumerate(contours):
plt.plot(contour[:, 1], contour[:, 0], linewidth=2)
contour = contours[0]
new_s = contour.copy()
appr_s = approximate_polygon(new_s, tolerance=0.8)
fig, ax2 = plt.subplots(ncols=1, figsize=(7, 5))
ax2.plot(contour[:, 0], contour[:, 1])
#these are all what i have tried
#plt.xticks(rotation='vertical')
# for tick in ax2.get_xticklabels():
# tick.set_rotation(45)
#plt.setp(ax2.xaxis.get_majorticklabels(), rotation=70 )
#ax2.tick_params(axis='both', rotation=45)
#fig.autofmt_xdate(bottom=0.5, rotation=90, ha='right')
#plt.hist(ax2, bins=10, orientation='horizontal')
plt.axis('off')
plt.tick_params(axis='both' , left='off', top='off', right='off', bottom='off', labelleft='off', labeltop='off', labelright='off', labelbottom='off')
plt.savefig("test.svg", format="svg")
The output is:
Expected output is:
Thanks in advance.
There are a lot of options here. It is important to note that rotating the ticks will not help here. Instead, use either of the following.
Flip the axes using invert_yaxis(). This would not rotate the image, but flip the axes the image is shown in vertically.
ax2.plot(contour[:, 1], contour[:, 0])
ax2.invert_yaxis()
Flip the image using numpy.flipud. This would not rotate the image, but flip it vertically before processing it further.
fimg = plt.imread(filename)
fimg = np.flipud(fimg)
# ...
ax2.plot(contour[:, 1], contour[:, 0])
Rotate the image using numpy.rot90. In fact you would need to rotate it by 180 degrees (k=2).
fimg = plt.imread(filename)
fimg = np.rot90(fimg,k=2)
# ...
ax2.plot(contour[:, 1], contour[:, 0])
Rotate the output curve
mat = lambda angle: np.array([[ np.cos(angle), np.sin(angle)],
[-np.sin(angle), np.cos(angle)]])
rotcontour = np.dot(contour, mat(np.deg2rad(180)))
ax2.plot(rotcontour[:, 1], rotcontour[:, 0])

Resources