Sikuli 1.1 making a new Region from an existing Region - python

Im trying to reuse predefined regions but I get Nonetype error when assigning it to a new variable using sikuli.setW(). Here's my code:
import math
import sikuli
self.screen_reg = sikuli.Screen(0)
self.monitor_reg = self.screen_reg
self.leftreg = sikuli.Region(
self.monitor_reg.x,
self.monitor_reg.y,
int(math.floor(self.monitor_reg.w/2)),
self.monitor_reg.h)
self.rightreg = sikuli.Region(
self.monitor_reg.x + int(math.floor(self.monitor_reg.w/2)),
self.monitor_reg.y,
int(math.floor(self.monitor_reg.w/2)),
self.monitor_reg.h)
self.leftreg.highlight(3) <=== working
self.quarter = self.leftreg.setW(int(math.floor(self.leftreg.w/2)))
self.quarter.highlight(3) <====== didnt work;
error: NoneType object has no attribute highlight
If I print type(quarter), it returns NoneType.
If I change it into these:
self.leftreg.highlight(3)
self.leftreg.setW(int(math.floor(self.leftreg.w/2)))
self.leftreg.highlight(3)
It works fine. What am I missing? Thanks for the help.

> What am I missing?
An object method may not have return type.
Here is excerpt from Sikuli source code
public void setW(int W) {
w = W > 1 ? W : 1;
initScreen(null);
}
Return type of setW is void. That is it returns nothing, while you expected that it returns a Region.
A correct way to do what you want would be:
self.quarter = Region(self.leftreg) # this constructs a new region
self.quarter.setW(int(math.floor(self.leftreg.w/2))) # and this resizes it

Related

Heatmap error "TraitError: The 'locations' trait of a Heatmap instance must be of length"

I'm trying to run a code that registers coordinates onto a heat map using Javascript on Jupyter Notebook. My code is:
import gmaps
import gmaps.datasets
gmaps.configure(api_key="MY API KEY")
data = [(-89.91161093276477, 35.241969778429194), (-89.87947624903887, 35.195319161704404), (-89.81418532101328, 35.17188216058175), (-89.75643652692003, 35.183538628834484), (-89.7496498284386, 35.14509890887518), (-89.78504762327763, 35.063349559432304), (-89.83100682136623, 35.013757847903044), (-89.85342496546569, 35.001086997562474)]
m = gmaps.Map()
heatmap_layer = gmaps.Heatmap(data=data)
m.add_layer(heatmap_layer)
m
But I keep on getting the error:
TraitError: The 'locations' trait of a Heatmap instance must be of length 1 <= L <= 9223372036854775807, but a value of [] was specified.
What does this mean and how can I fix it?
You are seeing this error because the function expects locations and you don't have anything defined there. I don't think you are calling your heatmap_layer correctly either.
https://jupyter-gmaps.readthedocs.io/en/latest/tutorial.html#heatmaps
Try this:
import gmaps.datasets
gmaps.configure(api_key="MY API KEY")
locations = [(-89.91161093276477, 35.241969778429194), (-89.87947624903887, 35.195319161704404), (-89.81418532101328, 35.17188216058175), (-89.75643652692003, 35.183538628834484), (-89.7496498284386, 35.14509890887518), (-89.78504762327763, 35.063349559432304), (-89.83100682136623, 35.013757847903044), (-89.85342496546569, 35.001086997562474)]
m = gmaps.Map()
heatmap_layer = gmaps.heatmap_layer(locations)
m.add_layer(heatmap_layer)
m

How do I get values from a C dll array pointer using ctypes and Python

A DLL provides a pointer to a 1D array in my C code like this:
__int16 *data = Msg_RowAt(surfaceMsg, rowIdx);
//access the values like this
data[iterator]
I'm building a Python project where I need to access the values of the same array. I've tried the following but get an access violation when I try iterate surfaceData.
surfaceDataPtr = Msg_RowAt(surfaceMsg, row)
ptr = ctypes.POINTER(ctypes.c_int16)
surfaceData = ctypes.cast(surfaceDataPtr, ptr)
print("ptr: " + str(surfaceData))
print("val: " + str(surfaceData[1]))
I'm accessing the wrong memory location but I'm not too sure what I've done wrong. Can anyone see what I'm doing wrong?
You can define restype:
c.Msg_RowAt.restype = ctypes.POINTER(ctypes.c_int16)
surfaceDataPtr = Msg_RowAt(surfaceMsg, row)
Then, you can randomly access to each element:
print(surfaceDataPtr[0])
print(surfaceDataPtr[1])
...

