How to display variables in python without using print() - python-3.x

I'm a reallyyyy new user to python, and mostly used Matlab before so still trying to understand the workings of python.
I've managed to write a program that detects ARUCO markers using a camera and calculates their pose vectors: a 3D translation list (# of markers, 1,3) and another for rotation (# of markers, 1,3).
I currently use print() to display the two vectors in "time" ( refresh with the camera's fps)...and trying to figure out if a separate window could be used to display them and refresh with each new frame.
I have done some looking into tkinter but it wasn't really working for me. I am not sure if there is a smarter or easier way to do this.
** only using arbitrary values right now to set up the code and then my plan was to create a function where I could feed in the marker ids, translationvectors, rotation vectors**
#Purpose: Create a Ouput GUI for output of Translation and Rotation Vectors
#def disp_PoseVal(ids, combpairs, id_rvec, id_tvec, r_rel, t_rel)
#marker id
a=[3.5, 2.5, 8]
a = " ".join(str(elem) for elem in a)
#a_str=''.join(a)
print(a)
#tranlation
#need to add an asterix to unpack range!
b = [[*range(3)], [*range(2,5)], [*range(8,11)]]
print(b)
#rotation
c=b
rootwindow = tk.Tk()
rootwindow.title("ARUCO Marker Pose information")
rootwindow.geometry('{}x{}'.format(800, 500))
#Frame 0: IDs
frame_0 = tk.LabelFrame(rootwindow,text="Detected Marker IDs")
frame_0.pack(side="top")
#Read IDs
rids = tk.Text(frame_0)
rids.insert("end",a)
rids.grid(row=0,columnspan=2)
#rids.pack()
#Frame 1: WRT to camera
frame_1 = tk.LabelFrame(rootwindow, height=100, text="Pose Vectors: Tranlation+ Rotation")
frame_1.pack()
#Translation Vector
Trans=tk.Text(frame_1)
for x in b:
ttemp = " ".join(str(x))
print(ttemp)
print('type',type(ttemp))
Trans.insert("end", ttemp + '\n')
Trans.grid(row=1,column=0)
#Rotation Vector
Rot=tk.Text(frame_1)
for y in c:
rtemp = " ".join(str(y))
print(rtemp)
print('type', type(rtemp))
Rot.insert("end", rtemp + '\n')
Rot.grid(row=1, column=1)
rootwindow.mainloop()```

Related

opencv python alternative for pyautogui.locatecenteronscreen(), just for an image instead of screen

i was wondering how you would use opencv (cv2) in python for making an alternative to pyautogui.locatecenteronscreen() function, just useing an image instead of an screen.
i will try useing an example.
maybe an user defined function,locateCenterOfTemplate("Path/to/template.png")
and now since im useing a screenshot as original image, it will ofc be the same as if i would
use pyautoguis, but for my main purpose i wont ofc.
import cv2
import pyautogui
pyautogui.screenshot(Path/to/original_image.png)
def locateCenterOfTemplate(image, template, accuracy=100,
region=#whole screen idk how to do this eaither):
temp = locateCenterOfTemplate("Path/to/original_image.png", "Path/to/template.png")
# now variable "temp" is the same as the posision of the center of the template,
# inside of the source immage
pyautogui.click(temp)
Basicly, i would like to have template matching with reagion, confidence and both template and original image as a functino :)
Thanks :D
If you load the image and template using cv2.imread(path). You can use cv2.matchTemplate. A while back I used this code to match all templates on a screen with a confidence higher than threshold. You can use debug=True, to draw a box around the found templates in red (cv2 uses BGR).
def match_all(image, template, threshold=0.8, debug=False, color=(0, 0, 255)):
""" Match all template occurrences which have a higher likelihood than the threshold """
width, height = template.shape[:2]
match_probability = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
match_locations = np.where(match_probability >= threshold)
# Add the match rectangle to the screen
locations = []
for x, y in zip(*match_locations[::-1]):
locations.append(((x, x + width), (y, y + height)))
if debug:
cv2.rectangle(image, (x, y), (x + width, y + height), color, 1)
return locations
It will return a list of bounding boxes for the areas that match. If you only want to return the highest match, you should adjust the match_locations line to:
match_location = np.unravel_index(match_probability.argmax(), match_probability.shape)
Alternatively if you are OK to use another library, you can take a look at Multi-Template-Matching, which returns a pandas DataFrame with the template name, bounding box and score.

Create new raster (.tif) from standard deviation stretched bands, works with dstack but not to write a new file, Python

I am sorry if the title is unclear, I am new to python and my vocabulary is limited.
What I am trying to do is apply a standard deviation stretch to each band in a .tif raster and then create a new raster (.tif) by stacking those bands using GDAL (Python).
I able to create new false color rasters with differing band combinations and save them, and I am able to create my desired IMAGE in python using dstack (first block of code), but I am unable to save that image as a georectified .tif file.
So to create the stretched image using dstack my code looks like:
import os
import numpy as np
import matplotlib.pyplot as plt
import math
from osgeo import gdal
# code from my prof
def std_stretch_data(data, n=2):
"""Applies an n-standard deviation stretch to data."""
# Get the mean and n standard deviations.
mean, d = data.mean(), data.std() * n
# Calculate new min and max as integers. Make sure the min isn't
# smaller than the real min value, and the max isn't larger than
# the real max value.
new_min = math.floor(max(mean - d, data.min()))
new_max = math.ceil(min(mean + d, data.max()))
# Convert any values smaller than new_min to new_min, and any
# values larger than new_max to new_max.
data = np.clip(data, new_min, new_max)
# Scale the data.
data = (data - data.min()) / (new_max - new_min)
return data
# open the raster
img = gdal.Open(r'/Users/Rebekah/ThesisData/TestImages/OG/OG_1234.tif')
#open the bands
red = img.GetRasterBand(1).ReadAsArray()
green = img.GetRasterBand(2).ReadAsArray()
blue = img.GetRasterBand(3).ReadAsArray()
# create alpha band where a 0 indicates a transparent pixel and 1 is a opaque pixel
# (this is from class and i dont FULLY understand it)
alpha = np.where(red + green + blue ==0, 0, 1).astype(np.byte)
red_stretched = std_stretch_data(red, 1)
green_stretched = std_stretch_data(green, 1)
blue_stretched = std_stretch_data(blue, 1)
data_stretched = np.dstack((red_stretched, green_stretched, blue_stretched, alpha))
plt.imshow(data_stretched)
plt.show()
And that gives me a beautiful image of exactly what I want in a separate window. But no where in that code is an option to assign projections, or save it as a multiband tif.
So I took that and applied it the best I could to the code I use to create false color images and it fails (code below). If I create a 4 band tif with the alpha band the output is an empty tif, and if I create a 3 band tif and omit the alpha band the output is an entirely black tif.
import os
import numpy as np
import matplotlib.pyplot as plt
import math
from osgeo import gdal
#code from my professor
def std_stretch_data(data, n=2):
"""Applies an n-standard deviation stretch to data."""
# Get the mean and n standard deviations.
mean, d = data.mean(), data.std() * n
# Calculate new min and max as integers. Make sure the min isn't
# smaller than the real min value, and the max isn't larger than
# the real max value.
new_min = math.floor(max(mean - d, data.min()))
new_max = math.ceil(min(mean + d, data.max()))
# Convert any values smaller than new_min to new_min, and any
# values larger than new_max to new_max.
data = np.clip(data, new_min, new_max)
# Scale the data.
data = (data - data.min()) / (new_max - new_min)
return data
#open image
img = gdal.Open(r'/Users/Rebekah/ThesisData/TestImages/OG/OG_1234.tif')
# get geotill driver
gtiff_driver = gdal.GetDriverByName('GTiff')
# read in bands
red = img.GetRasterBand(1).ReadAsArray()
green = img.GetRasterBand(2).ReadAsArray()
blue = img.GetRasterBand(3).ReadAsArray()
# create alpha band where a 0 indicates a transparent pixel and 1 is a opaque pixel
# (this is from class and i dont FULLY understand it)
alpha = np.where(red + green + blue ==0, 0, 1).astype(np.byte)
# apply the 1 standard deviation stretch
red_stretched = std_stretch_data(red, 1)
green_stretched = std_stretch_data(green, 1)
blue_stretched = std_stretch_data(blue, 1)
# create empty tif file
NewImg = gtiff_driver.Create('/Users/riemann/ThesisData/TestImages/FCI_tests/1234_devst1.tif', img.RasterXSize, img.RasterYSize, 4, gdal.GDT_Byte)
if NewImg is None:
raise IOerror('could not create new raster')
# set the projection and geo transform of the new raster to be the same as the original
NewImg.SetProjection(img.GetProjection())
NewImg.SetGeoTransform(img.GetGeoTransform())
# write new bands to the new raster
band1 = NewImg.GetRasterBand(1)
band1.WriteArray(red_stretched)
band2 = NewImg.GetRasterBand(2)
band2.WriteArray(green_stretched)
band3= NewImg.GetRasterBand(3)
band3.WriteArray(blue_stretched)
alpha_band = NewImg.GetRasterBand(4)
alpha_band.WriteArray(alpha)
del band1, band2, band3, img, alpha_band
I am not entirely sure how to go from here and create a new file displaying the stretch on the different bands.
The image is just a 4 band raster (NAIP) downloaded from earthexplorer, I can upload the specific image I am using for my test if needed but there is nothing inherently special about this file compared to other NAIP images.
You should close the new Dataset (NewImg) as well by either adding it to the del list you already have, or setting it to None.
That properly closes the file and makes sure all data is written to disk.
There is however another issue, you are scaling your data between 0 and 1, but storing it as a Byte. So either change the output datatype from gdal.GDT_Byte to something like gdal.GDT_Float32. Or multiply your scaled data to fit the output datatype, in the case of Byte multiple with 255 (don't forget the alpha), you should properly round it for accuracy, GDAL will otherwise truncate to the nearest integer.
You can use np.iinfo() to check what the range of a datatype is, in case you are unsure what multiplication to use for other datatypes.
Depending on your use case, it might be easiest to use gdal.Translate for the scaling. If you would modify your scaling function a little to return the scaling parameteters instead of the data, you could use something like:
ds = gdal.Translate(output_file, input_file, outputType=gdal.GDT_Byte, scaleParams=[
[old_min_r, old_max_r, new_min_r, new_max_r], # red
[old_min_g, old_max_g, new_min_g, new_max_g], # green
[old_min_b, old_max_b, new_min_b, new_max_b], # blue
[old_min_a, old_max_a, new_min_a, new_max_a], # alpha
])
ds = None
You could also add the exponents keyword for non-linear stretching.
Using gdal.Translate would save you from all the standard file creation boilerplate, you still would need to think about the datatype, since that might change compared to the input file.

networkx stared nodes rendered at wrong place with matplotib

i have stared nodes positions with networkx but matplotlib render it at wrong place.
What is very important is to get the same picture each time i launch the script : so, nodes coordinates respect is fundamental.
Also, the view is too compact, forcing me too manually zoom inside, and appears in figure2 in place of figure1.
finally, matplotlib works on little float scale [-1,1] where i prefer screen dimension x [0,1280] and y [0,704].
i have tried many source code but it still doesnt do the job properly
import matplotlib.pyplot as plt
import networkx as nx
zero_zero = 'zero_zero'
zero_one = 'zero_one'
one_zero = 'one_zero'
one_one = 'one_one'
foo_1 = 'foo_1'
foo_2 = 'foo_2'
foo_3 = 'foo_3'
bar_1 = 'bar_1'
bar_2 = 'bar_2'
bar_3 = 'bar_3'
stuff_1 = 'stuff_1'
stuff_2 = 'stuff_2'
stuff_3 = 'stuff_3'
waow = 'waow'
fig = plt.figure(figsize=(100,100))
fig, ax = plt.subplots()
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5 , 1.5)
G = nx.Graph()
starpos={zero_zero:(0,0), zero_one:(0,1), one_zero:(1,0), one_one:(1,1), foo_1:(1,0),foo_2:(0.1,0.1),foo_3:(0.2,0.3),bar_1:(0.3,0.2),bar_2:(0.76,.80),bar_3:(0,0.2),stuff_1:(0.8,0.6),stuff_2:(0.3,0.9),stuff_3:(0.7,0.7),waow:(0.4,0.6)}
for k,v in starpos.items():
G.add_node(k,pos=v)
G.nodes(data=True)
G.add_edge(foo_1, foo_2)
G.add_edge(foo_3, bar_3)
G.add_edge(bar_1, foo_3)
G.add_edge(bar_1, bar_2)
G.add_edge(bar_3, bar_2)
G.add_edge(stuff_1, stuff_3)
G.add_edge(waow, bar_3)
G.add_edge(bar_2, stuff_3)
G.add_edge(zero_zero, zero_one)
G.add_edge(zero_one, one_zero)
G.add_edge(one_zero, one_one)
G.add_edge(one_one, zero_zero)
pos = nx.spring_layout(G)
nx.draw(G, pos, font_size=16, with_labels=False)
for p in pos: # raise text positions
pos[p][1] += 0.07
nx.draw_networkx_labels(G, pos)
plt.show()
networkx matplotlib picture
Let's first deal with a misconception: even though you've assigned an attribute 'pos' to each node in the graph, the drawing commands don't use that at all.
When you do:
nx.draw(G, pos)
the argument pos is a dictionary whose keys are the nodes of G and whose values are the positions you want them to be in. In your case, you've defined pos using pos=nx.spring_layout(G). In this command, each node is initially given a random position, and then it treats the nodes as masses which are connected by springs and tries to find where the nodes would move to. So every time it will find a different arrangement, and - this is important - it doesn't care at all about the node attributes you've defined.
In your case, you've already defined the dictionary starpos, which I believe has the desired position of each node. So there's no need to assign an attribute when you create the nodes [since networkx doesn't use the attributes to assign positions]. Then when you draw it, use the dictionary you've already created rather than using spring_layout to create a new one. Try
nx.draw(G, starpos, font_size=16, with_labels=False)

Changing width of heatmap in Seaborn to compensate for font size reduction

I have a sentence like say
Hey I am feeling pretty boring today and the day is dull too
I pass it through the openai sentiment code which gives me some neuron weights which can be equal or little greater then number of words.
Neuron weights are
[ 0.01258736, 0.03544582, 0.08490616, 0.09010842, 0.07180552,
0.07271874, 0.08906463, 0.09690772, 0.10281454, 0.08131664,
0.08315734, 0.0790544 , 0.07770097, 0.07302617, 0.07329235,
0.06856266, 0.07642639, 0.08199468, 0.09079508, 0.09539193,
0.09061056, 0.07109602, 0.02138061, 0.02364372, 0.00322057,
0.01517018, 0.01150052, 0.00627739, 0.00445003, 0.00061127,
0.0228037 , -0.29226044, -0.40493113, -0.4069235 , -0.39796737,
-0.39871565, -0.39242673, -0.3537892 , -0.3779315 , -0.36448184,
-0.36063945, -0.3506464 , -0.36719123, -0.37997353, -0.35103855,
-0.34472692, -0.36256564, -0.35900915, -0.3619383 , -0.3532831 ,
-0.35352525, -0.33328298, -0.32929575, -0.33149993, -0.32934144,
-0.3261477 , -0.32421976, -0.3032671 , -0.47205922, -0.46902984,
-0.45346943, -0.4518705 , -0.50997925, -0.50997925]
Now what I wanna do is plot a heatmap , the positive values shows positive sentiments while negative ones shows negative sentiment and I am plotting the heat map but the heatmap isn't plotting like it should be
But when the sentence gets longer the whole sentence gets smaller and smaller that can't be seen ,So what changes should I do to make it show better.
Here is my plotting function:
def plot_neuron_heatmap(text, values, savename=None, negate=False, cell_height=.112, cell_width=.92):
#n_limit = 832
cell_height=.325
cell_width=.15
n_limit = count
num_chars = len(text)
text = list(map(lambda x: x.replace('\n', '\\n'), text))
num_chars = len(text)
total_chars = math.ceil(num_chars/float(n_limit))*n_limit
mask = np.array([0]*num_chars + [1]*(total_chars-num_chars))
text = np.array(text+[' ']*(total_chars-num_chars))
values = np.array((values+[0])*(total_chars-num_chars))
values = values.reshape(-1, n_limit)
text = text.reshape(-1, n_limit)
mask = mask.reshape(-1, n_limit)
num_rows = len(values)
plt.figure(figsize=(cell_width*n_limit, cell_height*num_rows))
hmap=sns.heatmap(values, annot=text, mask=mask, fmt='', vmin=-5, vmax=5, cmap='RdYlGn',xticklabels=False, yticklabels=False, cbar=False)
plt.subplots_adjust()
#plt.tight_layout()
plt.savefig('fig1.png')
#plt.show()
This is how it shows the lengthy text as
What I want it to show
Here is a link to the full notebook: https://github.com/yashkumaratri/testrepo/blob/master/heatmap.ipynb
Mad Physicist , Your code does this
and what really it should do is
The shrinkage of the font you are seeing is to be expected. As you add more characters horizontally, the font shrinks to fit everything in. There are a couple of solutions for this. The simplest would be to break your text into smaller chunks, and display them as you show in your desired output. Also, you can print your figure with a different DPI with what is shown on the screen, so that the letters will look fine in the image file.
You should consider cleaning up your function along the way:
count appears to be a global that is never used.
You redefine variables without ever using the original value (e.g. num_chars and the input parameters).
You have a whole bunch of variables you don't really use.
You recompute a lot of quantities multiple times.
The expression list(map(lambda x: x.replace('\n', '\\n'), text)) is total overkill: list(text.replace('\n', '\\n')) does the same thing.
Given that len(values) != len(text) for most cases, the line values = np.array((values+[0])*(total_chars-num_chars)) is nonsense and needs cleanup.
You are constructing numpy arrays by doing padding operations on lists, instead of using the power of numpy.
You have the entire infrastructure for properly reshaping your arrays already in place, but you don't use it.
The updated version below fixes the minor issues and adds n_limit as a parameter, which determines how many characters you are willing to have in a row of the heat map. As I mentioned in the last item, you already have all the necessary code to reshape your arrays properly, and even mask out the extra tail you end up with sometimes. The only thing that is wrong is the -1 in the shape, which always resolves to one row because of the remainder of the shape. Additionally, the figure is always saved at 100dpi, so the results should come out consistent for a given width, no matter how many rows you end up with. The DPI affects PNG because it increases or decreases the total number of pixels in the image, and PNG does not actually understand DPI:
def plot_neuron_heatmap(text, values, n_limit=80, savename='fig1.png',
cell_height=0.325, cell_width=0.15, dpi=100):
text = text.replace('\n', '\\n')
text = np.array(list(text + ' ' * (-len(text) % n_limit)))
if len(values) > text.size:
values = np.array(values[:text.size])
else:
t = values
values = np.zeros(text.shape, dtype=np.int)
values[:len(t)] = t
text = text.reshape(-1, n_limit)
values = values.reshape(-1, n_limit)
# mask = np.zeros(values.shape, dtype=np.bool)
# mask.ravel()[values.size:] = True
plt.figure(figsize=(cell_width * n_limit, cell_height * len(text)))
hmap = sns.heatmap(values, annot=text, fmt='', vmin=-5, vmax=5, cmap='RdYlGn', xticklabels=False, yticklabels=False, cbar=False)
plt.subplots_adjust()
plt.savefig(savename if savename else 'fig1.png', dpi=dpi)
Here are a couple of sample runs of the function:
text = 'Hey I am feeling pretty boring today and the day is dull too'
values = [...] # The stuff in your question
plot_neuron_heatmap(text, values)
plot_neuron_heatmap(text, values, 20)
plot_neuron_heatmap(text, values, 7)
results in the following three figures:

Matplotlib - Stacked Bar Chart with ~1000 Bars

Background:
I'm working on a program to show a 2d cross section of 3d data. The data is stored in a simple text csv file in the format x, y, z1, z2, z3, etc. I take a start and end point and flick through the dataset (~110,000 lines) to create a line of points between these two locations, and dump them into an array. This works fine, and fairly quickly (takes about 0.3 seconds). To then display this line, I've been creating a matplotlib stacked bar chart. However, the total run time of the program is about 5.5 seconds. I've narrowed the bulk of it (3 seconds worth) down to the code below.
'values' is an array with the x, y and z values plus a leading identifier, which isn't used in this part of the code. The first plt.bar is plotting the bar sections, and the second is used to create an arbitrary floor of -2000. In order to generate a continuous looking section, I'm using an interval between each bar of zero.
import matplotlib.pyplot as plt
for values in crossSection:
prevNum = None
layerColour = None
if values != None:
for i in range(3, len(values)):
if values[i] != 'n':
num = float(values[i].strip())
if prevNum != None:
plt.bar(spacing, prevNum-num, width=interval, \
bottom=num, color=layerColour, \
edgecolor=None, linewidth=0)
prevNum = num
layerColour = layerParams[i].strip()
if prevNum != None:
plt.bar(spacing, prevNum+2000, width=interval, bottom=-2000, \
color=layerColour, linewidth=0)
spacing += interval
I'm sure there's a more efficient way to do this, but I'm new to Matplotlib and still unfamilar with its capabilities. The other main use of time in the code is:
plt.savefig('output.png')
which takes about a second, but I figure this is to be expected to save the file and I can't do anything about it.
Question:
Is there a faster way of generating the same output (a stacked bar chart or something that looks like one) by using plt.bar() better, or a different Matplotlib function?
EDIT:
I forgot to mention in the original post that I'm using Python 3.2.3 and Matplotlib 1.2.0
Leaving this here in case someone runs into the same problem...
While not exactly the same as using bar(), with a sufficiently large dataset (large enough that using bar() takes a few seconds) the results are indistinguishable from stackplot(). If I sort the data into layers using the method given by tcaswell and feed it into stackplot() the chart is created in 0.2 seconds, rather than 3 seconds.
EDIT
Code provided by tcaswell to turn the data into layers:
accum_values = []
for values in crosssection:
accum_values.append([float(v.strip()) for v iv values[3:]])
accum_values = np.vstack(accum_values).T
layer_params = [l.strip() for l in layerParams]
bottom = numpy.zeros(accum_values[0].shape)
It looks like you are drawing each bar, you can pass sequences to bar (see this example)
I think something like:
accum_values = []
for values in crosssection:
accum_values.append([float(v.strip()) for v iv values[3:]])
accum_values = np.vstack(accum_values).T
layer_params = [l.strip() for l in layerParams]
bottom = numpy.zeros(accum_values[0].shape)
ax = plt.gca()
spacing = interval*numpy.arange(len(accum_values[0]))
for data,color is zip(accum_values,layer_params):
ax.bar(spacing,data,bottom=bottom,color=color,linewidth=0,width=interval)
bottom += data
will be faster (because each call to bar creates one BarContainer and I suspect the source of your issues is you were creating one for each bar, instead of one for each layer).
I don't really understand what you are doing with the bars that have tops below their bottoms, so I didn't try to implement that, so you will have to adapt this a bit.

Resources