Cartopy wmts KeyError issue : TileMatrixLimits - python-3.x

Since a while, I am using the wmts function of cartopy but since last week this function does not works returning this error:
KeyError: 'TileMatrixLimits with tileMatrix "1" already exists'
The run code is coming from the cartopy web doc.
below the code:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
def main():
url = 'https://map1c.vis.earthdata.nasa.gov/wmts-geo/wmts.cgi'
layer = 'VIIRS_CityLights_2012'
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
ax.add_wmts(url, layer)
ax.set_extent([-15, 25, 35, 60], crs=ccrs.PlateCarree())
ax.set_title('Suomi NPP Earth at night April/October 2012')
plt.show()
if __name__ == '__main__':
main()
I do not understand what is wrong.
Thank for help.

You can solve it commenting the lines 654 to 657 of (your Python dir)/Lib/site-packages/owslib/wmts.py which check the existence of the indexes in the static function from_elements of the TileMatrixSetLink class
Like this:
for limits_element in link_element.findall(path):
tml = TileMatrixLimits(limits_element)
if tml.tilematrix:
#if tml.tilematrix in tilematrixlimits:
# msg = ('TileMatrixLimits with tileMatrix "%s" '
# 'already exists' % tml.tilematrix)
# raise KeyError(msg)
tilematrixlimits[tml.tilematrix] = tml
links.append(TileMatrixSetLink(uri, tilematrixlimits))
For portability effects you can replace that function in your code before you use it
Like this:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
### START REPLACEMENT ###
from owslib.wmts import TileMatrixSetLink, TileMatrixLimits, _TILE_MATRIX_SET_TAG, _TILE_MATRIX_SET_LIMITS_TAG, _TILE_MATRIX_LIMITS_TAG
def custom_from_elements(link_elements):
links = []
for link_element in link_elements:
matrix_set_elements = link_element.findall(_TILE_MATRIX_SET_TAG)
if len(matrix_set_elements) == 0:
raise ValueError('Missing TileMatrixSet in %s' % link_element)
elif len(matrix_set_elements) > 1:
set_limits_elements = link_element.findall(
_TILE_MATRIX_SET_LIMITS_TAG)
if set_limits_elements:
raise ValueError('Multiple instances of TileMatrixSet'
' plus TileMatrixSetLimits in %s' %
link_element)
for matrix_set_element in matrix_set_elements:
uri = matrix_set_element.text.strip()
links.append(TileMatrixSetLink(uri))
else:
uri = matrix_set_elements[0].text.strip()
tilematrixlimits = {}
path = '%s/%s' % (_TILE_MATRIX_SET_LIMITS_TAG,
_TILE_MATRIX_LIMITS_TAG)
for limits_element in link_element.findall(path):
tml = TileMatrixLimits(limits_element)
if tml.tilematrix:
tilematrixlimits[tml.tilematrix] = tml
links.append(TileMatrixSetLink(uri, tilematrixlimits))
return links
TileMatrixSetLink.from_elements = custom_from_elements
### END REPLACEMENT ###
def main():
url = 'https://map1c.vis.earthdata.nasa.gov/wmts-geo/wmts.cgi'
layer = 'VIIRS_CityLights_2012'
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
ax.add_wmts(url, layer)
ax.set_extent([-15, 25, 35, 60], crs=ccrs.PlateCarree())
ax.set_title('Suomi NPP Earth at night April/October 2012')
plt.show()
if __name__ == '__main__':
main()

Related

Is there a way in an external .py to catch data populated by a kivy button (row by row) and then get len() of that dataset as well?