rpy2 code snippet returns an empty object

I am using rpy2 to use a R library in Python. The library has a function prebas() that returns an array in which the item with index [8] is the output. When I write this output to CSV within the R code snippet, everything works as expected (the output is a CSV over 200kB). However, when I return the same object (PREBASout[8]), it returns an empty object. So, obviously, when I write that object to CSV, the file is empty.
run_prebasso = robjects.r('''
weather <- read.csv("/home/example_inputs/weather.csv",header = T)
PAR = c(weather$PAR,weather$PAR,weather$PAR)
TAir = c(weather$TAir,weather$TAir,weather$TAir)
Precip = c(weather$Precip,weather$Precip,weather$Precip)
VPD = c(weather$VPD,weather$VPD,weather$VPD)
CO2 = c(weather$CO2,weather$CO2,weather$CO2)
DOY = c(weather$DOY,weather$DOY,weather$DOY)
library(Rprebasso)
PREBASout = prebas(nYears = 100, PAR=PAR,TAir=TAir,VPD=VPD,Precip=Precip,CO2=CO2)
write.csv(PREBASout[8],"/home/outputs/written_in_r.csv",row.names = F)
PREBASout[8]
''')
r_write_csv = robjects.r['write.csv']
r_write_csv(run_prebasso, "/home/outputs/written_in_py.csv")
This is what the code snippet returns:
(Pdb) run_prebasso
<rpy2.rinterface.NULLType object at 0x7fc1b31e6b48> [RTYPES.NILSXP]
Question: Why aren't written_in_py.csv and written_in_r.csv the same?
I have just found the bug. The problem was in the line
write.csv(PREBASout[8],"/home/outputs/written_in_r.csv",row.names = F)
This statement was returned instead of what I wanted (PREBASout[8]). When I removed it or assigned it to a variable, everything worked as expected.

Proper way to use setAttr with channel box selection

please bear with me - I'm new to all this. I tried the searches and have only found bits and pieces to what I'm looking for, but not what I need to connect them.
Basically, I'm trying to create a Python script that allows the user to simply "0" out multiple selected attributes on Maya's Channel box.
So far I have:
import maya.cmds as cmds
selObjs = cmds.ls(sl=1)
selAttrs = cmds.channelBox("mainChannelBox", q=1, sma=1)
print selObjs # returns [u'pCube1']
print selAttrs # returns [u'ty']
If I would like to set the attributes:
cmds.setAttr(selObjs + "." + selAttrs, '0')
of course this is wrong, so how do I properly execute the setAttr command in this sceneario? (The intention includes having to set them if I have multiple selected attributes in the channel box).
I found that in MEL, it works like this. So really I just need help figuring out how to create the python counterpart of this:
string $object[] = `ls -sl`;
string $attribute[] = `channelBox -q -sma mainChannelBox`;
for ($item in $object)
for($attr in $attribute)
setAttr ($item + "." + $attr) 0;
Moving after that, I need an if loop where, if the attribute selected is a scale attribute, the value should be 1 - but this is something I'll look into later, but wouldn't mind being advised on.
Thanks!
So here's what I finally came up with:
import maya.cmds as cmds
selObjs = cmds.ls(sl=1)
selAttrs = cmds.channelBox("mainChannelBox", q=1, sma=1)
scales = ['sy','sx','sz','v']
if not selObjs:
print "no object and attribute is selected!"
elif not selAttrs:
print "no attribute is selected!"
else:
for eachObj in selObjs:
for eachAttr in selAttrs:
if any(scaleVizItem in eachAttr for scaleVizItem in scales):
cmds.setAttr (eachObj+"."+eachAttr, 1)
else:
cmds.setAttr (eachObj+"."+eachAttr, 0)
This will reset the basic transformations to their defaults. Including an if for the scale and visibility values.
I managed to come up with this:
import maya.cmds as cmds
selObjs = cmds.ls(sl=1)
selAttrs = cmds.channelBox("mainChannelBox", q=1, sma=1)
for each in selObjs:
for eachAttr in selAttrs:
cmds.setAttr (each+"."+eachAttr, 0)
And It's working to zero out selected attributes perfectly.
Now im at the stage of figuring out how to get the script to recognize if it contains scale attributes - to change that value to 1 instead of 0. (stuck at how to extract values from a list at the moment)

