I have a script which accepts, on the command line, arguments to create a matplotlib.patches.Rectangle object.
Typical arguments that could be passed to the Rectangle constructor might be something like (in Python, without argument parsing):
patches.Rectangle(
xy=(15000,0),
width=9.4,
height=4,
color='peachpuff'
)
The user can encode this on the command line like so:
--patches '[{ "x" : 15000,"y" : 0,"width" : 9.4,"height" : 4,"color" : "peachpuff"}]'
This json array is loaded with json.loads. Note that most of the arguments can just be passed directly through to the Rectangle constructor, but the xy tuple causes a problem: json.loads will never generate a tuple type, so you can't create a tuple this way.
To work around it, I have the user pass separate x and y mappings, and then combine them like this:
p.add_argument('--patches', help='A JSON array of patches.Rectangle object arguments to patch onto the chart',
type=json.loads)
# stuff
# put some patches on
if args.patches:
def from_json(json):
ret = dict(json)
del ret['x']
del ret['y']
ret['xy'] = (json['x'], json['y'])
return ret
for pjson in args.patches:
p = from_json(pjson)
ax.add_patch(patches.Rectangle(**p))
Half of that code (essentially all of from_json) is just dealing with the transformation of x and y args into the xy = (x, y) tuple.
Any more elegant/Pythonic way to deal with this?
It might involve cleaner handling of the json input, or perhaps passing something other than json on the command line (but it must have rough feature-parity with the current approach).
Your from_json function can effectively be used as a custom type for your --patches option.
def RectangleArgs(s):
d = json.loads(s)
d['xy'] = (d.pop('x'), d.pop('y'))
return d
...
parser.add_argument('--patches', action='append', type=RectangleArgs)
...
for patch in args.patches:
ax.add_patch(patches.Rectangle(**patch))
Aside from simply massaging the JSON read from the command line, you can do additional validation, raising argparse.ArgumentTypeError if you find anything that would cause a problem when you try to use the return value in a call to patches.Rectangle.
Your motivating assumption that you need a tuple for the xy argument to Rectangle is not correct: a 2-element list works just as well, so "xy" : "[1, 2]" will work fine.
Pointed out by Jeff in the comments.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With