size of a Matplotlib figure - python-3.x

Am trying to make my figure fit the window in terms of its width, and have experimented on the ones have commented out(Line 1, 3, and 4) in the part of the full code below and the attached screenshot is the way it is now. Anyone to help, please.
# fig = plt.figure()
fig = plt.figure(1, figsize = (40, 2), dpi = 80, constrained_layout = True)
#fig = plt.gcf()
#fig.set_size_inches(18.5, 10.5)
ax = fig.add_subplot()
ax.set_title("Electrocadiogram")
ax.set_xlabel("Time(Sec)")
ax.set_ylabel("Voltage(mV)")
ax.grid(b=True, which='major', color='#666666', linestyle='-')
ax.minorticks_on()
ax.grid(b=True, which='minor', color='#666666', linestyle='-', alpha=0.2)
canvas = FigureCanvasTkAgg(fig, master=plotting_frame)
canvas.draw()
canvas.get_tk_widget().place(x = 0, y = 0, width = 600, height = 420)

I have managed to figure it out, the canvas was restricting the size of the figure on which it was embedded, so I played with the canvas width and it has worked.
canvas.get_tk_widget().place(x = 0, y = 0, width = 1170, height = 420)

Related

How to Iterate or Loop the Python Script for the range

I have built a python script to plot an image file, it works fine. When I want to plot multiple image files within a range, I am able to create multiple image files. The issue I am facing - the first image files comes out fine. The second, third and there after all image files are overlapped with the previous image files. What is that I am doing wrong. Appreciate some help, I am new to Python.
df4 = ((df3 + 1).cumprod() - 1)
for row_no in range(2, 10):
df5 = df4.iloc[:row_no,:]
rcParams['figure.figsize']=25,10
plt.scatter(df5.mean(), df5.std())
plt.vlines(df5['SPY'].mean(), ymin = -0.01, ymax = 0.10, colors = 'blue')
plt.hlines(df5['SPY'].std(), xmin = -0.10, xmax = 0.10, colors = 'blue')
plt.tight_layout()
plt.xlabel('Expected returns')
plt.ylabel('Risk')
plt.title("Watchlist Today Performance")
plt.xlim([-0.1, 0.1])
plt.ylim([-0.01, 0.1])
for label, x, y in zip(df5.columns, df5.mean(), df5.std()):
#plt.annotate(label, xy = (x, y), xytext = (20, -20), textcoords = 'offset points', ha = 'right', va = 'bottom', bbox = dict(boxstyle = 'round,pad=0.5', fc = 'red', alpha = 0.5), arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
plt.annotate(label, xy = (x, y), xytext = (20, -20), textcoords = 'offset points', ha = 'right', va = 'bottom', bbox = dict(boxstyle = 'round,pad=0.5', fc = 'red', alpha = 0.5))
plt.savefig('/content/drive/MyDrive/Images/jan26/image.png')
i = 0
while os.path.exists("/content/drive/MyDrive/Images/jan26/image-%s.png" % i):
i += 1
with open('/content/drive/MyDrive/Images/jan26/image.png', 'rb') as f:
data = f.read()
with open('/content/drive/MyDrive/Images/jan26/image-%s.png' % i, 'wb') as f:
f.write(data)
First Image file
Fifth Image File
Final Image File

How to recognize and count circles in a rectangle?

I would like to count how many circles are in static rectangles for more than 3 seconds. The circles represent the center of objects recognized by the camera and static rectangles are areas of interest where I would like to count the total amount of circles that are inside the area of interest for more than 3 seconds. Currently I am able to recognize objects in real-time, find the center of each object and draw static rectangles, but I don't know how to do the rest. Below is my current while loop. Any help would be greatly appreciated.
while True:
frame = vs.read()
frame = imutils.resize(frame, width=720)
box_one = cv2.rectangle(frame, (30,30), (330,330), color, 2)
box_two = cv2.rectangle(frame, (350,30), (630,330), color, 2)
(h, w) = frame.shape[:2]
blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)),
0.007843, (300, 300), 127.5)
net.setInput(blob)
detections = net.forward()
for i in np.arange(0, detections.shape[2]):
confidence = detections[0, 0, i, 2]
if confidence > args["confidence"]:
idx = int(detections[0, 0, i, 1])
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype("int")
label = "{}: {:.2f}%".format(CLASSES[idx],
confidence * 100)
cv2.rectangle(frame, (startX, startY), (endX, endY),
COLORS[idx], 2)
center = ((startX+endX)/2, (startY+endY)/2)
first_value = int(center[0])
second_value = int(center[1])
coordinates = (first_value, second_value)
cv2.circle(frame, coordinates, 5, (255,255,255), -1)
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF
The output looks like this

Removing duplicate legend bar plot matplotlib