Python Image Library: How to combine 4 images into a 2 x 2 grid?

I have 4 directories with images for an animation. I would like to take the set of images and generate a single image with the 4 images arranged into a 2x2 grid for each frame of the animation.
My code so far is:
import Image
fluid64 = "Fluid64_half_size/00"
fluid128 = "Fluid128_half_size/00"
fluid512 = "Fluid512_half_size/00"
fluid1024 = "Fluid1024_half_size/00"
out_image = "Fluid_all/00"
for pic in range(1, 26):
blank_image = Image.open("blank.jpg")
if pic < 10:
image_num = "0"+str(pic)
else:
image_num = str(pic)
image64 = Image.open(fluid64+image_num+".jpg")
image128 = Image.open(fluid128+image_num+".jpg")
image512 = Image.open(fluid512+image_num+".jpg")
image1024 = Image.open(fluid1024+image_num+".jpg")
out = out_image + image_num + ".jpg"
blank_image.paste(image64, (0,0)).paste(fluid128, (400,0)).paste(fluid512, (0,300)).paste(fluid1024, (400,300)).save(out)
Not sure why it's not working. I'm getting the error:
Traceback (most recent call last):
File "C:\Users\Casey\Desktop\Image_composite.py", line 24, in <module>
blank_image.paste(image64, (0,0)).paste(fluid128, (400,0)).paste(fluid512, (
ste(fluid1024, (400,300)).save(out)
AttributeError: 'NoneType' object has no attribute 'paste'
shell returned 1
Any help would be awesome. Thanks!
The only problem there is that "paste" does not return an image object - it rather modifies the "blank" image inplace.
So, when the second paste is called (the one that uses the fuild128 image), it tries to be applied on "None" - which is the return value of the first image.
If that is the only problem you are having, just make one paste call per line, like this:
blank_image.paste(image64, (0,0))
blank_image.paste(fluid128, (400,0))
blank_image.paste(fluid512, (0,300))
blank_image.paste(fluid1024, (400,300))
blank_image.save(out)
Although it looks likely you'd need to scale each image so that their format match as well.
And your code for the "image_num" variable is unecessary. Python is really good with strings - just do something like this:
image64 = Image.open(fluid64 + "%02d.jpg" % pic)
You may want to be using something along the lines of :
blank_image = Image.new("RGB", (800, 600))
This will create a new area in memory in which you can generate your image. You should then be able to paste you images into that.
Then you'll need to save it out again later on with:
blank_image.save("blank.jpg")
Read the error message:
AttributeError: 'NoneType' object has no attribute 'paste'
This means you tried to call .paste on something that was of type NoneType, i.e. on the None object.
Image.paste returns None. You can't "chain" together calls like that except when the functions are specifically designed to support it, and Image.paste is not. (Support for this sort of thing is accomplished by having the function return self. You get an error that talks about NoneType because the function is written not to return anything, and everything in Python returns None by default if nothing else is returned explicitly.) This is considered Pythonic: methods either return a new value, or modify self and return None. Thus, so-called "fluent interfaces" are not used when the functions have side effects - Pythonistas consider that harmful. Returning None is a warning that the function has side effects. :)
Just do four separate .paste calls.
Tiling figures in a 2-by-2 grid would be easy to achieve with the append_images function defined in this reply
https://stackoverflow.com/a/46623632/8738113
For example:
img1 = append_images([image64, image128], direction='horizontal')
img2 = append_images([image512, image1024], direction='horizontal')
final = append_images([img1, img2], direction='vertical')
final.save("Fluid_all/00.jpg")
Unlike PIL APIs copy, crop, resize or rotate which return an Image object, paste returns None which prevents chained method calls. Not so convenient API design.

Categories