0

I would like to pass optional arguments to a matplotlib script running from the command line.

I have the following:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('Agg')

import pandas as pd
import argparse

parser = argparse.ArgumentParser(description="Plot x,y data in python")
parser.add_argument('-xF',"--x", type=str, metavar='', required=True, help="x-Data")
parser.add_argument('-yF', "--y", type=str, metavar='', required=True, help="y-Data")
parser.add_argument('-o', "--options", nargs="+", default=[], help="Options for plotting")
args = parser.parse_args()

def plot(x, y, xlabel, ylabel, name, legend=None, otherArgs=None):

    xData = pd.read_csv(x) 
    yData = pd.read_csv(y)     

    plt.figure()
    plt.plot(xData, yData, label=legend, *(otherArgs), zorder=1)   
    plt.tight_layout()
    plt.savefig("tst.tiff")

if __name__ == '__main__':
    plot(args.x, args.y, args.options)

However, currently I am not able to do so. Is there any way to pass under the optional arguments other parameters to the plot functions? Set colors, markers, etc.. ?

Best Regards

mysticSnake
  • 167
  • 7
  • This [related question](https://stackoverflow.com/questions/58904900/passing-some-arguments-through-from-the-commadn-line-directly-to-matplotlib) contains a more well-formed version of what you might be trying to achieve. – metatoaster Sep 30 '22 at 09:52
  • Hi, does it contain an answer? I was not able to identify how to pass arguments from the command line to the plot funtion – mysticSnake Sep 30 '22 at 10:10
  • This [thread](https://stackoverflow.com/questions/15206010/how-to-pass-on-argparse-argument-to-function-as-kwargs) points out a generic way to pass arguments from `parse_args()` into a function using keyword arguments. Just adapt that as the solution. This [thread](https://stackoverflow.com/questions/54712264/use-argparse-to-send-arguments-to-function-within-python-script) uses explicit arguments. – metatoaster Sep 30 '22 at 10:19
  • you could show how you run it with optional arguments. Do you do `var1=val1 var2=val2` or with `,` like `var1=val1,var2=val2`? It may need simple split to convert to list with pairs `("var1", "val1")` and create dict `{"var1": "val1"}` which should work with `**` like `**{"var1": "val1"})` – furas Sep 30 '22 at 10:55
  • `argparse` is best for defined keys, as in the first suggestion. Generic key/value pairs require bypassing most of its useful features. – hpaulj Sep 30 '22 at 11:17
  • @furas I am passing optional parameters as: `-o marker=\'o\'` – mysticSnake Sep 30 '22 at 11:21
  • BTW: yoi can use without `'` - `-o marker=o` – furas Sep 30 '22 at 11:24

1 Answers1

2

If you will run as

-o color=red marker=o

then you will get list

["color=red", "marker=o"]

and you can use split("=") and dict()

args.options = dict(x.split('=') for x in args.options)

to get it as dictionary

{"color":"red", "marker":"o"}

And then you can use ** to put dictionary

plt.plot(..., **otherArgs)   

and it will accept it as correct parameters.


Minimal working code:

For test I put argumenst directly in sys.argv - so I can run it without writing parameters in console.

EDIT: it needs dictionary default={} instead of default=[]

import numpy as np
import matplotlib.pyplot as plt
import matplotlib
#matplotlib.use('Agg')

import pandas as pd
import argparse

# --- functions ---

def plot(x, y, xlabel='X', ylabel='Y', name='Name', legend=None, otherArgs=None):

    xData = [1,2,3]
    yData = [3,1,1]

    plt.figure()
    plt.plot(xData, yData, label=legend, **otherArgs, zorder=1)   
    plt.tight_layout()
    #plt.savefig("tst.tiff")
    plt.show()

# --- main ---

if __name__ == '__main__':
    
    import sys
    sys.argv += ['--x', '1', '--y', '2', '-o', 'color=red', 'marker=o']

    parser = argparse.ArgumentParser(description="Plot x,y data in python")
    parser.add_argument('-xF',"--x", type=str, metavar='', required=True, help="x-Data")
    parser.add_argument('-yF', "--y", type=str, metavar='', required=True, help="y-Data")
    parser.add_argument('-o', "--options", nargs="+", default={}, help="Options for plotting")   # `default={}` instead of `default=[]`
    args = parser.parse_args()

    print('[args.options] before:', args.options)
    
    args.options = dict(x.split('=') for x in args.options)

    print('[args.options] after :', args.options)
    
    plot(args.x, args.y, otherArgs=args.options)

Console:

[args.options] before: ['color=green', 'marker=o']
[args.options] after : {'color': 'green', 'marker': 'o'}

EDIT:

I found also method to create own class based on argparse.Action and later assign it to action in add_param(..., action=...)

class keyvalue(argparse.Action):
    
    def __call__(self, parser, namespace, values, option_string):
        #print(parser)
        #print(values)
        #print(option_string)
        print('[namespace] before:', namespace)
        
        data = dict()
        
        for value in values:
            key, val = value.split('=')
            data[key] = val
            
        setattr(namespace, self.dest, data)
        
        print('[namespace] after :', namespace)
parser.add_argument('-o', "--options", nargs="+", default={},  action=keyvalue)

Full working code

import argparse
import matplotlib.pyplot as plt
#matplotlib.use('Agg')
#import pandas as pd

# --- functions ---

def plot(x, y, xlabel='X', ylabel='Y', name='Name', legend=None, otherArgs=None):

    xData = [1,2,3]
    yData = [3,1,1]

    plt.figure()
    plt.plot(xData, yData, label=legend, **otherArgs, zorder=1)   
    plt.tight_layout()
    #plt.savefig("tst.tiff")
    plt.show()

class keyvalue(argparse.Action):
    
    def __call__(self, parser, namespace, values, option_string):
        #print(parser)
        #print(values)
        #print(option_string)
        print('[namespace] before:', namespace)
        
        data = dict()
        
        for value in values:
            key, val = value.split('=')
            data[key] = val
            
        setattr(namespace, self.dest, data)
        
        print('[namespace] after :', namespace)

# --- main ---
        
if __name__ == '__main__':
    
    import sys
    sys.argv += ['--x', '1', '--y', '2', '-o', 'color=green', 'marker=o']

    parser = argparse.ArgumentParser(description="Plot x,y data in python")
    parser.add_argument('-xF',"--x", type=str, metavar='', required=True, help="x-Data")
    parser.add_argument('-yF', "--y", type=str, metavar='', required=True, help="y-Data")
    parser.add_argument('-o', "--options", nargs="+", default={}, help="Options for plotting", action=keyvalue)
    args = parser.parse_args()

    print('[args.options] before:', args.options)
    
    plot(args.x, args.y, otherArgs=args.options)

Source:

furas
  • 134,197
  • 12
  • 106
  • 148