How do I catch tuples generated by clicks on the kivy button in file 1 and the corresponding number of rows, i.e. len(), of that number of rows in file 2? Any support out there is much, much appreciated....
View explanation below...
I created a kivy app delivering a row of tupled values every time I click my button. That works fine. Now I want to pick up, e.g. a dataset of five clicks on button, i.e. 5 rows of tuples. Below is what I did in file 1:
file 1.py:
kv = '''
<Launch>:
BoxLayout:
Button:
size:(80,80)
size_hint:(None,None)
text:"..."
on_press: root.build()
'''
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
warnings.simplefilter(action='ignore', category=DeprecationWarning)
warnings.simplefilter(action='ignore', category=RuntimeWarning)
warnings.simplefilter(action='ignore', category=UserWarning)
import pandas as pd
import numpy as np
from kivy.app import App
from kivy.uix.button import Button
def test(t):
size = t
a = pd.DataFrame(columns=['col1', 'col2', 'col3'])
a['col1'] = pd.DataFrame(np.random.randint(1, 50, size))
a['col2'] = pd.DataFrame(np.random.randint(1, 50, size))
a['col3'] = pd.DataFrame(np.random.rand(size))
t = a
return t
def vars_n(self):
a = test(t=1)
# Define objects for dataframe and col inputs
self.a_num = pd.DataFrame(test(1))
self.a_limit = a[(a.col3) < 1 & (a.col3 > 0.8)]
self.a_col1 = a['col1']
self.a_col2 = a['col2']
self.a_col3 = a['col3']
cols = self.a_col1, self.a_col2, self.a_col3
lst = []
self.a_col1, self.a_col2, self.a_col3 = 'src', 'dest', 'col3'
for a in range(1):
lst.append([self.a_col1, self.a_col2, self.a_col3])
self.a_col1, self.a_col2, self.a_col3 = \
np.random.randint(1, 40, size=1), np.random.randint(1, 40, size=1), np.random.rand(1)
df = pd.DataFrame(lst, columns=cols)
tuple1 = self.a_col1
tuple2 = self.a_col2
tuple3 = self.a_col3
q = tuple(zip(tuple1, tuple2, tuple3))
return q
class MyDf(App, object):
def __init__(self):
super().__init__()
def test_def(self):
msg = test(1)
print(msg)
def test_vars_n(self):
msg = vars_n(test(t=1))
print(msg)
def length(self):
result = len(vars_n(test(t=1)))
print(result)
# Define output for activation of kivy button
def press(self, instance):
print(vars_n(test(t=1)))
# Define kivy button configuration
def build(self):
butt=Button(text="...")
butt.bind(on_press=self.press)
return butt
MyDf().run()
Result after e.g. five clicks, could generate below dataset:
((6, 22, 0.8525529856428397),)
((12, 7, 0.3912468711230911),)
((30, 14, 0.979806646854341),)
((21, 27, 0.618131650972481),)
((8, 20, 0.9164440407619223),)
So, in file 2, I'd like to pull above five lines in the dataset above and, at the same time, get the len of that dataset, i.e. 5. Tried this, but it does not seem to catch the output of file 1:
file 2.py:
import pandas as pd
import numpy as np
my_instance = MyDf()
interactions = my_instance.test_vars_n()
interactions = np.array(interactions)
print(len(interactions)) # testing result
Got this error:
Traceback (most recent call last):
File "G:\...\...\...\....\file2.py", line 38, in <module>
print(len(interactions))
TypeError: len() of unsized object
EDITING with example I was inspired by in above attempts:
File 1
import pandas as pd
import numpy as np
def test(t):
size = t
a = pd.DataFrame(columns=['col1', 'col2', 'col3'])
a['col1'] = pd.DataFrame(np.random.randint(1, 50, size))
a['col2'] = pd.DataFrame(np.random.randint(1, 50, size))
a['col3'] = pd.DataFrame(np.random.rand(size))
t = a
return t
class ClassTest(object):
def test_def(self):
msg = test(1)
print(msg)
File 2:
from Call_an_outside_function_from_class_file_1 import ClassTest
my_new_instance = ClassTest()
ClassTest().test_def()
Got this result, and without using the App.get_running_app() replacement:
col1 col2 col3
0 48 3 0.514489
Process finished with exit code 0

I'm trying to get this code to draw lines on the output window but I can't seem to get it to