I want to edit my legend to make it only shows the labels once
I use for loop to create my bar graph. How can I remove the duplicate legend? It should only show week and month once
This code give me the graph below
fig, ax = plt.subplots(figsize = (10,6))
ax.set(xlim=(0,6))
ax.set(ylim=(0,150))
ax.set_xticklabels(edgeslist)
for i in range(6):
plt.bar(x = i, data = classw.iloc[:,i],
height = len(classw.iloc[:,i]) - classw.iloc[:,i].isna().sum(),
color = (0.91, 0.1, 0.4, 1), label = 'week',
align = 'edge', width = -0.4)
plt.bar(x = i, data = classm.iloc[:,i],
height = len(classm.iloc[:,i]) - classm.iloc[:,i].isna().sum(),
color = 'blue', label = 'month',
align = 'edge', width = 0.4)
plt.legend()
You can create a custom legend containing only the elements you want using the following code
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
r = Patch(facecolor=(0.91,0.1,0.4,1.0), label='week')
b = Patch(facecolor='blue', label='month')
plt.legend(handles=[r,b])
plt.show()
Which would give you a legend like this
Refer to this page for more on making custom legends.
Method 1 You can set the legend inside the loop only if a condition is met:
fig, ax = plt.subplots(figsize = (10,6))
ax.set(xlim=(0,6))
ax.set(ylim=(0,150))
ax.set_xticklabels(edgeslist)
for i in range(6):
plt.bar(x = i, data = classw.iloc[:,i],
height = len(classw.iloc[:,i]) - classw.iloc[:,i].isna().sum(),
color = (0.91, 0.1, 0.4, 1), label = 'week',
align = 'edge', width = -0.4)
plt.bar(x = i, data = classm.iloc[:,i],
height = len(classm.iloc[:,i]) - classm.iloc[:,i].isna().sum(),
color = 'blue', label = 'month',
align = 'edge', width = 0.4)
if i==0:
ax.legend()
Method 2
You can create a list with the label name. You will set as None but one value, then in the plot code, you index the label list this way.
fig, ax = plt.subplots(figsize = (10,6))
ax.set(xlim=(0,6))
ax.set(ylim=(0,150))
ax.set_xticklabels(edgeslist)
label_week = [None]*6
label_week[5] = 'week'
label_month = [None]*6
label_month[5] = 'month'
for i in range(6):
plt.bar(x = i, data = [1, 2, 5, 6, 0, 1],
height = 5,
color = (0.91, 0.1, 0.4, 1), label = label_week[i],
align = 'edge', width = -0.4)
plt.bar(x = i, data = [1, 2, 5, 6, 0, 1],
height = 6,
color = 'blue', label = label_month[i],
align = 'edge', width = 0.4)
plt.legend()
Hope it helps.

Scaling a PDF to show 100% at peak

I'm displaying a histogram of my data, with an overlaid PDF. My plots all look something like this:
and I'm trying to scale the red curve to show 100% at the peak.
My following toy code is identical to what I'm actually using, apart from the lines in between the two %:
%
import pandas as pd
import matplotlib.pyplot as plt
import scipy.stats as stats
import numpy as np
my_randoms = np.random.normal(0.5, 1, 50000)
dictOne = {"delta z":my_randoms}
df = pd.DataFrame(dictOne)
df = df[df['delta z'] > -999]
%
fig, ax = plt.subplots()
h, edges, _ = ax.hist(df['delta z'], alpha = 1, density = False, bins = 100)
param = stats.norm.fit(df['delta z'].dropna()) # Fit a normal distribution to the data
pdf_fitted = stats.norm.pdf(df['delta z'], *param)
x = np.linspace(*df['delta z'].agg([min, max]), 100) # x-values
binwidth = np.diff(edges).mean()
ax.plot(x, stats.norm.pdf(x, *param)*h.sum()*binwidth, color = 'r')
# Decorations
graph_title = 'U-B'
plt.grid(which = 'both')
plt.title(r'$\Delta z$ distribution for %s'%graph_title, fontsize = 25)
plt.xlabel(r'$\Delta z = z_{spec} - z_{photo}$', fontsize = 25)
plt.ylabel('Number', fontsize = 25)
plt.xticks(fontsize = 25)
plt.yticks(fontsize = 25)
xmin, xmax = min(df['delta z']), max(df['delta z'])
plt.xlim(xmin, xmax)
plt.annotate(
r'''$\mu_{\Delta z}$ = %.3f
$\sigma_{\Delta z}$ = %.3f'''%(param[0], param[1]),
fontsize = 25, color = 'r', xy=(0.85, 0.85), xycoords='axes fraction')
How would I define another axes object from 0 to 100 on the right-hand side and map the PDF to that?
Or is there a better way to do it?
This is kind of a follow-up to my previous question.
You can use density=True in plotting the histogram.
You use .twinx():
fig = plt.figure(figsize=(10, 8), dpi=72.0)
n_rows = 2
n_cols = 2
ax1 = fig.add_subplot(n_rows, n_cols, 1)
ax2 = fig.add_subplot(n_rows, n_cols, 2)
ax3 = ax1.twinx()
https://matplotlib.org/gallery/api/two_scales.html

Resizing image and its bounding box

