0

Sorry if this is obvious... I am trying to build a graph function that if you choose the limit values, it takes those, otherwise it takes the axis limits.

This has led me to this problem. Consider the following minimal example:

xmin = 5
xmax = None
ymin = None
ymax = None

plt.plot([0,1], [0,1])
xming, xmaxg, yming, ymaxg = plt.axis()

plt.ylim((ymin, ymax))
plt.xlim((xmin, xmax))
plt.show()

I want to replace the limits xmin, xmax, ymin and ymax with their corresponding xming etc if they are None. I can do this one at a time like this:

xmin = xming if xmin == None else xmin
xmax = xmaxg if xmax == None else xmax
ymin = yming if ymin == None else ymin
ymax = ymaxg if ymax == None else ymax

But I was hoping I could do it with a for loop, given another situation where their might be lots more variables. The following does not work: (I'm pretty sure I understand why - limit is its own separate variable and not a representative of xmin etc.)

for limit, limitg in [(xmin, xming), (xmax, xmaxg), (ymin, yming), (ymax, ymaxg)]:
    if limit == None:
        limit = limitg.copy()
        print(limit, limitg)
        print(ymin, ymax)
print(xmin, ymax)

I'm also pretty sure it would be possible to put all of these variables into lists and iterate it like that, however I was hoping there might be a better way I am missing? (Although that might be the proper way of doing it...)

  • If you have a lot of these variables you may pack them into a dictionary instead which can be processed more easily. – Michael Butscher Oct 08 '20 at 14:07
  • You'd need to store the result in another structure. What structure you'd use though depends on how this data is going to be used. A dictionary of strings to ints may be appropriate. – Carcigenicate Oct 08 '20 at 14:07
  • @MichaelButscher @Carcigenicate hmmm I thought that might have been the answer. Doing `limits = {'xmin': xmin, 'xmax': xmax, 'ymin': ymin, 'ymax': ymax}` and `limitsg = {'xmin': xming, 'xmax': xmaxg, 'ymin': yming, 'ymax': ymaxg}` and then using a for loop works... but I still don't see why you can't iterate through a bunch of variables and modify them as you go... – Joel Leeb-du Toit Oct 08 '20 at 14:16
  • For the reason you gave. Reassigning `limit` only changes `limit`; not the variable that originally held its data. To do what you'd want, you'd need to stick the data in a mutable container like a list (`pairs = [([xmin], xming), ([xmax], pxmaxg)]`), then do `for limit, limitg in pairs:` then in the loop do something like `limit[0] = limitg if limit[0] is None else limit[0]`. Then `pairs` will hold the answer after. That's ugly though. You could also use a `dataclass` that holds the data, and mutate it in the loop. – Carcigenicate Oct 08 '20 at 14:20
  • It's the same reason why this doesn't affect `b`: `a = 1; b = a; a = 5`. Same scenario, just using a `for` loop. – Carcigenicate Oct 08 '20 at 14:22
  • Can you explain the difference (or point me in the right direction) in that case between that and in pandas: `a=pd.DataFrame({'a':1, 'b':2}, index=[0]); b=a; a.loc[0,'b'] = 3; b` where setting them means they both are the same object? – Joel Leeb-du Toit Oct 08 '20 at 14:29
  • 2
    `b=a` always means that `b` and `a` are the same object; regardless of what type the objects are. The difference is between mutating a mutable object (which you're doing in the pandas example), and reassigning an object (which I did in my example). – Carcigenicate Oct 08 '20 at 15:04
  • Ok, so essentially there are two types of objects: mutable objects and 'normal' objects. – Joel Leeb-du Toit Oct 08 '20 at 15:08
  • 1
    I wouldn't think about it like that, since it's the same behavior regardless of whether an object is mutable or not. The only difference is you don't have the option of mutating an immutable object like an `int`. The key is the difference between changing the internal state of an object (using something like a method call, or reassigning an internal attribute; `a.b = 5`), and changing what object a name is associated with (using `=`; `a = 5`). – Carcigenicate Oct 08 '20 at 15:13
  • 1
    Part of the confusion here is probably the syntax of `a.loc[0, 'b'] = 3`. That actually "desugars" to `a.__setitem__((0, 'b'), 3)` behind the scenes, so `a.loc[0,'b'] = 3` is a method call that changes the internal state, **not** reassignment (despite what it looks like). – Carcigenicate Oct 08 '20 at 15:13
  • 1
    [Here actually](https://stackoverflow.com/questions/59699482/x-y-lists-vs-numbers), I go into more detail. – Carcigenicate Oct 08 '20 at 15:21

0 Answers0