import numpy
import cv2
import time as t
from PIL import ImageGrab
import numpy as np
print("\n\n----------------\n\nPress 'Q' to Quit\n\n----------------\n\n")
def draw_line(img, lines):
try:
for line in lines:
coords = line[0]
cv2.line(img, (coords[0]),(coords[1]),(coords[2]),(coords[3]), [255,0,255], 5)
except:
pass
def process_img(o_img):
pro_img = cv2.cvtColor(o_img, cv2.COLOR_BGR2GRAY)
pro_img = cv2.Canny(pro_img, threshold1= 100, threshold2=300)
lines = cv2.HoughLinesP(pro_img, 1, np.pi/180, 180, 3, 15)
draw_line(pro_img, lines)
return pro_img
while(True):
screen = np.array(ImageGrab.grab(bbox = (80, 130, 990, 630)))
new_scr = process_img(screen)
cv2.imshow("window", new_scr)
#cv2.imshow('window 2',cv2.cvtColor(screen, cv2.COLOR_BGR2RGB))
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
I tried the draw function and it didn't work not sure if I need to do something else to the image or if the function isn't placed correctly

Python cv2 ORB detectandcompute returning "invalid number of channels in input image"

I'm trying to extract and match features from two different images but for some reason the "detectAndCompute" method doesn¡t work on my orb object:
orb = cv2.ORB_create()
kp, corners = orb.detectAndCompute(image,None
I am passing a single grayscale image (the return of the function np.float32(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY))). For some reason, the program returns the following error:
Traceback (most recent call last):
File "C:\Users\levxr\Desktop\Visual-positioning-bot-main\alloverlay.py", line 37, in
cv2.imshow("camera "+str(i), corn1.updateanddisplay())
File "C:\Users\levxr\Desktop\Visual-positioning-bot-main\features.py", line 33, in updateanddisplay
dst = self.update(image=self.image)
File "C:\Users\levxr\Desktop\Visual-positioning-bot-main\features.py", line 23, in update
kp, corners = orb.detectAndCompute(image,None)
cv2.error: OpenCV(4.4.0) c:\users\appveyor\appdata\local\temp\1\pip-req-build-95hbg2jt\opencv\modules\imgproc\src\color.simd_helpers.hpp:92: error: (-2:Unspecified error) in function '__cdecl cv::impl::anonymous-namespace'::CvtHelper<struct cv::impl::anonymous namespace'::Set<3,4,-1>,struct cv::impl::A0x2980c61a::Set<1,-1,-1>,struct cv::impl::A0x2980c61a::Set<0,2,5>,2>::CvtHelper(const class cv::_InputArray &,const class cv::_OutputArray &,int)'
Invalid number of channels in input image:
'VScn::contains(scn)'
where
'scn' is 1
The program is split in 3 files, alloverlay.py(the main file):
import sys
import cv2
import numpy as np
import features as corn
import camera as cali
cv2.ocl.setUseOpenCL(False)
#videoname = input("enter input")
videoname = "camera10001-0200.mkv"
try:
videoname = int(videoname)
cap = cv2.VideoCapture(videoname)
except:
cap = cv2.VideoCapture(videoname)
videoname2 = "camera 20000-0200.mkv"
try:
videoname = int(videoname)
cap2 = cv2.VideoCapture(videoname)
except:
cap2 = cv2.VideoCapture(videoname)
if cap.isOpened()and cap2.isOpened():
ret1, image1 = cap.read()
ret2, image2 = cap2.read()
ret = [ret1, ret2]
image = [np.float32(cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)), np.float32(cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY))]
cali1 = cali.Calibrator()
corn1 = corn.Corner_detector(image)
while cap.isOpened() and cap2.isOpened():
ret[0], image[0] = cap.read()
ret[1], image[1] = cap2.read()
if ret:
backupimg = image
for i, img in enumerate(image):
if cali1.calibrated:
backupimg[i] = corn1.image = cali1.undistort(np.float32(cv2.cvtColor(image[i], cv2.COLOR_BGR2GRAY)), cali1.mtx, cali1.dist)
else:
backupimg[i] = corn1.image = np.float32(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY))
cv2.imshow("camera "+str(i), corn1.updateanddisplay())
image = backupimg
print(ret, image)
#cv2.imshow("test", image)
key = cv2.waitKey(1)
if key == ord("c"):
cali1.calibrate(cali1.image)
if cv2.waitKey(25) & 0xFF == ord("q"):
break
else:
print("capture not reading")
break
cap.release()
, camera.py(module to calibrate and undistort the camera and triangulate the relative position of the point (a different part of this project, irrelevant to this issue)):
import sys
import cv2
#import glob
import numpy as np
cv2.ocl.setUseOpenCL(False)
class Missing_calibration_data_error(Exception):
def __init__():
pass
class Calibrator():
def __init__(self, image=None, mtx=None, dist=None, camera_data={"pixelsize":None, "matrixsize":None, "baseline":None, "lens_distance":None}, criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001), calibrated = False):
self.criteria = criteria
self.objpoints = []
self.imgpoints = []
self.objp = np.zeros((6*7,3), np.float32)
self.objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)
self.image = image
self.mtx = mtx
self.dist = dist
self.calibrated = calibrated
self.pixelsize = camera_data["pixelsize"]
self.matrixsize = camera_data["matrixsize"]
self.baseline = camera_data["baseline"]
self.lens_distance = camera_data["lens_distance"]
def calibrate(self, image):
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
ret, corners = cv2.findChessboardCorners(gray, (7,6),None)
if ret == True:
self.objpoints.append(self.objp)
corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),self.criteria)
self.imgpoints.append(corners2)
h, w = image.shape[:2]
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)
self.mtx = mtx
self.dist = dist
self.calibrated = True
return mtx, dist
def undistort(self, image, mtx, dist):
if dist == None or mtx == None or image == None:
raise Missing_calibration_data_error
h, w = image.shape[:2]
newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))
dst = cv2.undistort(image, mtx, dist, None, newcameramtx)
x,y,w,h = roi
dst = dst[y:y+h, x:x+w]
return image
def calculate_point_relative_position(self, point_location2d):
angle = self.baseline/(point_location2d[left][x]-point_location2d[right][x])
x = angle * (point_location2d[left][x]-self.matrixsize[0]/2)
y = angle * (point_location2d[left][y]-self.matrixsize[1]/2)
z = self.lens_distance * (1-angle/self.pixelsize)
return [x, y, z]
´´´
, and features.py(module to detect and match the features, aparently where the issue happens):
´´´
import sys
import cv2
import numpy as np
cv2.ocl.setUseOpenCL(False)
class Unknown_algorythm_error(Exception):
def __init__(self):
pass
class No_image_passed_error(Exception):
def __int__ (self):
pass
class Corner_detector():
def __init__(self, image, detectortype="ORB", corners=[]):
self.corners = corners
self.image = image
self.detectortype = detectortype
def update(self, image=None):
if self.detectortype == "Harris":
self.corners = cv2.cornerHarris(image, 3, 3, 0, 1)
elif self.detectortype == "Shi-Tomasi":
self.corners = cv2.goodFeaturesToTrack(image, 3, 3, 0, 1)
elif self.detectortype == "ORB":
orb = cv2.ORB_create()
kp, corners = orb.detectAndCompute(image,None)
elif self.detectortype == "SURF":
minHessian = 400
detector = cv2.features2d_SURF(hessianThreshold=minHessian)
keypoints1, descriptors1 = detector.detectAndCompute(img1, None)
keypoints2, descriptors2 = detector.detectAndCompute(img2, None)
else:
raise Unknown_algoryth_error
return self.corners
def updateanddisplay(self):
dst = self.update(image=self.image)
self.image[dst>0.01*dst.max()] = 0
return self.image
class Feature_matcher():
def __init__(self, matcher = cv2.DescriptorMatcher_create(cv2.DescriptorMatcher_FLANNBASED)):
self.matcher = matcher
´´´
Does anyone know how to fix this? I've been looking for the answer for quite a while but i only find the answer for when you're converting the image to grayscale and it doesnt work for me.
It's hard to follow, but I think I identified the issue:
You are passing orb.detectAndCompute an image of type np.float32.
orb.detectAndCompute does not support image of type np.float32.
Reproducing the problem:
The following "simple test" reproduces the problem:
The code sample passes a black (zeros) image to orb.detectAndCompute:
The following code passes without an exception (image type is np.uint8):
# image type is uint8:
image = np.zeros((100, 100), np.uint8)
orb = cv2.ORB_create()
kp, corners = orb.detectAndCompute(image, None)
The following code raises an exception because image type is np.float32:
# image type is float32:
image = np.float32(np.zeros((100, 100), np.uint8))
orb = cv2.ORB_create()
kp, corners = orb.detectAndCompute(image, None)
Rises an exception:
Invalid number of channels in input image:
Solution:
Try to avoid the np.float32 conversion.
You may also convert image to uint8 as follows:
kp, corners = orb.detectAndCompute(image.astype(np.uint8), None)