I have an image with bounding box in it, and I want to resize the image.
img = cv2.imread("img.jpg",3)
x_ = img.shape[0]
y_ = img.shape[1]
img = cv2.resize(img,(416,416));
Now I want to calculate the scale factor:
x_scale = ( 416 / x_)
y_scale = ( 416 / y_ )
And draw an image, this is the code for the original bounding box:
( 128, 25, 447, 375 ) = ( xmin,ymin,xmax,ymax)
x = int(np.round(128*x_scale))
y = int(np.round(25*y_scale))
xmax= int(np.round (447*(x_scale)))
ymax= int(np.round(375*y_scale))
However using this I get:
While the original is:
I don't see any flag in this logic, what's wrong?
Whole code:
imageToPredict = cv2.imread("img.jpg",3)
print(imageToPredict.shape)
x_ = imageToPredict.shape[0]
y_ = imageToPredict.shape[1]
x_scale = 416/x_
y_scale = 416/y_
print(x_scale,y_scale)
img = cv2.resize(imageToPredict,(416,416));
img = np.array(img);
x = int(np.round(128*x_scale))
y = int(np.round(25*y_scale))
xmax= int(np.round (447*(x_scale)))
ymax= int(np.round(375*y_scale))
Box.drawBox([[1,0, x,y,xmax,ymax]],img)
and drawbox
def drawBox(boxes, image):
for i in range (0, len(boxes)):
cv2.rectangle(image,(boxes[i][2],boxes[i][3]),(boxes[i][4],boxes[i][5]),(0,0,120),3)
cv2.imshow("img",image)
cv2.waitKey(0)
cv2.destroyAllWindows()
The image and the data for the bounding box are loaded separately. I am drawing the bounding box inside the image. The image does not contain the box itself.
I believe there are two issues:
You should swap x_ and y_ because shape[0] is actually y-dimension and shape[1] is the x-dimension
You should use the same coordinates on the original and scaled image. On your original image the rectangle is (160, 35) - (555, 470) rather than (128,25) - (447,375) that you use in the code.
If I use the following code:
import cv2
import numpy as np
def drawBox(boxes, image):
for i in range(0, len(boxes)):
# changed color and width to make it visible
cv2.rectangle(image, (boxes[i][2], boxes[i][3]), (boxes[i][4], boxes[i][5]), (255, 0, 0), 1)
cv2.imshow("img", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
def cvTest():
# imageToPredict = cv2.imread("img.jpg", 3)
imageToPredict = cv2.imread("49466033\\img.png ", 3)
print(imageToPredict.shape)
# Note: flipped comparing to your original code!
# x_ = imageToPredict.shape[0]
# y_ = imageToPredict.shape[1]
y_ = imageToPredict.shape[0]
x_ = imageToPredict.shape[1]
targetSize = 416
x_scale = targetSize / x_
y_scale = targetSize / y_
print(x_scale, y_scale)
img = cv2.resize(imageToPredict, (targetSize, targetSize));
print(img.shape)
img = np.array(img);
# original frame as named values
(origLeft, origTop, origRight, origBottom) = (160, 35, 555, 470)
x = int(np.round(origLeft * x_scale))
y = int(np.round(origTop * y_scale))
xmax = int(np.round(origRight * x_scale))
ymax = int(np.round(origBottom * y_scale))
# Box.drawBox([[1, 0, x, y, xmax, ymax]], img)
drawBox([[1, 0, x, y, xmax, ymax]], img)
cvTest()
and use your "original" image as "49466033\img.png",
I get the following image
And as you can see my thinner blue line lies exactly inside your original red line and it stays there whatever targetSize you chose (so the scaling actually works correctly).
Another way of doing this is to use CHITRA
image = Chitra(img_path, box, label)
# Chitra can rescale your bounding box automatically based on the new image size.
image.resize_image_with_bbox((224, 224))
print('rescaled bbox:', image.bounding_boxes)
plt.imshow(image.draw_boxes())
https://chitra.readthedocs.io/en/latest/
pip install chitra
I encountered an issue with bounding box coordinates in Angular when using TensorFlow.js and MobileNet-v2 for prediction. The coordinates were based on the resolution of the video frame.
but I was displaying the video on a canvas with a fixed height and width. I resolved the issue by dividing the coordinates by the ratio of the original video resolution to the resolution of the canvas.
const x = prediction.bbox[0] / (this.Owidth / 300);
const y = prediction.bbox[1] / (this.Oheight / 300);
const width = prediction.bbox[2] / (this.Owidth / 300);
const height = prediction.bbox[3] / (this.Oheight / 300);
// Draw the bounding box.
ctx.strokeStyle = '#99ff00';
ctx.lineWidth = 2;
ctx.strokeRect(x, y, width, height);
this.Owidth & this.Oheight are original resolution of video. it is obtained by.
this.video.addEventListener(
'loadedmetadata',
(e: any) => {
this.Owidth = this.video.videoWidth;
this.Oheight = this.video.videoHeight;
console.log(this.Owidth, this.Oheight, ' pixels ');
},
false
);
300 X 300 is my static canvas width and height.
you can use the resize_dataset_pascalvoc
it's easy to use python3 main.py -p <IMAGES_&_XML_PATH> --output <IMAGES_&_XML> --new_x <NEW_X_SIZE> --new_y <NEW_X_SIZE> --save_box_images <FLAG>"
It resize all your dataset and rewrite new annotations files to resized images

Resources