0

Let's say I want to plot different class objects attribute from a function.

So far I have this:

...

import matplotlib.pyplot as plt

def plot2vars (deviceList, xVars, yVars, xLims, yLims, colormap=plt.cm.Spectral):
    x0 = xVars[0]
    x1 = xVars[1]
    y0 = yVars[0]
    y1 = yVars[1]
    fig, ax = plt.subplots(1,2)

    fig, ax = plt.subplots(1,2)
    for d in deviceList: #these 'd' are the class instances...
        if not d.discard:
                    ax[0].plot(d.x0, d.y0)
                    ax[0].set_xlim(xLims[0])
                    ax[0].set_ylim(yLims[0])

                    ax[1].plot(d.x1, d.y1)
                    ax[1].set_xlim(xLims[1])
                    ax[1].set_ylim(yLims[1])
    plt.show()

where deviceList is a list containing class instances with different attributes like, for example, u, z or T.

Now, when I call the function, I declare xVars, yVars, xLims, yLims as arrays of strings, which obviously doesn't work. But I don't know how to call these. And I don't even know how to look for this in the manuals...

plot2vars (
      deviceList, 
      xVars=['u', 'u'], yVars=['z', 'T'],  
      xLims=['', 'left=0.8'], yLims=['','bottom=0, top=0.8']
      )
6
  • You say it doesn't work. Could you please share the error you're getting? Also, please share an example of a call to this function (the values of all the parameters, including deviceList) Commented Feb 14, 2020 at 8:25
  • i wrote it in the question, deviceList is a list of Device class instances, which is a class with many attributes, like for example u, z, or T. Commented Feb 14, 2020 at 8:29
  • Your function takes xVars and yVars but never uses them. Is it okay? Commented Feb 14, 2020 at 8:33
  • You've edited the question... But still you take x0, y0 ... from xVars and yVars but you don't use them below. Commented Feb 14, 2020 at 8:35
  • That is my problem, when I call d.x0, python complains there is not x0 attribute of the class, and of course there isn't. I want to call d.u instead. And I want to be able to call different attributes everytime I call the function. That's why I need it to be a variable. But I don't know how to. Commented Feb 14, 2020 at 8:35

2 Answers 2

1

Maybe, if you want to take the attributes given as strings from your xVars and yVars, you should use getattr method like this:

d.x0 -> getattr(d, x0)

For example, if x0 = 'qwerty', getattr(d, x0) equals to d.qwerty.

So in your code you should use:

...
ax[0].plot(getattr(d, x0), getattr(d, y0))
...
ax[1].plot(getattr(d, x1), getattr(d, y1))
...

Documentation: https://docs.python.org/3/library/functions.html#getattr


As for xLims and yLims, I would define it as list of dictionaries like this:

xLims = [{}, {'left': 0.8}]
yLims = [{}, {'bottom': 0, 'top': 0.8}]

So this would allow me to use them through **kwargs approach:

...
ax[0].set_xlim(**xLims[0])
ax[0].set_ylim(**yLims[0])
...
ax[1].set_xlim(**xLims[1])
ax[1].set_ylim(**yLims[1])
...

The main idea is when you pass a dictionary to a function with ** the key-values pairs will be unpacked into key-value arguments.

Sign up to request clarification or add additional context in comments.

6 Comments

Yes! that was exactly what I was asking for. You say 'if I want to take them given as strings', is there any other way? I ask this because, when I call the xLims and yLims in the function, it doesn't recognise them as arrays but of corse as strings...
I am not sure about other ways. It is a standard way to access an attribute of an object by its name from a variable.
This works for the class attribute, but not for the xLims given to the set_xlim function... is there a proper way to do this too?
As far as I can see, it should work in the was you implemented. I can't see any error in it.
Same here, but this is the error I get: File "/usr/lib/python3/dist-packages/matplotlib/axes/_base.py", line 2769, in set_xlim left, right = left ValueError: too many values to unpack (expected 2)
|
1

So if I understand correctly, you are trying to access the attribute u of object d which would typically be called by writing d.u, but you want to be able to do that without defining ahead of time that the attribute in question is u.

d.x0 will look for an attribute of d which is called x0, which has nothing to do the x0 you have defined.

The closest thing to what you're trying to do in this case is the getattr function: getattr(d, x0) should give you what you want.

That being said, it's not great practice if you can avoid using it. I would recommend simply passing d.u as argument to plot2vars and edit plot2vars accordingly when possible.

3 Comments

The problem is I don't see how I would do that, since d is how I call each class instance inside a loop...
Sorry, I wasn't meaning to say that you specifically shouldn't use it in this case. I would say it's justified here. I was just giving a general warning. If you wanted to avoid using getattr in this case, you could always resort to a list comprehension: call plot2vars([d.u, d.z, d.u, d.T for d in deviceList], xLims, yLims) and in plot2vars you do for x0, y0, x1, y1 in first_argument: and use them directly. Honestly I would say it's better to have a little ugliness hidden away in a function than on display when calling it.
Oh yes, now I see what you meant! And yes, I agree the function call is more elegant this way.... I would like to accept both answers now :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.