Python multiprocessing queue is empty although it is filled in a different thread

I have now tried to resolve this issue for multiple hours but no matter what I do, I never get the thing to work.
My project tracks live data and provides an endpoint for other services to get the latest(ish) measurement. But no matter what I do, the queue.get() always returns nothing.
Here is my code:
from collections import deque
import numpy as np
import argparse
import imutils
import cv2
from flask import Flask
from multiprocessing import Queue
import threading
import Queue as Q
app = Flask(__name__)
class ImageParser(object):
def dosmth(self, q):
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video", help="path to the (optional) video file")
ap.add_argument("-b", "--buffer", type=int, default=14, help="max buffer size")
args = vars(ap.parse_args())
greenLower = [(86, 61, 128)]
greenUpper = [(148, 183, 196)]
pts1 = deque(maxlen=args["buffer"])
pts2 = deque(maxlen=args["buffer"])
if not args.get("video", False):
camera = cv2.VideoCapture(0)
else:
camera = cv2.VideoCapture(args["video"])
while True:
(grabbed, frame) = camera.read()
if args.get("video") and not grabbed:
break
frame = imutils.resize(frame, width=1200)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
for j in range(len(greenLower)):
upper = greenUpper[j]
lower = greenLower[j]
mask = cv2.inRange(hsv, lower, upper)
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[-2]
for i in range(len(cnts)):
center = None
if len(cnts) > 0:
c = max(cnts, key=cv2.contourArea)
((x, y), radius) = cv2.minEnclosingCircle(c)
M = cv2.moments(c)
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
if radius > 10:
q.put(center)
cv2.circle(frame, (int(x), int(y)), int(radius),
(0, 255, 255), 2)
cv2.circle(frame, center, 5, (0, 0, 255), -1)
if j == 0:
pts1.appendleft(center)
for i in xrange(1, len(pts1)):
if pts1[i - 1] is None or pts1[i] is None:
continue
thickness = int(np.sqrt(args["buffer"] / float(i + 1)) * 2.5)
cv2.line(frame, pts1[i - 1], pts1[i], (255,0,0), thickness)
if j == 1:
pts2.appendleft(center)
for i in xrange(1, len(pts2)):
if pts2[i - 1] is None or pts2[i] is None:
continue
thickness = int(np.sqrt(args["buffer"] / float(i + 1)) * 2.5)
cv2.line(frame, pts2[i - 1], pts2[i], (51, 153, 255), thickness)
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
camera.release()
cv2.destroyAllWindows()
imgPar = ImageParser()
q = Queue()
scp = threading.Thread(target=imgPar.dosmth, args=(q,))
scp.start()
def getVal():
try:
(x,y) = q.get_nowait()
except Q.Empty:
return -1 , -1
return (x,y)
#app.route('/', methods=['GET'])
def doMain():
x,y = getVal()
print x,y
return '{},{}'.format(x,y)
app.run(debug=True, host='10.21.8.52')
As I really do not have any other clue, what I should do, any help would be appreciated.
Everything is running on python 2.7.15 in an anaconda environment if that helps in any way.
As I really do not have
I took the liberty of stripping out the CV2 code as I don't have a camera, and replace the queue filler with a pair of random numbers every .5 seconds, and PEP8-ing the code a bit, and this way it works:
import random
import time
from flask import Flask
import threading
from multiprocessing import Queue
from Queue import Empty as QueueEmpty
app = Flask(__name__)
class ImageParser(object):
def __init__(self, queue):
self.queue = queue
self.source = random.random
self.pause = 0.5
def run(self):
while True:
value = (self.source(), self.source())
self.queue.put(value)
time.sleep(self.pause)
queue = Queue()
image_parser = ImageParser(queue)
image_thread = threading.Thread(target=image_parser.run)
#app.route('/', methods=['GET'])
def do_main():
try:
value = queue.get_nowait()
except QueueEmpty:
value = None
print(value)
return str(value)
if __name__ == '__main__':
image_thread.start()
app.run(debug=True, host='127.0.0.1')
Under http://127.0.0.1:5000/ I now get pairs of random numbers, and the occasional None when I reload too fast.
I therefore conclude that the problem probably lies with the image processing part. Specifically I noticed that only contours with an enclosing radius > 10 get put into the queue. Maybe that path of code just never gets executed. Are you quite sure that any values get put into the queue at all? Maybe a print x, y, radius before the if radius > 10 will shed some light. (And why put center instead of x and y?)

