-1

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).

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
fales
  • 89
  • 7
  • 1
    What exactly are you trying to ask? If you want to write a function that wraps that method and applies `YInvert`, just... do that. Or write an `invertAllY` method, perhaps, that can take a list of (x, y) coords and return a list of (x, y') inversions. – jonrsharpe Mar 05 '17 at 10:22
  • I am asking how to write such a function `LineNew` that wraps the `YInvert`. Especially how can I manage that a function has as argument something in parentheses. Moreover, I do not know how to pass on the set of arguments such as `stroke` and `fill`. – fales Mar 05 '17 at 10:39
  • Sounds like you want to patch a lot of functions for particular parameters. Do you want a general solution? – Peter Wood Mar 05 '17 at 10:41
  • See also [flip svg coordinate system](http://stackoverflow.com/questions/3846015/flip-svg-coordinate-system) – Peter Wood Mar 05 '17 at 10:41
  • *"something in parentheses"* is just a `tuple`. The *"set of arguments"* you mention are *keyword* arguments. How to write something is rather broad for an SO question. – jonrsharpe Mar 05 '17 at 10:41

1 Answers1

2

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)
Paul Panzer
  • 51,835
  • 3
  • 54
  • 99