matplotlib plot rotation 90 degree is not happening - python-3.x

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])

Related

Matplotlib - Transformation between figure and image coordinates

I have data I wish to do some manipulations on, which are easier to do if I convert my data to an image (e.g., Hough transform). For that, I convert the data to an image (see attached figure). However, I do not understand how to properly move between the two coordinate systems (or alternatively, convert the axes instance to image rather than the figure instance, and then transformation would be trivial).
I tried playing around with the transformations framework but with no success.
I attach a figure containing two subplots, on the left of the scatter data, and on the right its image representation.
(also, I don't know if how I turned the scatter data to an image can be done neater, if so, I would be happy to hear suggestions for improvement).
I use python 3.6.9; matplotlib version = 3.3.4
Thanks in advance.
import numpy as np
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
# --- Study case: generate random data
X = np.random.rand(1000, 2)
# --- Figure configuration
fig = plt.figure(figsize=(25, 25))
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
# --- First subplot
ax1.scatter(X[:, 0], X[:, 1], s=2, c='k')
ax1.set_title('ax.scatter')
# --- Scatter plot to image
Fig = Figure()
canvas = FigureCanvas(Fig)
Ax = Fig.gca()
Ax.axis('off')
Ax.scatter(X[:, 0], X[:, 1], s=2, c='k')
Ax.get_yaxis().set_ticks([])
Ax.get_xaxis().set_ticks([])
canvas.draw() # draw the canvas, cache the renderer
width, height = Fig.get_size_inches() * Fig.get_dpi()
height = int(height)
width = int(width)
img = np.frombuffer(canvas.tostring_rgb(), dtype='uint8').reshape(height, width, 3)
# --- Display image
ax2.imshow(img)
plt.title('ax.imshow')
plt.show()

Insert a png image in a matplotlib figure

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.

What happens to image type when importing images in python?

libraries such as PIL, Skimage and matplotlib mping all produced the same result
img1 = io.imread("1.3/blurry-moon.tif")
img1 = img1.astype('int32')
img2 = io.imread("1.3/blurry-moon.tif")
imageArray = np.copy(img1)
image1 = np.copy(img1)
image2 = np.copy(img2)
applying a fir filter to these two images produces different results
FIR = [[0, -1, 0], [-1, 5 , -1], [0, -1, 0]]
img1 produces an enhanced image while img2 loses some detail in darker regions
I don't understand why the imported image type by default produces such bad results, any ideas on what is going on?
Thank you.
complete code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import math
from skimage import io
# if current row of image exceeds row of convolutional filter, find the right row of the filter to apply
def convolve(image,filter, i, e):
tot = 0
for x in range(3):
for v in range(3):
tot += image[i+x][e+v]*filter[x][v]
return tot
# let img1 be an image with no features
img1 = io.imread("1.3/blurry-moon.tif")
# change image encoding, keeps the source image as it is. What conversion happened when using the Library?
# ***********************************
img1 = img1.astype('int32')
img2 = io.imread("1.3/blurry-moon.tif")
# These are their own individual new images
imageArray = np.copy(img1)
image1 = np.copy(img1)
image2 = np.copy(img2)
# gets the size of the image array
imageSize = imageArray.shape
FIR = [[0, -1, 0],
[-1, 5 , -1],
[0, -1, 0]]
for i, row in enumerate(imageArray):
for e, value in enumerate(row):
# make sure we done apply the filter outside the image boundary
if i < (imageSize[0]-3) and e < (imageSize[1]-3):
image1[i+1][e+1] = convolve(imageArray, FIR, i ,e)
for i, row in enumerate(imageArray):
for e, value in enumerate(row):
if i < (imageSize[0]-3) and e < (imageSize[1]-3):
image2[i+1][e+1] = convolve(imageArray, FIR, i ,e)
plt.imshow(img1, cmap='gray')
plt.axis('off')
plt.title('original')
plt.show()
plt.imshow(image1, cmap='gray')
plt.axis('off')
plt.title('Laplacian filter')
plt.show()
plt.imshow(image2, cmap='gray')
plt.axis('off')
plt.title('FIR filter')
plt.show() ```

Matplotlib sum of colors as result of plot overlapping [duplicate]

When dealing with overlapping high density scatter or line plots of different colors it can be convenient to implement additive blending schemes, where the RGB colors of each marker add together to produce the final color in the canvas. This is a common operation in 2D and 3D render engines.
However, in Matplotlib I've only found support for alpha/opacity blending. Is there any roundabout way of doing it or am I stuck with rendering to bitmap and then blending them in some paint program?
Edit: Here's some example code and a manual solution.
This will produce two partially overlapping random distributions:
x1 = randn(1000)
y1 = randn(1000)
x2 = randn(1000) * 5
y2 = randn(1000)
scatter(x1,y1,c='b',edgecolors='none')
scatter(x2,y2,c='r',edgecolors='none')
This will produce in matplotlib the following:
As you can see, there are some overlapping blue points that are occluded by red points and we would like to see them. By using alpha/opacity blending in matplotlib, you can do:
scatter(x1,y1,c='b',edgecolors='none',alpha=0.5)
scatter(x2,y2,c='r',edgecolors='none',alpha=0.5)
Which will produce the following:
But what I really want is the following:
I can do it manually by rendering each plot independently to a bitmap:
xlim = plt.xlim()
ylim = plt.ylim()
scatter(x1,y1,c='b',edgecolors='none')
plt.xlim(xlim)
plt.ylim(ylim)
scatter(x2,y2,c='r',edgecolors='none')
plt.xlim(xlim)
plt.ylim(ylim)
plt.savefig(r'scatter_blue.png',transparent=True)
plt.savefig(r'scatter_red.png',transparent=True)
Which gives me the following images:
What you can do then is load them as independent layers in Paint.NET/PhotoShop/gimp and just additive blend them.
Now ideal would be to be able to do this programmatically in Matplotlib, since I'll be processing hundreds of these!
If you only need an image as the result, you can get the canvas buffer as a numpy array, and then do the blending, here is an example:
from matplotlib import pyplot as plt
import numpy as np
fig, ax = plt.subplots()
ax.scatter(x1,y1,c='b',edgecolors='none')
ax.set_xlim(-4, 4)
ax.set_ylim(-4, 4)
ax.patch.set_facecolor("none")
ax.patch.set_edgecolor("none")
fig.canvas.draw()
w, h = fig.canvas.get_width_height()
img = np.frombuffer(fig.canvas.buffer_rgba(), np.uint8).reshape(h, w, -1).copy()
ax.clear()
ax.scatter(x2,y2,c='r',edgecolors='none')
ax.set_xlim(-4, 4)
ax.set_ylim(-4, 4)
ax.patch.set_facecolor("none")
ax.patch.set_edgecolor("none")
fig.canvas.draw()
img2 = np.frombuffer(fig.canvas.buffer_rgba(), np.uint8).reshape(h, w, -1).copy()
img[img[:, :, -1] == 0] = 0
img2[img2[:, :, -1] == 0] = 0
fig.clf()
plt.imshow(np.maximum(img, img2))
plt.subplots_adjust(0, 0, 1, 1)
plt.axis("off")
plt.show()
the result:
This feature is now supported by my matplotlib backend https://github.com/anntzer/mplcairo (master only):
import matplotlib; matplotlib.use("module://mplcairo.qt")
from matplotlib import pyplot as plt
from mplcairo import operator_t
import numpy as np
x1 = np.random.randn(1000)
y1 = np.random.randn(1000)
x2 = np.random.randn(1000) * 5
y2 = np.random.randn(1000)
fig, ax = plt.subplots()
# The figure and axes background must be made transparent.
fig.patch.set(alpha=0)
ax.patch.set(alpha=0)
pc1 = ax.scatter(x1, y1, c='b', edgecolors='none')
pc2 = ax.scatter(x2, y2, c='r', edgecolors='none')
operator_t.ADD.patch_artist(pc2) # Use additive blending.
plt.show()

How to set zero margins of the figure - matplotlib

How to crop the figure to have no white space where nothing is plotted? Why plt.tight_layout(pad=0) does not work? The picture draw 3d coordinate system.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
fig = plt.figure(figsize=[5,3])
ax = fig.gca(projection = '3d')
ax.set_ylim(-2,3)
ax.set_zlim(-1,2)
vleng = 5
aleng = vleng/3.
p = np.array([vleng+200, 0, 0])
q = np.array([0, vleng-2, 0])
r = np.array([0, 0, vleng-3])
ax.plot(*np.vstack([[0,0,0], p]).T, color='black')
ax.plot(*np.vstack([[0,0,0], q]).T, color='black')
ax.plot(*np.vstack([[0,0,0], r]).T, color='black')
ax.azim = 20 # y rotation (default=270)
ax.elev = 20 # x rotation (default=0)
ax.dist = 10 # zoom (define perspective)
ax.set_axis_off( ) # hide all grid
plt.tight_layout(pad=0)
plt.show()
The output:
figure
So I tried multiple things. The only thing that would reduce these white spaces would require the three lines to be drawn along the meeting lines of the planes. So I did some measurements and here's the code where the white spaces have significantly reduced. You're free to reduce it further by tweaking it some more. Also comment out ax.set_axis_off( ) to see what's happening:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
fig = plt.figure(figsize=[5,3])
ax = fig.gca(projection = '3d')
ax.set_ylim(0,3)
ax.set_zlim(0,2)
# ax.set_xlim(0,2)
vleng = 5
aleng = vleng/3.
p = np.array([vleng+200, 0, 0])
q = np.array([0, vleng-2, 0])
r = np.array([0, 0, vleng-3])
ax.plot(*np.vstack([[0,0,0], p]).T, color='black')
ax.plot(*np.vstack([[0,0,0], q]).T, color='black')
ax.plot(*np.vstack([[0,0,0], r]).T, color='black')
ax.azim = 20 # y rotation (default=270)
ax.elev = 20 # x rotation (default=0)
ax.dist = 10 # zoom (define perspective)
ax.set_axis_off( ) # hide all grid
plt.tight_layout(pad=0)
plt.show()

Resources