How to fix crontab issue or 'os.execute()' issue with python script? - python-3.x

I run domoticz on a PI3b with Raspbian, for better effiency the PI3b has now a 7" screen to show domotics behaviour + weather-station information + internet forecast...
To show all of this I've coded a C++/WXWidget app with graphics for temp/pressure...
Temp/pressures graphs are with Python3/matplotlib plotted, saved as 3 png files. The Python script read datas in files and plot/save the graphs.
It works good from terminal.... but no way to work with crontab, or with an "os.execute()" from events lua-scripts of domoticz...
I've pushed Up all permissions/access for scripts and png files (read/write)
One python script read data from bme280 sensor, crontab 2 minutes, no problem, it works from terminal, crontab, lua events...
Second script read datas, plot graphs and send http json command in order to update a device in domoticz. This works fine from terminal, but not from domoticz (lua os.execute()) or from crontab.
call in crontab:
sudo /usr/bin/python3 /home/pi/Desktop/graph.py
call from domoticz lua script:
os.execute('sudo /usr/bin/python3 /home/pi/Desktop/graph.py')
from terminal it works fine with python, /usr/bin/python, or /usr/bin/python3 (--> matplotlib)
python --version = 3.7.0
It looks like a problem beetween many python versions, the good one is not called from crontab and lua-scripts.... How to fix-it ?
default python version to 2.7.0, 3.0, 3.6, 3.7 tested to check problem with env/bin/path...
only problem found with urllib.urlopen changed with "urlopen from urllib.request"
#!/usr/bin/python3
import matplotlib.lines as lines
import matplotlib.pyplot as plt
#import urllib ---> urllib.urlopen() works with /usr/bin/python
from urllib.request import urlopen #---> to work with /usr/bin/python3
fig = plt.figure()
ax = fig.add_subplot(111)
ax.grid(which='major', axis='x', color=(0.6, 0.6, 0.6), linewidth=1)
ax.patch.set_color('black')
fig.set_facecolor((0.0, 0.0, 0.0))
fig.set_size_inches(26.25, 7.42)
fig.patch.set_facecolor('black')
ax.spines["top"].set_visible(False)
ax.spines["bottom"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.spines["left"].set_visible(False)
plt.ylim(0, 63)
plt.xlim(0, 210)
plt.style.use('dark_background')
list = []
d1 = 0
d2 = 0
d3 = 0
def readf( str ): #open/read file, fill the list
list[:] = []
with open(str) as infile: #parsing to float
numbers = infile.read()
numbers = numbers.replace(" ","").replace("\r","").replace("\n","")
for num in numbers.split(";"):
n = float(num)
list.append(n)
infile.close()
if str == "/home/pi/Dev/PI-Weather_Station/pressval.txt":
t = len(list) - 1
t1 = t - 6
t2 = t - 12
t3 = t - 24
d1 = list[t] - list[t1]
d2 = list[t] - list[t2]
d3 = list[t] - list[t3]
if d1 < 0 and d2 < 0:
httpresponse = urlopen("http://192.168.x.xxx:xxxx/json.htm?type=command&param=updateuservariable&vname=tendance&vtype=2&vvalue=baisse")
elif d1 < 0 and d2 > 0:
httpresponse = urlopen("http://192.168.x.xxx:xxxx/json.htm?type=command&param=updateuservariable&vname=tendance&vtype=2&vvalue=stable")
elif d1 > 0 and d2 > 0:
httpresponse = urlopen("http://192.168.x.xxx:xxxx/json.htm?type=command&param=updateuservariable&vname=tendance&vtype=2&vvalue=hausse")
elif d1 > 0 and d2 < 0:
httpresponse = urlopen("http://192.168.x.xxx:xxxx/json.htm?type=command&param=updateuservariable&vname=tendance&vtype=2&vvalue=stable")
return;
def chart( stg ): #plot/save the charts
o = len(list)
omin = 1400
omax = -50
i = 0
n = 0
line = lines.Line2D([i, i+1], [list[i], list[i+1]], lw=1, color='blue', axes=ax)
if o > 210:
i = o - 210
n = i
while i < o-1:
if stg == "/home/pi/Dev/PI-Weather_Station/tex.png":
line = lines.Line2D([i, i+1], [list[i], list[i+1]], lw=3, color=(0.0, 0.7, 1.0), axes=ax)
ax.add_line(line)
elif stg == "/home/pi/Dev/PI-Weather_Station/tin.png":
line = lines.Line2D([i, i+1], [list[i], list[i+1]], lw=3, color='yellow', axes=ax)
ax.add_line(line)
elif stg == "/home/pi/Dev/PI-Weather_Station/press.png":
line = lines.Line2D([i, i+1], [list[i], list[i+1]], lw=3, color='red', axes=ax)
ax.add_line(line)
if list[i] < omin:
omin = list[i]
if list[i] > omax:
omax = list[i]
i += 1
ax.axis([n, o, omin - 0.1, omax + 0.1])
ax.axhline((omax+omin)/2, 0, 1)
ax.axvline(n+30, 0, 1)
ax.axvline(n+60, 0, 1)
ax.axvline(n+90, 0, 1)
ax.axvline(n+120, 0, 1)
ax.axvline(n+150, 0, 1)
ax.axvline(n+180, 0, 1)
fig.savefig(stg, dpi = 10, bbox_inches = 'tight')
return;
readf("/home/pi/Dev/PI-Weather_Station/texval.txt")
chart("/home/pi/Dev/PI-Weather_Station/tex.png")
readf("/home/pi/Dev/PI-Weather_Station/tinval.txt")
chart("/home/pi/Dev/PI-Weather_Station/tin.png")
readf("/home/pi/Dev/PI-Weather_Station/pressval.txt")
chart("/home/pi/Dev/PI-Weather_Station/press.png")
plt.close()

Oky,
source: Generating a PNG with matplotlib when DISPLAY is undefined
that was a pb with matplotlib, the script runs fine in terminal but for others it needs more codes:
#!/usr/bin/python
import matplotlib
matplotlib.use('Agg')

Related

Only integer scalar arrays can be converted to a scalar index not running under Spyder

I have the following code, which runs well under Visual Studio Code with python 3.9.10, opencv 4.5.5 and numpy 1.22.1.
I would like to migrate this code into the Spyder IDE (Version 5, another notebook), python 3.8, opencv 4.5.1 and numpy 1.22.2.
In spyder, I get the error message TypeError: only integer scalar arrays can be converted a scalar index in line: output_layers = [layer_names[i-1]...] (marked line down in the code section)
I have already checked other answers on this site such as
TypeError when indexing a list with a NumPy array: only integer scalar arrays can be converted to a scalar index
which suggests list comprehension, but in my understanding I am already implemented this.
What is the reason for running currectly in on environment but not in the other?
import cv2
import numpy as np
def get_output_layers(net):
layer_names = net.getLayerNames()
output_layers = [layer_names[i - 1] for i in net.getUnconnectedOutLayers()]
return output_layers
def draw_prediction(img, class_id, confidence, x, y, x_plus_w, y_plus_h):
label = str(classes[class_id])
color = COLORS[class_id]
cv2.rectangle(img, (x,y), (x_plus_w,y_plus_h), color, 2)
cv2.putText(img, label, (x-10,y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
image = cv2.imread('horses.jpg')
Width = image.shape[1]
Height = image.shape[0]
scale = 0.00392
classes = None
with open(r'yolov3.txt', 'r') as f:
classes = [line.strip() for line in f.readlines()]
COLORS = np.random.uniform(0, 255, size=(len(classes), 3))
net = cv2.dnn.readNet('yolov3.weights','yolov3.cfg')
blob = cv2.dnn.blobFromImage(image, scale, (416,416), (0,0,0), True, crop=False)
net.setInput(blob)
outs = net.forward(get_output_layers(net))
class_ids = []
confidences = []
boxes = []
conf_threshold = 0.5
nms_threshold = 0.4
for out in outs:
for detection in out:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.5:
center_x = int(detection[0] * Width)
center_y = int(detection[1] * Height)
w = int(detection[2] * Width)
h = int(detection[3] * Height)
x = center_x - w / 2
y = center_y - h / 2
class_ids.append(class_id)
confidences.append(float(confidence))
boxes.append([x, y, w, h])
indices = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)
for i in indices:
box = boxes[i]
x = box[0]
y = box[1]
w = box[2]
h = box[3]
draw_prediction(image, class_ids[i], confidences[i], round(x), round(y),
round(x+w), round(y+h))
cv2.imshow("object detection", image)
cv2.waitKey()
cv2.imwrite("object-detection.jpg", image)
cv2.destroyAllWindows()
there were subtle, recent api changes wrt handling std::vector in python
(4.5.1 still expects a 2d array, but it's 1d in 4.5.5)
to avoid the whole trouble, please simply use:
output_layers = net.getUnconnectedOutLayersNames()
(like it is done in the sample)

How could I set the staring and ending points randomly in a grid that generates random obstacles?

I built a grid that generates random obstacles for pathfinding algorithm, but with fixed starting and ending points as shown in my snippet below:
import random
import numpy as np
#grid format
# 0 = navigable space
# 1 = occupied space
x = [[random.uniform(0,1) for i in range(50)]for j in range(50)]
grid = np.array([[0 for i in range(len(x[0]))]for j in range(len(x))])
for i in range(len(x)):
for j in range(len(x[0])):
if x[i][j] <= 0.7:
grid[i][j] = 0
else:
grid[i][j] = 1
init = [5,5] #Start location
goal = [45,45] #Our goal
# clear starting and end point of potential obstacles
def clear_grid(grid, x, y):
if x != 0 and y != 0:
grid[x-1:x+2,y-1:y+2]=0
elif x == 0 and y != 0:
grid[x:x+2,y-1:y+2]=0
elif x != 0 and y == 0:
grid[x-1:x+2,y:y+2]=0
elif x ==0 and y == 0:
grid[x:x+2,y:y+2]=0
clear_grid(grid, init[0], init[1])
clear_grid(grid, goal[0], goal[1])
I need to generate also the starting and ending points randomly every time I run the code instead of making them fixed. How could I make it? Any assistance, please?.
Replace,
init = [5,5] #Start location
goal = [45,45] #Our goal
with,
init = np.random.randint(0, high = 49, size = 2)
goal = np.random.randint(0, high = 49, size = 2)
Assuming your grid goes from 0-49 on each axis. Personally I would add grid size variables, i_length & j_length
EDIT #1
i_length = 50
j_length = 50
x = [[random.uniform(0,1) for i in range(i_length)]for j in range(j_length)]
grid = np.array([[0 for i in range(i_length)]for j in range(j_length)])

Subplot size using gridspec

Python 3.6. I don't understand why my plots are so smashed like this inside each part of the grid. Width is ok, they are stuck by two as i wanted, and space between each block is also ok. But i didn't find what i could change to change the size of the y axis.
Here is my code:
def graphiqueLigneDate(listeDates, listeOrdonnees, nomOrdonnees, axe, labelLigne):
# -- Variables utiles
listeTicks = []
step = 5
for i in range(int(len(listeDates)/step)+1):
listeTicks.append(listeDates[step*i][:-5])
# -- Configurer graphique ---
axe.plot([i for i in range(1,len(listeDates)+1)], listeOrdonnees, label = labelLigne)
axe.set_ylabel(nomOrdonnees)
axe.set_xlabel('Date')
axe.set_xticks([i for i in range(1,len(listeDates)+1,5)])
axe.set_xticklabels(listeTicks)
axe.legend()
fig = plt.figure(figsize=(6,5))
fig.suptitle('Volume vs Prix', size=18)
plt.subplots_adjust(top=0.9, wspace=0.1, hspace=0.5)
nbreDeMots = len(listeMots)
heightRatiosListe = [1] * nbreDeMots
grille = gridspec.GridSpec(nbreDeMots, 2, height_ratios = heightRatiosListe)
i = 0
for mot in listeMots:
gs = gridspec.GridSpecFromSubplotSpec(2, 1, subplot_spec = grille[i], hspace = 0)
j = 0
for cellule in gs:
ax1 = fig.add_subplot(cellule)
if j % 2 == 0:
ax1.tick_params(axis='x',which='both', direction='in' , bottom='on',top='off', labelbottom='off')
ax1.set_ylabel('Volume')
ft.graphiqueLigneDate(listeBonnesDates, dicoVolume[mot], 'Volume Tweet', ax1, mot)
else:
ax1.set_xlabel('Date')
ax1.set_ylabel('Prix')
ft.graphiqueLigneDate(listeBonnesDates, dicoSpot[mot], 'Volume Tweet', ax1, mot)
j += 1
i +=1
fig.tight_layout()
fig.show()
Thanks !

Python :IndexError: list index out of range How to solve this error?

I am using bilateral filter for my work. I am getting following error:
src = cv2.imread(str(sys.argv[1]), 0) IndexError: list index out of
range
code:Bilateral bilter
import numpy as np
import cv2
import sys
import math
def distance(x, y, i, j):
return np.sqrt((x-i)**2 + (y-j)**2)
def gaussian(x, sigma):
return (1.0 / (2 * math.pi * (sigma ** 2))) * math.exp(- (x ** 2) / (2 * sigma ** 2))
def apply_bilateral_filter(source, filtered_image, x, y, diameter, sigma_i, sigma_s):
hl = diameter/2
i_filtered = 0
Wp = 0
i = 0
while i < diameter:
j = 0
while j < diameter:
neighbour_x = x - (hl - i)
neighbour_y = y - (hl - j)
if neighbour_x >= len(source):
neighbour_x -= len(source)
if neighbour_y >= len(source[0]):
neighbour_y -= len(source[0])
gi = gaussian(source[neighbour_x][neighbour_y] - source[x][y], sigma_i)
gs = gaussian(distance(neighbour_x, neighbour_y, x, y), sigma_s)
w = gi * gs
i_filtered += source[neighbour_x][neighbour_y] * w
Wp += w
j += 1
i += 1
i_filtered = i_filtered / Wp
filtered_image[x][y] = int(round(i_filtered))
def bilateral_filter_own(source, filter_diameter, sigma_i, sigma_s):
filtered_image = np.zeros(source.shape)
i = 0
while i < len(source):
j = 0
while j < len(source[0]):
apply_bilateral_filter(source, filtered_image, i, j, filter_diameter, sigma_i, sigma_s)
j += 1
i += 1
return filtered_image
if __name__ == "__main__":
src = cv2.imread(str(sys.argv[1]), 0)
filtered_image_OpenCV = cv2.bilateralFilter(src, 5, 12.0, 16.0)
cv2.imwrite("original_image_grayscale.png", src)
cv2.imwrite("filtered_image_OpenCV.png", filtered_image_OpenCV)
filtered_image_own = bilateral_filter_own(src, 5, 12.0, 16.0)
cv2.imwrite("filtered_image_own.png", filtered_image_own)
sys.argv[1] is indexing into the first element of the command line arguments list. If you're not providing an argument when running the program, e.g. python yourfilename.py testing, an IndexError will be thrown. Note that the 0th element of the list is the filename of the script.
Debug with print(sys.argv) immediately below if __name__ == "__main__": to view the contents of your sys.argv list.
Also, note that arguments are passed as strings, so the str() cast is superfluous.
It seems that something is not as you expect, this IndexError: list index out of range indicates that your list src = cv2.imread(str(sys.argv[1]), 0) doesn't have 2 elements in it, and only 1 exists.
Try debug your code:
if __name__ == "__main__":
print('This is the type of my sys.argv', type(sys.argv))
print('This is str(sys.argv) as full list --> ', str(sys.argv)) # my guess is that it will give only 1 item in the list, maybe you first need to do some splitting or etc, but the end result will be seen from you'r debugging :)
print('This is str(sys.argv[0]) first itme from list --> ', str(sys.argv[0]))
# add break point here
src = cv2.imread(str(sys.argv[1]), 0)
filtered_image_OpenCV = cv2.bilateralFilter(src, 5, 12.0, 16.0)
cv2.imwrite("original_image_grayscale.png", src)
cv2.imwrite("filtered_image_OpenCV.png", filtered_image_OpenCV)
filtered_image_own = bilateral_filter_own(src, 5, 12.0, 16.0)
cv2.imwrite("filtered_image_own.png", filtered_image_own)

Installing and running vpython with Python 3.5 on Windows 10

I'm trying to install vpython with python3.5 on windows 10.
I used the following commands in the cmd:
pip install vpython
pip install update --ipython
If I then try to run some vpython code (copied from internet to simulate projectile motion):
from vpython import *
from math import sin, cos
initialHeight = 4.6
initialVelocity = 24
Angle = 65
#Set up the display window
scene1 = display(title = "Projectile Motion for the uninitiated",
x=0,y=0, width=800, height=600,
range=10, background=colour.white,
center = (10,initialHeight,0))
#Create objects
table = box(pos=(-1,initialHeight - 1,0), size=(5,1,4))
ball1 = sphere(pos=(0,initialHeight,0),radius=1,
color=color.green, make_trail = true)
ball2 = sphere(pos=(0,initialHeight,0),radius=1,
color=color.red, make_trail = true)
floor = box(pos=(0,0,0), size =(100,0.25,10))
t=0
dt=0.01
g=-32 #ft/s**2
Fgrav = vector(0,g*dt,0)
#velocity vector for ball1
ball1v = vector(initialVelocity*cos(Angle*pi/180),
initialVelocity*sin(Angle*pi/180),0)
#This loop puts it into motion
while True:
rate(30) #speeds it up
ball1v = ballv + Fgrav
ball1.pos += ball1.v*dt
ball2.pos = (initialVelocity*cos(Angle*pi/180)*t,
initialHeight + initialVelocity*t*sin(Angle*pi/180) - 16*t**2)
if ball1.y < 0: #when ball hits floor
print("ball1.pos = ", ball1.pos, "t = ", t)
print("ball2.pos = ", ball2.pos, "t = ", t)
break
When I run this I then get the following errors:
Traceback (most recent call last):
File "C:/Users/yours_truly/Google Drive/Python/projectile motion.py", line 1, in <module>
from vpython import *
File "C:\Users\yours_truly\AppData\Local\Programs\Python\Python35-32\lib\site-packages\vpython\__init__.py", line 10, in <module>
from .vpython import *
File "C:\Users\yours_truly\AppData\Local\Programs\Python\Python35-32\lib\site-packages\vpython\vpython.py", line 442, in <module>
get_ipython().kernel.comm_manager.register_target('glow', GlowWidget)
AttributeError: 'NoneType' object has no attribute 'kernel'
I cannot understand the problem here, nor can I make sense of the discussions of this that I have found online. Can anyone tell me what the score is here? Is vpython incompatible with python 3.5 (which I've read in some places) or is there a workaround (which I've also read in other places)?
Thank you.
I cannot remember when exactly support for Python 3.5 became available; it is certainly supported now. But the problem may have been associated with the fact that the program has a number of errors. Here is a version that works, including with Python 3.5 on Windows 10. The corrections were to change true -> True, bal
from vpython import *
from math import sin, cos
initialHeight = 4.6
initialVelocity = 24
Angle = 65
#Set up the display window
scene1 = display(title = "Projectile Motion for the uninitiated",
x=0,y=0, width=800, height=600,
range=10, background=color.white,
center = (10,initialHeight,0))
#Create objects
table = box(pos=vec(-1,initialHeight - 1,0), size=vec(5,1,4))
ball1 = sphere(pos=vec(0,initialHeight,0),radius=1,
color=color.green, make_trail = True)
ball2 = sphere(pos=vec(0,initialHeight,0),radius=1,
color=color.red, make_trail = True)
floor = box(pos=vec(0,0,0), size =vec(100,0.25,10))
t=0
dt=0.01
g=-32 #ft/s**2
Fgrav = vector(0,g*dt,0)
#velocity vector for ball1
ball1v = vector(initialVelocity*cos(Angle*pi/180),
initialVelocity*sin(Angle*pi/180),0)
#This loop puts it into motion
while True:
rate(30) #speeds it up
ball1v = ball1v + Fgrav
ball1.pos += ball1v*dt
ball2.pos = vec(initialVelocity*cos(Angle*pi/180)*t,
initialHeight + initialVelocity*t*sin(Angle*pi/180) - 16*t**2,0)
if ball1.pos.y < 0: #when ball hits floor
print("ball1.pos = ", ball1.pos, "t = ", t)
print("ball2.pos = ", ball2.pos, "t = ", t)
break

Resources