如何解决matplotlib文档中的颜色循环器示例是隐秘的python 这是matplotlib文档中的部分:
有人会这么友善地向我解释这个示例的工作原理吗,摘自“持久周期”部分下的matplotlib documentation?
基本上,它们创建了颜色循环程序,我不确定它们是工厂功能还是迭代器,还是普通功能或对象。您可以通过某种方式使用iter(my_cycler)
来生成一个有限的生成器,并使用my_cycler()
来生成一个itertools.cycle生成器。这只是我的头绪。
所以我的问题是:为什么你可以做iter(my_cycler)
并给出有限的东西,为什么你可以做my_cycler()
并给出相同的东西却是无限的(循环)?
>>> from cycler import cycler
>>> cyl = cycler(color=['r','g','b'])
>>> type(cyl)
cycler.Cycler
>>> import cycler
>>> cycler.Cycler.__mro__
(cycler.Cycler,object)
>>> type(cyl())
itertools.cycle
>> type(iter(cyl))
generator
当我键入:
>>> next(cyl)
TypeError: 'Cycler' object is not an iterator
但是以某种方式可以在这里工作:
>>> for s in cyl:
... print(s)
{'color': 'r'}
{'color': 'g'}
{'color': 'b'}
另一个问题是defaultdict的奇怪应用。 styles = defaultdict(lambda : next(finite_cy_iter))
。我想我大致理解了这一点,但我想确定一下:每当密钥不在字典中时,就会调用(lambda : next(finite_cy_iter))()
或类似的东西。根据defaultdicts的文档,您必须为其提供一个函数,在这种情况下为function = (lambda : next(finite_cy_iter))
。因此,我猜每次每次都不在dict function
中的键被调用时,它实际上是一个伪装的迭代器,它为您提供循环器中的下一个dict,然后将其存储为该键的值。>
这是matplotlib文档中的部分:
持久周期 通过字典查找将给定标签与样式相关联并动态生成该映射可能很有用。使用defaultdict可以轻松实现这一点
In [40]: from cycler import cycler as cy
In [41]: from collections import defaultdict
In [42]: cyl = cy('c','rgb') + cy('lw',range(1,4))
要获得一组有限的样式
In [43]: finite_cy_iter = iter(cyl)
In [44]: dd_finite = defaultdict(lambda : next(finite_cy_iter))
or repeating
In [45]: loop_cy_iter = cyl()
In [46]: dd_loop = defaultdict(lambda : next(loop_cy_iter))
这在绘制同时具有分类和标签的复杂数据时会很有帮助
finite_cy_iter = iter(cyl)
styles = defaultdict(lambda : next(finite_cy_iter))
for group,label,data in DataSet:
ax.plot(data,label=label,**styles[group])
这将导致以相同的样式绘制具有相同组的每个数据。
解决方法
回答问题的第一部分,
所以我的问题是:为什么你可以做
iter(my_cycler)
并给出有限的东西,为什么你可以做my_cycler()
并给出相同的东西却是无限的(循环)?
cycler
类的行为是这样的,因为它是这样定义的,请看下面这个简单的示例,以了解我的意思……
In [13]: class callable_list(list):
...: def __call__(self):
...: from itertools import cycle
...: return cycle(self)
In [14]: l = callable_list((1,2))
In [15]: l
Out[15]: [1,2]
In [16]: it_l = iter(l) ; cy_l = l()
In [17]: for _ in range(3): print(next(it_l))
1
2
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-17-e4324d8268a6> in <module>
----> 1 for _ in range(3): print(next(it_l))
StopIteration:
In [18]: for _ in range(3): print(next(cy_l))
1
2
1
这种行为的“原因”是什么?
我们想在轴中放置任意数量的Artist,并且希望能够使用不同的属性(不仅仅是颜色)来区分它们,从而对其进行唯一标识。
默认情况是调用Cycler对象,并使用返回的无限循环,允许进行一定程度的重复,但不会引发StopIteration
异常。
在OP引用的示例中显示的另一种方法是在Cycler对象上使用iter
,这样可以避免重复,但是编码人员必须预见到StopIteration
的可能性
附录寻址an OP's comment
当我对Cycler对象执行
cyl[1]
时。我得到:ValueError: Can only use slices with Cycler.__getitem__
是什么意思?
这意味着cycler
模块的编码人员决定了只能通过切片来寻址Cycler对象……
cyl[1:2]
有用,但是奇怪的是,它返回了两个元素而不是一个,cyl[1:1]
给出了一个元素
这不是我看到的…定义两个Cycler及其外部产品
In [1]: from cycler import cycler
...: c,w = cycler(c=['r','g','b']),cycler(lw=range(1,5))
...: cw = c*w
...: print(c,w,cw,sep='\n')
cycler('c',['r','b'])
cycler('lw',[1,2,3,4])
(cycler('c','b']) * cycler('lw',4]))
并从第一个[1:2]
循环开始,对我来说它会返回一个单一值
In [2]: c[1:2]
Out[2]: cycler('c',['g'])
,然后是[1:1]
,再次是单个值,它是一个空的Cycler
In [3]: c[1:1] # empty cycler
Out[3]: cycler('c',[])
请注意,这类似于切片列表,在任何情况下,表达式的值都是单个对象,列表,可能是空列表……没什么新意。
最后,让我们看看切片外部产品时会发生什么,但首先让我们了解其中的内部情况
In [5]: for i,d in enumerate(cw): print(i,d)
0 {'c': 'r','lw': 1}
1 {'c': 'r','lw': 2}
2 {'c': 'r','lw': 3}
3 {'c': 'r','lw': 4}
4 {'c': 'g','lw': 1}
5 {'c': 'g','lw': 2}
6 {'c': 'g','lw': 3}
7 {'c': 'g','lw': 4}
8 {'c': 'b','lw': 1}
9 {'c': 'b','lw': 2}
10 {'c': 'b','lw': 3}
11 {'c': 'b','lw': 4}
现在我们通过切片来解决
In [6]: cw[3:9]
Out[6]: (cycler('c','b']) + cycler('lw',[4,1,4,1]))
结果是一个循环仪,这是两个循环仪的内积,在展开时对应于上面枚举打印输出的3÷8位置。
最后,让我们使用cw
来寻址[3:3]
,即一个空片(破坏者,什么都不会发生!)
In [7]: cw[3:3]
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-7-1bf3cb52c570> in <module>
----> 1 cw[3:3]
~/lib/miniconda3/lib/python3.7/site-packages/cycler.py in __getitem__(self,key)
219 trans = self.by_key()
220 return reduce(add,(_cycler(k,v[key])
--> 221 for k,v in six.iteritems(trans)))
222 else:
223 raise ValueError("Can only use slices with Cycler.__getitem__")
~/lib/miniconda3/lib/python3.7/site-packages/cycler.py in __add__(self,other)
241 raise ValueError("Can only add equal length cycles,"
242 "not {0} and {1}".format(len(self),len(other)))
--> 243 return Cycler(self,other,zip)
244
245 def __mul__(self,other):
~/lib/miniconda3/lib/python3.7/site-packages/cycler.py in __init__(self,left,right,op)
116 """
117 if isinstance(left,Cycler):
--> 118 self._left = Cycler(left._left,left._right,left._op)
119 elif left is not None:
120 # Need to copy the dictionary or else that will be a residual
~/lib/miniconda3/lib/python3.7/site-packages/cycler.py in __init__(self,op)
133 self._right = None
134
--> 135 self._keys = _process_keys(self._left,self._right)
136 self._op = op
137
~/lib/miniconda3/lib/python3.7/site-packages/cycler.py in _process_keys(left,right)
66 The keys in the composition of the two cyclers
67 """
---> 68 l_peek = next(iter(left)) if left is not None else {}
69 r_peek = next(iter(right)) if right is not None else {}
70 l_key = set(l_peek.keys())
StopIteration:
In [8]:
在我的拙见中,最后一个功能非常像一个错误……
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。