用于重叠透明区域的自定义图例在 python pandas 数据帧中为stacked=false 具有精确的颜色? [英] Custom legend for overlapping transparent areas with exact colors in a python pandas dataframe for stacked=false?
问题描述
使用(我使用了稍微不同的alpha计算),我得到的是这样的:
为了更容易地比较图例项与重叠圆圈的混合颜色,我将图例项用 Photoshop 处理到图中(圆圈边缘的小方块).
将matplotlib.pyplot导入为plt从matplotlib.lines导入Line2Dplt.figure()# cf = 前景色,cb = 背景色def mix_colors(cf,cb):a = cb [-1] + cf [-1]-cb [-1] * cf [-1]#固定的alpha计算r = (cf[0] * cf[-1] + cb[0] * cb[-1] * (1 - cf[-1]))/ag = (cf[1] * cf[-1] + cb[1] * cb[-1] * (1 - cf[-1]))/ab =(cf [2] * cf [-1] + cb [2] * cb [-1] *(1-cf [-1]))/a返回[r,g,b,a]c1 = [1.0,0.1,0.1,0.5]c2 = [0.3,0.2,0.7,0.5]c3 = [0.5,0.8,0.5,0.5]c12 = mix_colors(c2,c1)#在c1上混合c2c13 = mix_colors(c3, c1) # 在 c1 上混合 c3c123 = mix_colors(c3, c12) # 在 c12 上混合 c3circle1 = plt.Circle((3,3),radius = 3,fc = c1,edgecolor = None)circle2 = plt.Circle((3,7),radius = 3,fc = c2,edgecolor = None)circle3 = plt.Circle((6,5),radius = 3,fc = c3,edgecolor = None)圆圈 = [圆圈 1,圆圈 2,圆圈 3]对于圈子中的牧师:plt.gca().add_patch(cle)plt.axis('scaled')plt.xlim(0,10)circ1 = Line2D([0], [0], linestyle='none', marker='s',标记大小=10,标记面颜色=c1)circ2 = Line2D([0], [0], linestyle='none', marker='s',标记大小=10,标记面颜色=c2)circ3 = Line2D([0],[0],linestyle ='none',marker ='s',markersize = 10,markerfacecolor = c3)circ4 = Line2D([0],[0],linestyle ='none',marker ='s',标记大小=10,标记面颜色=c12)circ5 = Line2D([0],[0],linestyle ='none',marker ='s',markersize = 10,markerfacecolor = c13)circ6 = Line2D([0],[0],linestyle ='none',marker ='s',标记大小=10,标记面颜色=c123)plt.legend((circ1,circ2,circ3,circ4,circ5,circ6),('A','B','C','AB','AC','ABC'),numpoints = 1,loc ='最好的')
When producing an unstacked area plot with pandas dataframe.plot, one gets more colored surfaces than the number of legend entries.
Consider:
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randn(11, 3)+3, columns=['A', 'B', 'C'])
with
>>> print df
giving e.g.:
A B C
0 1.908785 2.516292 4.139940
1 2.566306 3.275534 3.889655
2 2.083525 2.554483 3.565328
3 1.406931 2.021886 2.956590
4 3.293099 3.672927 3.203007
5 3.542735 1.301354 3.259613
6 1.331992 4.882820 2.165666
7 2.670735 3.763886 3.290484
8 4.211895 0.923923 3.415861
9 3.664398 2.009058 2.436214
10 2.707552 3.149282 1.629846
and
df.plot(kind='area', stacked=False)
producing:
With three data series, or columns in the dataframe, there are seven differently colored surfaces: With A,B,C as the basis, there are the pairs AB, AC, BC, and the overlap of all: ABC.
Trying to visualize this in the pyplot with overlapping circles as follows:
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
plt.figure()
circle1 = plt.Circle((3, 3), radius=3, fc='r', alpha=0.5, edgecolor=None)
circle2 = plt.Circle((3, 7), radius=3, fc='g', alpha=0.5, edgecolor=None)
circle3 = plt.Circle((6, 5), radius=3, fc='b', alpha=0.5, edgecolor=None)
circles = [circle1, circle2, circle3]
for cle in circles:
plt.gca().add_patch(cle)
plt.axis('scaled')
plt.xlim(0, 10)
Now, I learned how to make a custom legend with specific colors in pyplot with line2D objects as follows:
circ1 = Line2D([0], [0], linestyle='none', marker='s', alpha=0.5,
markersize=10, markerfacecolor='r')
circ2 = Line2D([0], [0], linestyle='none', marker='s', alpha=0.5,
markersize=10, markerfacecolor='g')
circ3 = Line2D([0], [0], linestyle='none', marker='s', alpha=0.5,
markersize=10, markerfacecolor="blue")
plt.legend((circ1, circ2, circ3), ('A', 'B', 'C'), numpoints=1, loc='best')
yielding the following output:
But how does one access the exact colors for the overlapping surfaces from the original pandas plot of unstacked areas, providing a means to create a legend with seven entries?
Please also note that the colors here are slightly different. While on the one hand in pandas the additive coloring produces darker shades of red (although this seems to vary with the number of data series/columns of the dataframe plotted), on the other hand pyplot produces darker shades of blue.
You could manully calculate the blended color. For example, with the algorithm I found here (I used a slightly different alpha calculation), I get something like this:
For an easier comparison of the legend items with the blended color of the overlapping circles, I Photoshopped the legend items into the figure (small squares at the edges of the circles).
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
plt.figure()
# cf = foreground color, cb = background color
def mix_colors(cf, cb):
a = cb[-1] + cf[-1] - cb[-1] * cf[-1] # fixed alpha calculation
r = (cf[0] * cf[-1] + cb[0] * cb[-1] * (1 - cf[-1])) / a
g = (cf[1] * cf[-1] + cb[1] * cb[-1] * (1 - cf[-1])) / a
b = (cf[2] * cf[-1] + cb[2] * cb[-1] * (1 - cf[-1])) / a
return [r,g,b,a]
c1 = [1.0, 0.1, 0.1, 0.5]
c2 = [0.3, 0.2, 0.7, 0.5]
c3 = [0.5, 0.8, 0.5, 0.5]
c12 = mix_colors(c2, c1) # mix c2 over c1
c13 = mix_colors(c3, c1) # mix c3 over c1
c123 = mix_colors(c3, c12) # mix c3 over c12
circle1 = plt.Circle((3, 3), radius=3, fc=c1, edgecolor=None)
circle2 = plt.Circle((3, 7), radius=3, fc=c2, edgecolor=None)
circle3 = plt.Circle((6, 5), radius=3, fc=c3, edgecolor=None)
circles = [circle1, circle2, circle3]
for cle in circles:
plt.gca().add_patch(cle)
plt.axis('scaled')
plt.xlim(0, 10)
circ1 = Line2D([0], [0], linestyle='none', marker='s',
markersize=10, markerfacecolor=c1)
circ2 = Line2D([0], [0], linestyle='none', marker='s',
markersize=10, markerfacecolor=c2)
circ3 = Line2D([0], [0], linestyle='none', marker='s',
markersize=10, markerfacecolor=c3)
circ4 = Line2D([0], [0], linestyle='none', marker='s',
markersize=10, markerfacecolor=c12)
circ5 = Line2D([0], [0], linestyle='none', marker='s',
markersize=10, markerfacecolor=c13)
circ6 = Line2D([0], [0], linestyle='none', marker='s',
markersize=10, markerfacecolor=c123)
plt.legend((circ1, circ2, circ3, circ4, circ5, circ6), ('A', 'B', 'C', 'AB', 'AC', 'ABC'), numpoints=1, loc='best')
这篇关于用于重叠透明区域的自定义图例在 python pandas 数据帧中为stacked=false 具有精确的颜色?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!