I use the svgwrite
library in Python and, because svg has y-axis going downwards while I find it more convenient to have it upwards, I defined a function YInvert
which does the trick for me. However, I have to use this function every time I use a function from svgwrite
, e.g.:
dwg.line((xI,YInvert(yI)), (xII,YInvert(yII)), stroke='blue', stroke_width=0.1)
However, this is uncomfortable. How could I redefine the function dwg.line
(or define some new function LineNew
) to automatically include the YInvert
? I want the argument to be in the same form, by this I mean I could use:
dwg.line((xI,yI), (xII,yII), stroke='blue', stroke_width=0.1)
or
LineNew((xI,yI), (xII,yII), stroke='blue', stroke_width=0.1)
I also use for example
dwg.circle(center=(10,YInvert(10)), r=0.2, fill='black')
so I am looking for something that would apply for a wide variety of arguments, just adding the YInvert
function at the right place(s).
Here is a decorator approach. The coordinate detection is not very smart, you'd probably want to hone that a bit:
from functools import wraps
def YInvert(Y): # just for demo
return -Y
def invert_axis(f):
@wraps(f)
def g(*args, **kwds):
args = list(args)
for j, a in enumerate(args):
if isinstance(a, tuple) and len(a) == 2:
try:
args[j] = (a[0], YInvert(a[1]))
except:
pass
for k, v in kwds.items():
if isinstance(v, tuple) and len(v) == 2:
try:
kwds[k] = (v[0], YInvert(v[1]))
except:
pass
return f(*args, **kwds)
return g
Demo:
@invert_axis
def f(a, b, c, d=3):
print(a, b, c, d)
f((1, 2), 3, (4, 5), d=(1, 2))
# (1, -2) 3 (4, -5) (1, -2)
This can also be applied to functions already defined like library functions:
f2 = invert_axis(f2)