I have been following tutorials on Digital Tutors for scripting, and in some videos the tutor makes a tool that adds gamma correct nodes to any selected shader using MEL, for my learning I thought I'd try to rewrite the code in Python but I am struggling to convert a piece of MEL code to Python.
The code I have so far is this:
import maya.cmds as cmds
selMat = cmds.ls(sl=True, mat=True)
if len(selMat) < 1:
cmds.warning('Select at least one Maya or Mental Ray Shader to apply gamma correct node to.')
for mat in selMat:
gammaCorrect_util = cmds.shadingNode('gammaCorrect', asUtility=True)
rename_gamma = cmds.rename(gammaCorrect_util, ('gamma_' + mat))
cmds.setAttr((rename_gamma + '.gammaX'), 0.45)
cmds.setAttr((rename_gamma + '.gammaY'), 0.45)
cmds.setAttr((rename_gamma + '.gammaZ'), 0.45)
if cmds.attributeQuery('color', mat): # << error here
connection_to_mat = cmds.listConnections(mat + '.color')
if len(connection_to_mat) == 1:
cmds.connectAttr ((connection_to_mat + '.outColor'), (rename_gamma + '.value'), f=True)
cmds.connectAttr ((rename_gamma + '.outValue'), (mat + '.color'), f=True)
when I run this I get the following error:
Error: Too many objects or values.Traceback (most recent call last): File "", line 17, in TypeError: Too many objects or values.
The MEL code where I think the issue is is:
if(`attributeExists "color" $mat`){
string $connection_to_mat[] = `listConnections($mat + ".color")`;
if(size($connection_to_mat) == 1){
connectAttr -f ($connection_to_mat[0] + ".outColor") ($rename_gamma + ".value");
connectAttr -f ($rename_gamma + ".outValue") ($mat + ".color");
I'm not sure how to convert and use the "attributeQuery" command in python in place of "attributeExists" in MEL, The tutor also defines the preseeding varables "$connection_to_mat[]" but this doesnt work in Python.
attributeQuery only takes one unnamed argument, the attribute. You have to specify the node with the node flag, same as the MEL version.
cmds.attributeQuery('color', n=mat, exists=True)
listConnections returns an array. You'll need to check there are some connections and if so use the first connection: connection_to_mat[0]
Incidentally, if you specify that you want the plug, then you won't have to concatenate the string with ".outColor"
cmds.listConnections(mat + '.color', p=True)
// result ["someNode.outColor"]
This is better because there's a possibility the incoming attribute is named differently, or is a child of a compound. Example: someNode.colors.outColor1. Whatever it is, you can just feed it to connectAttr.
Related
Given the following rectangles in Inkscape .svg format, I want to find the absolute coordinates, of all four corners, of the second rectangle (in Python). Without writing my own matrix-transformations, or anything really complex.
You'd think there would be a library for this sort of thing. In fact, I found Python SVG Extensions - simpletransform.py, that sounds like it would to it. But it's in the deprecated folder of my installed Inkscape, with this notice:
This directory IS NOT a module path, to denote this we are using a dash in the name and there is no 'init.py'
And is not really importable, as-is. I might just try copy/pasting the code, but I don't have a warm-fuzzy that it will work at all.
And there seem to be a lot of questions/articles about "removing transforms", but they all seem to be related to "accidentally" added transforms.
Just to make things more complex - it looks like the x/y coordinates of the second rectangle - refer to the corner of the bounding-box, not the actual rectangle corner. I still don't really understand Inkscape's funky coordinate-system - it seems like the GUI is backwards from the actual objects. When I mouse-over the rectangle, its coordinates don't match what I expect to see.
Oh, and all units are set to pixels (I think).
This is a very interesting question. Inkscape transform (or transform in computer graphics) can be quite complicated. This webpage has some good information on how transform works in Inkscape extensions.
https://inkscapetutorial.org/transforms.html
For your specific example, the direct answer is that Inkscape system extension (after version 1.0) has a Transform class (in transforms.py module), which has a method apply_to_point that can calculate the absolute coordinates.
More specifically, the following extension (inx and py files, under menu item Extension -> Custom -> Transform Element 2) draws the rectangle in your example with the Rectangle class, calculates the 4 corners with apply_to_point method, draws a path with those 4 points. The result two rectangles overlap each other, so we know the calculation is correct.
Code in transform2.inx file
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Transform Element 2</name>
<id>user.transform2</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="Custom"/>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">transform2.py</command>
</script>
</inkscape-extension>
Code in transform2.py file
import inkex
from inkex import Rectangle, Transform
from inkex import Vector2d
class NewElement(inkex.GenerateExtension):
container_label = 'transform'
container_layer = True
def generate(self):
self.style = {'fill' : 'none', 'stroke' : '#000000',
'stroke-width' : self.svg.unittouu('2px')}
self.style_red = {'fill' : 'none', 'stroke' : '#FF0000',
'stroke-width' : self.svg.unittouu('.5px')}
rects = self.add_rect()
for r in rects:
yield r
def add_rect(self):
rect = Rectangle.new(15, 5, 20, 5)
rect.style = self.style
tr = Transform('rotate(45)')
rect.transform = tr
el = rect
pt_top_left = tr.apply_to_point(Vector2d(el.left, el.top))
pt_top_right = tr.apply_to_point(Vector2d(el.right, el.top))
pt_right_bottom = tr.apply_to_point(Vector2d(el.right, el.bottom))
pt_left_bottom = tr.apply_to_point(Vector2d(el.left, el.bottom))
path = inkex.PathElement()
path.update(**{
'style': self.style_red,
'inkscape:label': 'redline',
'd': 'M ' + str(pt_top_left.x) + ',' + str(pt_top_left.y) +
' L ' + str(pt_top_right.x) + ',' + str(pt_top_right.y) +
' L ' + str(pt_right_bottom.x) + ',' + str(pt_right_bottom.y) +
' L ' + str(pt_left_bottom.x) + ',' + str(pt_left_bottom.y) +
' z'})
return [rect, path]
if __name__ == '__main__':
NewElement().run()
Here is the result of the extension run:
Furthermore, the simpletransform.py documentation you referenced in your post is written for Inkscape System Extension before version 1.0. The code is written with Python 2.X version. Even though you can find a copy of the file that comes with Inkscape 0.92.X, you will need to spend time to understand the code and rewrite it to be Python 3 compatible, and then you can use it in your program. It is not really recommended for anyone to do that.
As for Inkscape extension units, this webpage also has some good information on this topic.
https://inkscapetutorial.org/units-and-coordinate-systems.html
NOTE: Work constraints I must use python 2.7 (I know - eyeroll) and standard modules. I'm still learning python.
I have about 100 tiled 'area of interest' polygons in a geodatabase that need to be processed through my script. My script has been tested on individual tiles & works great. I need advice how to iterate this process so I don't have to run one at a time. (I don't want to iterate ALL 100 at once in case something fails - I just want to make a list or something to run about 10-15 at a time). I also need to add the tile name that I am processing to each feature class that I output.
So far I have tried using fnmatch.fnmatch which errors because it does not like a list. I changed syntax to parenthesis which did NOT error but did NOT print anything.
I figure once that naming piece is done, running the process in the for loop should work. Please help with advice what I am doing wrong or if there is a better way - thanks!
This is just a snippet of the full process:
tilename = 'T0104'
HIFLD_fc = os.path.join(work_dir, 'fc_clipped_lo' + tilename)
HIFLD_fc1 = os.path.join(work_dir, 'fc1_hifldstr_lo' + tilename)
HIFLD_fc2 = os.path.join(work_dir, 'fc2_non_ex_lo' + tilename)
HIFLD_fc3 = os.path.join(work_dir, 'fc3_no_wilder_lo' + tilename)
arcpy.env.workspace = (env_dir)
fcs = arcpy.ListFeatureClasses()
tile_list = ('AK1004', 'AK1005')
for tile in fcs:
filename, ext = os.path.splitext(tile)
if fnmatch.fnmatch(tile, tile_list):
print(tile)
arcpy.Clip_analysis(HIFLD_fc, bufferOut2, HIFLD_fc1, "")
print('HIFLD clipped for analysis')
arcpy.Clip_analysis(HIFLD_fc, env_mask, HIFLD_masked_rds, "")
print('HIFLD clipped by envelopes and excluded from analysis')
arcpy.Clip_analysis(HIFLD_masked_rds, wild_mask, HIFLD_excluded, "")
print('HIFLD clipped by wilderness mask and excluded from analysis')
arcpy.MakeFeatureLayer_management(HIFLD_fc1, 'hifld_lyr')
arcpy.SelectLayerByLocation_management('hifld_lyr', "COMPLETELY_WITHIN", bufferOut1, "", "NEW_SELECTION", "INVERT")
if arcpy.GetCount_management('hifld_lyr') > 0:
arcpy.CopyFeatures_management('hifld_lyr', HIFLD_fc2)
print('HIFLD split features deleted fc2')
else:
pass
I'm trying to make a python proram to find derivatives and integrals as well as showing how. I have so far found that there is an integral_steps function which returns the steps used, but I have not found an equivalent for differentiation.
Does anyone know if there is an equivalent?
If there isn't, do you have any ideas on how to find the steps needed to find a derivative?
Method 1 (manual)
Looking at the code, the Derivative class is where the top-level logic lives. That's only the top-level part. From there on, the computation requires computing derivatives of different nodes inside the expression tree.
The logic for each specific node of the expression tree lives in the _eval_derivative method corresponding to each particular node type.
This would allow you to add code to those _eval_derivative methods in order to trace the entire process and find all the steps.
Method 2 (using a tracer)
Python has multiple tracing packages. python-hunter written by #ionelmc is quite good actually and fits this use-case well.
Among many other features, it allows installing certain callbacks when a function starts executing, and another one when the function returns its value. In fact that's exactly what we need.
Here's an example that shows how to use this (I ran and tested this on Python 3.7.3, SymPy 1.7 and hunter 3.3.1) :
import hunter
import sys
from hunter import Q, When, Stop
hunter.trace(
Q(module_contains="sympy",function='_eval_derivative',kind_in=["call","return"],action=hunter.CallPrinter(repr_func=str))
)
from sympy import *
x = symbols('x')
f = 1/(x * sin(x)**2)
f.diff(x)
So this allows to pick which data structures we want to inspect, how we want to print them, and it allows us to see the intermediary steps of the differentiation process:
[...]7/site-packages/sympy/core/power.py:1267 call => _eval_derivative(self=sin(x)**(-2), s=x)
[...]7/site-packages/sympy/core/power.py:1267 call => _eval_derivative(self=<sympy.core.power.Pow object at 0x7f5925337150>, s=<sympy.core.symbol.Symbol object at 0x7f5925b6a2b0>)
[...]ite-packages/sympy/core/function.py:598 call => _eval_derivative(self=sin(x), s=x)
[...]ite-packages/sympy/core/function.py:598 call => _eval_derivative(self=<sympy.functions.elementary.trigonometric.sin object at 0x7f592589ee08>, s=<sympy.core.symbol.Symbol object at 0x7f5925b6a2b0>)
[...]ite-packages/sympy/core/function.py:612 return <= _eval_derivative: cos(x)
[...]ite-packages/sympy/core/function.py:612 return <= _eval_derivative: <sympy.functions.elementary.trigonometric.cos object at 0x7f592525fef8>
[...]7/site-packages/sympy/core/power.py:1271 return <= _eval_derivative: -2*cos(x)/sin(x)**3
[...]7/site-packages/sympy/core/power.py:1271 return <= _eval_derivative: <sympy.core.mul.Mul object at 0x7f5925259b48>
[...]7/site-packages/sympy/core/power.py:1267 call => _eval_derivative(self=1/x, s=x)
[...]7/site-packages/sympy/core/power.py:1267 call => _eval_derivative(self=<sympy.core.power.Pow object at 0x7f5925337200>, s=<sympy.core.symbol.Symbol object at 0x7f5925b6a2b0>)
[...]7/site-packages/sympy/core/power.py:1271 return <= _eval_derivative: -1/x**2
[...]7/site-packages/sympy/core/power.py:1271 return <= _eval_derivative: <sympy.core.mul.Mul object at 0x7f5925259f10>
If you want to also cover the diff function you can alter the code above and have function_in=['_eval_derivative','diff'] . In this way, you can look at not only the partial results, but also the call of the diff function and its return value.
Method 3 (using a tracer, building a call graph and visualizing it)
Using graphviz, latex and a tracer (again, python-hunter) you can actually see the call graph more clearly. It does take a bit of time to render all the formulas for each intermediary step, because pdflatex is being used (I'm sure there's faster renderers for latex though).
Each node's value is in the following format:
function_name
argument => return_value
There seem to be a few diff nodes that have the argument equal to the return value which I'm not sure how to explain at the moment.
The diagram could probably be more useful if it mentioned somehow where each rule was applied (I can't think of an easy way to do that).
Here's the code for this too:
import hunter
import sys
from hunter import Q, When, Stop, Action
from hunter.actions import ColorStreamAction
formula_ltx = r'''
\documentclass[border=2pt,varwidth]{letter}
\usepackage{amsmath}
\pagenumbering{gobble}
\begin{document}
\[ \texttt{TITLE} \]
\[ FORMULA \]
\end{document}
'''
# ==============
# == Tracing ===
# ==============
from sympy.printing.latex import LatexPrinter, print_latex, latex
global call_tree_root
# a node object to hold an observed function call
# with its argument, its return value and its function name
class Node(object):
def __init__(self, arg=None, retval=None, func_name=None):
self.arg = arg
self.retval = retval
self.arg_ascii = ""
self.retval_ascii = ""
self.func_name = func_name
self.uid = 0
self.children = []
# this is a hunter action where we build a call graph and populate it
# so we can later render it
#
# CGBAction (Call Graph Builder Action)
class CGBAction(ColorStreamAction):
def __init__(self, *args, **kwargs):
super(ColorStreamAction, self).__init__(*args, **kwargs)
# a custom call stack
self.tstack = []
global call_tree_root
call_tree_root = Node(arg="",func_name="root")
self.node_idx = 1
self.tstack.append(call_tree_root)
def __call__(self, event):
if event.kind in ['return','call']:
if event.kind == 'return':
print(str(event.arg))
if len(self.tstack) > 0:
top = self.tstack.pop()
top.retval = latex(event.arg)
top.retval_ascii = str(event.arg)
elif event.kind == 'call':
print(str(event.locals.get('self')))
new = Node()
new.uid = self.node_idx
new.arg = latex(event.locals.get('self'))
new.arg_ascii = str(event.locals.get('self'))
top = self.tstack[-1]
self.tstack.append(new)
top.children.append(new)
new.func_name = event.module + ":" + event.function
self.node_idx += 1
hunter.trace(
Q(module_contains="sympy",function_in=['_eval_derivative','diff'],kind_in=["call","return"],action=CGBAction)
)
from sympy import *
x = symbols('x')
f = 1 / (x * sin(x)**2)
#f = 1 / (x * 3)
#f = sin(exp(cos(x)*asin(x)))
f.diff(x)
# ============================
# == Call graph rendering ====
# ============================
import os
import re
OUT_DIR="formulas"
if not os.path.exists(OUT_DIR):
os.mkdir(OUT_DIR)
def write_formula(prefix,uid,formula,title):
TEX = uid + prefix + ".tex"
PDF = uid + prefix + ".pdf"
PNG = uid + prefix + ".png"
TEX_PATH = OUT_DIR + "/" + TEX
with open(TEX_PATH,"w") as f:
ll = formula_ltx
ll = ll.replace("FORMULA",formula)
ll = ll.replace("TITLE",title)
f.write(ll)
# compile formula
CMD = """
cd formulas ;
pdflatex {TEX} ;
convert -trim -density 300 {PDF} -quality 90 -colorspace RGB {PNG} ;
""".format(TEX=TEX,PDF=PDF,PNG=PNG)
os.system(CMD)
buf_nodes = ""
buf_edges = ""
def dfs_tree(x):
global buf_nodes, buf_edges
arg = ("" if x.arg is None else x.arg)
rv = ("" if x.retval is None else x.retval)
arg = arg.replace("\r","")
rv = rv.replace("\r","")
formula = arg + "\\Rightarrow " + rv
print(x.func_name + " -> " + x.arg_ascii + " -> " + x.retval_ascii)
x.func_name = x.func_name.replace("_","\\_")
write_formula("",str(x.uid),formula,x.func_name)
buf_nodes += """
{0} [image="{0}.png" label=""];
""".format(x.uid);
for y in x.children:
buf_edges += "{0} -> {1};\n".format(x.uid,y.uid);
dfs_tree(y)
dfs_tree(call_tree_root)
g = open(OUT_DIR + "/graph.dot", "w")
g.write("digraph g{")
g.write(buf_nodes)
g.write(buf_edges)
g.write("}\n")
g.close()
os.system("""cd formulas ; dot -Tpng graph.dot > graph.png ;""")
Mapping SymPy logic to differentiation rules
I think one remaining step is to map intermediary nodes from SymPy to differentiation rules. Here's some of the ones I was able to map:
Product rule maps to sympy.core.mul.Mul._eval_derivative
Chain rule maps to sympy.core.function.Function._eval_derivative
Sum rule maps to sympy.core.add.Add._eval_derivative
Derivative of a summation maps to sympy.concrete.summations.Sum._eval_derivative
n-th Derivative of a product via the General Leibniz rule maps to sympy.core.mul.Mul._eval_derivative_n_times
Generalized power rule maps to sympy.core.power.Pow._eval_derivative
I haven't seen a Fraction class in sympy.core so maybe the quotient rule is handled indirectly through a product rule, and a generalized power rule with exponent -1.
Running
In order to get this to run you'll need:
sudo apt-get install graphviz imagemagick texlive texlive-latex-base
And the file /etc/ImageMagick-6/policy.xml will have to be updated with the following line to allow conversion fron PDF->PNG:
<policy domain="coder" rights="read|write" pattern="PDF" />
There's another call graph library called jonga but it's a bit generic and doesn't allow to completely filter out unwanted calls.
My book requires me to Make another program using functions, the catch is that I need to make it a little bit more complex this time, so instead of going for a simple addition I try to solve a very simple physics problem with values given to me by the user, using two functions (velocity and acceleration).
Heres the aim of the program (sampledoc)
Create a program that reads and prints this txt document
Introduces the Program and the name of the script
Uses a function to solve a problem, make the function more complex
User gives distance (x) and time (t)
Program calculates velocity and acceleration
Creates a new txt document and writtes the results in it
Prints the results of the problem directly from the new document.
And heres the code:
from sys import argv
script, textf = argv; sampledoc = open(textf)
def velocity (x, t):
vel = (float(x)) / (float(t))
return float(vel)
def acceleration (v, t):
accel = (float(v)) / (float(t))
return float(accel)
print "Hello my name is TAR or as my creator called me %s" % script; print sampledoc.read(); sampledoc.close()
print "Results will be printed on a new text document, thanks for your preference"
x = float(raw_input("Please introduce the Distance")); t = float(raw_input("Please introduce the time:... "))
vel = velocity(x, t)
accel = acceleration (velocity, t)
results = 'ResultsP.txt'
new_file = open(results, 'w')
new_file.write(str(vel)); new_file.write(str(accel))
new_file.close()
new_file.open(results, 'r')
print new_file.read()
new_file.close()
I know there's something wrong here, somewhere, but my brain isn't working right now, I suppose it has something to do with either the way I am trying to solve this or the ''floats'' I used in the function since I am getting this error:
File "ex21Study.py", line 20, in <module>
accel = acceleration (velocity, t)
File "ex21Study.py", line 10, in acceleration
accel = (float(v)) / (float(t))
TypeError: float() argument must be a string or a number
I googled this and found some answers on other similar issues that said something about converting my results to float or str, however, I tried both and with no fruitful results.
You are passing in a function here:
accel = acceleration (velocity, t)
velocity is not a floating point value; it is a function object. You probably meant to use vel instead here, which you calculated on the preceding line:
vel = velocity(x, t)
accel = acceleration(vel, t)
I'm parsing multiple choice questions with multiple answers that look like this :
ParserElement.setDefaultWhitespaceChars(u""" \t""")
in_ = """1) first stem.
= option one one key
= option one two key
- option one three distractor
= option one four key
2) second stem ?
- option two one distractor
- option two two distractor
= option one three key
3) third stem.
- option three one key
= option three two distractor
"""
The equal sign represents a correct answer, the dash a distractor.
My grammar looks like this :
newline = Suppress(u"\n")
end_number = Suppress(oneOf(u') / ('))
end_stem = Suppress(oneOf(u"? .")) + newline
end_phrase = Optional(u'.').suppress() + newline
phrase = OneOrMore(Word(alphas)) + end_phrase
prefix = Word(u"-", max=1)('distractor') ^ Word(u"=", max=1)('key')
stem = Group(OneOrMore(Word(alphas))) + end_stem
number = Word(nums) + end_number
question = number + stem('stem') +
Group(OneOrMore(Group(prefix('prefix') + phrase('phrase'))))('options')
And when I'm parsing the results:
for match, start, end in question.scanString(in_):
for o in match.options:
try:
print('key', o.prefix.key)
except:
print('distractor', o.prefix.distractor)
I get :
AttributeError: 'unicode' object has no attribute 'distractor'
I'm pretty sure the result names are chainable. If so, what am I doing wrong ? I can easily work around this but it's unsatisfactory not knowing what I did wrong and what I misunderstood.
The problem is that o is actually the prefix -- when you call o.prefix, you're actually going one level deeper then you need to, and are retrieving the string the prefix maps to, not the ParseResults object.
You can see this by modifying the code so that it prints out the parse tree:
for match, start, end in question.scanString(in_):
for o in match.options:
print o.asXML()
try:
print('key', o.prefix.key)
except:
print('distractor', o.prefix.distractor)
The code will then print out:
<prefix>
<key>=</key>
<phrase>option</phrase>
<ITEM>one</ITEM>
<ITEM>one</ITEM>
<ITEM>key</ITEM>
</prefix>
Traceback (most recent call last):
File "so07.py", line 37, in <module>
print('distractor', o.prefix.distractor)
AttributeError: 'str' object has no attribute 'distractor'
The problem then becomes clear -- if o is the prefix, then it doesn't make sense to do o.prefix. Rather, you need to simply call o.key or o.distractor.
Also, it appears that if you try and call o.key where no key exists, then pyparsing will return an empty string rather than throwing an exception.
So, your fixed code should look like this:
for match, start, end in question.scanString(in_):
for o in match.options:
if o.key != '':
print('key', o.key)
else:
print('distractor', o.distractor)