Reputation: 153
I am setting up some code such that prior to plotting, the user can basically store all the plotting variables that they want to use in a dictionary, and these entries are stored for later use. The keys to the dictionary follow matplotlib.pyplot keyword syntax. An example of this dictionary would be something like this:
plot_info = {'title':'A neato title!',
'x':[1,2,3,4],
'y':[5,6,7,8],
'grid':'on'}
How do I bring this dictionary into a plot command to execute the keys as arguments and the parameters as inputs to those arguments?
Thus far, I have attempted:
import matplotlib.pyplot as plt
plot_info = {'title':'A neato title!',
'x':[1,2,3,4],
'y':[5,6,7,8],
'grid':'on'}
plt.plot(**plot_info)
Expecting this to do the trick. However, upon running the code, the figure pops up, but the figure is empty and everything is blank (runs without error but opens an empty figure).
I expect the output to display a plot whose title, x, and y values correspond to the dictionary values, and whose grid is on. Any idea why this plot would be blank?
For the record, I know that there are workarounds, and that this can be solved another way. However, I am curious as to why this is happening.
Upvotes: 1
Views: 2968
Reputation: 117
its can be done, just keep the x & y first.
Example:
plot_args = {'color':'black', 'marker':'.', 'linewidth':3, 'markersize':15, 'markerfacecolor':'white', 'markeredgecolor':'black', 'markeredgewidth':2} ax.plot(data[x],data[y],**plot_args)
Upvotes: 0
Reputation: 5247
The answer by Reedinationer is already a good start, I would perhaps suggest creating a class instead, like:
import matplotlib.pyplot as plt
class CustomPlot(object):
"""docstring for CustomPlot"""
def __init__(self, plot_dict):
super(CustomPlot, self).__init__()
self.plot_dict = plot_dict
## you should also include some kind of "validation" here
## which verifies the plot_dict key:value pairs
self.make_plot()
plt.show()
def make_plot(self):
fig,ax=plt.subplots()
for k,v in self.plot_dict.items():
if isinstance(v,dict):
print(k)
if k=='plot':
eval('plt.plot({x},{y})'.format(**v))
else:
print(v)
eval('plt.{0}("{1}")'.format(k,v) )
plot_info = {
'title':'A neato title!',
'plot':{
'x':[1,2,3,4],
'y':[5,6,7,8],
},
'grid':'True'
}
p=CustomPlot(plot_info)
Note: I am using eval()
here, which is not really a clean way to do this. It would require, that you properly validate the dictionary before you hand it over to eval()
, and really, really, test this. In your exemplary input, you e.g. suggested to call plt.plot()
with an argument title
, which is not following matplotlib.pyplot
keyword syntax, as you initially implied. This is a mistake that might also happen to your potential users, and you need to accommodate for this (i.e. make your own error handling). It might be better to create e.g. a dictionary of allowed function calls and expected types and then use this for validation.
Also, such a class would only be the start, you should next consider defining additional helper functions like def loads_data()
, def store_dict()
, and whatever else to have everything designed in a clean way.
Upvotes: 0
Reputation: 59701
No, you cannot do that with plt.plot
. The reason is that the signature for plt.plot
reads:
def plot(*args, scalex=True, scaley=True, data=None, **kwargs)
The first parameter, args
, which receives the data to plot, is a var-positional parameter. See the definition of parameter from the glossary:
parameter
A named entity in a function (or method) definition that specifies an argument (or in some cases, arguments) that the function can accept. There are five kinds of parameter:
positional-or-keyword: specifies an argument that can be passed either positionally or as a keyword argument. This is the default kind of parameter, for example foo and bar in the following:
def func(foo, bar=None): ...
positional-only: specifies an argument that can be supplied only by position. Python has no syntax for defining positional-only parameters. However, some built-in functions have positional-only parameters (e.g.
abs()
).keyword-only: specifies an argument that can be supplied only by keyword. Keyword-only parameters can be defined by including a single var-positional parameter or bare
*
in the parameter list of the function definition before them, for example kw_only1 and kw_only2 in the following:def func(arg, *, kw_only1, kw_only2): ...
var-positional: specifies that an arbitrary sequence of positional arguments can be provided (in addition to any positional arguments already accepted by other parameters). Such a parameter can be defined by prepending the parameter name with
*
, for example args in the following:def func(*args, **kwargs): ...
var-keyword: specifies that arbitrarily many keyword arguments can be provided (in addition to any keyword arguments already accepted by other parameters). Such a parameter can be defined by prepending the parameter name with
**
, for example kwargs in the example above.Parameters can specify both optional and required arguments, as well as default values for some optional arguments.
See also the argument glossary entry, the FAQ question on the difference between arguments and parameters, the
inspect.Parameter
class, the Function definitions section, and PEP 362.
You can only give arguments for positional-or-keyword or keyword-only parameters with a dictionary. The var-positional parameter args
is neither of those, so it cannot be filled anyhow.
By the way, about the definition above for positional-only parameters, a proper syntax for them has been accepted in PEP 570.
Upvotes: 1
Reputation: 5774
I'm don't think what you are asking is possible. plt.plot()
doesn't have grid
or title
arguments. Instead these arguments would be fed to plt
itself! You would need several lines of code for that (since they are different methods of a plt
object) like:
import matplotlib.pyplot as plt
plt.plot([1, 2, 3, 4],
[5, 6, 7, 8])
plt.grid(True)
plt.title('A neato title!')
plt.show()
To make a valid script. I'm not sure how your intended solution is easier/more beautiful than the built in functionality, since you still have to specify the arguments anyways. If you are trying to implement defaults, perhaps a function would do the trick (you could expand this example to unpack a dictionary too):
def plot_my_data(x=(1, 2, 3, 4),
y=(5, 6, 7, 8),
grid_flag=True,
title='A neato title!'):
plt.plot(x, y)
plt.grid(grid_flag)
plt.title(title)
Where now a simple
plot_my_data()
plt.show()
Yields your expected
Upvotes: 0