Main thread not in main loop error in threading module

import time
import datetime as dt
import urllib.request
from bs4 import BeautifulSoup
import matplotlib.pyplot as plt
import matplotlib.animation as Animation
from matplotlib import style
import matplotlib
import csv
import threading
style.use('fivethirtyeight')
fig = plt.figure()
def usd_in_bitcoin():
try:
resp = urllib.request.urlopen("https://bitcoinwisdom.com/")
except Exception as e:
print(e)
text = resp.read()
soup = BeautifulSoup(text, 'html.parser')
intermediate = soup.find('tr', {"id": "o_btcusd"})
ans = intermediate.find('td', {'class': 'r'})
return ans.contents[0]
def write_to_file(interval):
while True:
value = str(usd_in_bitcoin())
unix_time = str(time.time())
print(unix_time, value)
with open('bitcoin_usd.csv', 'a+') as file:
file.write(unix_time)
file.write("," + str(value))
file.write('\n')
time.sleep(interval)
def animate(i):
with open('bitcoin_usd.csv') as csv_file:
readcsv = csv.reader(csv_file, delimiter=',')
xs = []
ys = []
for row in readcsv:
if len(row) > 1:
x, y = [float(s) for s in row]
xs.append(dt.datetime.fromtimestamp(x))
ys.append(y)
print(len(xs))
dates = matplotlib.dates.date2num(xs)
# print(dates)
fig.clear()
plt.plot_date(dates, ys)
def plotting():
ani = Animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
def main():
# plotting()
b = threading.Thread(name='making graph', target=plotting)
# a = threading.Thread(name='updating_csv', target=write_to_file, args=(5,))
# a.start()
b.start()
if __name__ == '__main__':
main()
In the above block of code, I am trying to plot the value of a bitcoin in usd by using scraping and then putting the value in a csv file.
Then I read the csv file to plot the graph.
Both plotting and scraping seem to work fine but if I do both of them simultaneously, I am getting an error saying main thread not in main loop. I searched a lot but was not able to solve this problem
The problem here is with the sequence of lines in main()
Try this:
def main():
a = threading.Thread(name='updating_csv', target=write_to_file, args=(5,))
a.start()
b = threading.Thread(name='making graph', target=plotting)
b.start()
plotting()

Resources