椭圆的边缘颜色作为第三个变量的函数

Edgecolor of Ellipse as a function of a third variable

我希望椭圆的边缘颜色是第三个变量的函数。让我们假设第三个变量称为通量。如果变量 'flux' 的值很高,我希望椭圆的边缘颜色为深蓝色,如果值较低,我希望颜色为黄色。任何中间值都应该是这些颜色的混合。我希望此颜色渐变在具有最高值和最低值的绘图的 z 轴上可见。我尝试参考此 link Matplotlib scatterplot; colour as a function of a third variable 但这似乎不适用于我的情况。我正在从如下所示的文本文件中读取绘制椭圆所需的参数:

149.20562 2.29594 0.00418 0.00310 83.40 1.15569 

149.23158 1.99783 0.00437 0.00319 90.30 3.46331 

149.23296 2.45440 0.00349 0.00264 120.30 2.15457 

第五列是名为 'flux' 的列,必须根据该列绘制颜色渐变。

这是我尝试的一个例子。

import matplotlib.pyplot as plt
import numpy as np
import math
import astropy.io.ascii as asciitable
from matplotlib.patches import Ellipse
ax = plt.gca()
path="/users/xxxx/Desktop/"
plt.xlim([149,151.3])
plt.ylim([1,3.3])
fw=open(path + 'data_plot.txt', 'r')
data = asciitable.read(path+ "data_plot.txt") 
np.array(data)
for i in range(len(data)):
    ra,dec,maj,minor,ang,flux =data[i][0],data[i][1],data[i][2],data[i][3],data[i][4],data[i][5]
    ellipse = Ellipse(xy=(ra, dec), width=maj, height=minor, angle=ang, edgecolor=flux, lw=3, fc='None')
    ax.add_patch(ellipse) 


plt.xlabel('Right Ascention')
plt.ylabel('Declination')
plt.title('abc') 
plt.savefig(path+'abc.eps')

不出所料,这没有用。这是我的错误日志。

runfile('/users/vishnu/.spyder2-py3/radio_sources.py',   wdir='/users/vishnu/.spyder2-py3')


    Traceback (most recent call last):

  File "<ipython-input-695-a0011c0326f5>", line 1, in <module>
    runfile('/users/vishnu/.spyder2-py3/radio_sources.py', wdir='/users/vishnu/.spyder2-py3')

  File "/users/vishnu/anaconda3/lib/python3.5/site-packages/spyderlib/widgets/externalshell/sitecustomize.py", line 699, in runfile
    execfile(filename, namespace)

  File "/users/vishnu/anaconda3/lib/python3.5/site-packages/spyderlib/widgets/externalshell/sitecustomize.py", line 88, in execfile
    exec(compile(open(filename, 'rb').read(), filename, 'exec'), namespace)

  File "/users/vishnu/.spyder2-py3/radio_sources.py", line 63, in <module>
    ellipse = Ellipse(xy=(ra, dec), width=maj, height=minor, angle=ang, edgecolor=flux, lw=3, fc='None')

  File "/users/vishnu/anaconda3/lib/python3.5/site-packages/matplotlib/patches.py", line 1378, in __init__
    Patch.__init__(self, **kwargs)

  File "/users/vishnu/anaconda3/lib/python3.5/site-packages/matplotlib/patches.py", line 111, in __init__
    self.set_edgecolor(edgecolor)

  File "/users/vishnu/anaconda3/lib/python3.5/site-packages/matplotlib/patches.py", line 277, in set_edgecolor
    self._edgecolor = colors.colorConverter.to_rgba(color, self._alpha)

  File "/users/vishnu/anaconda3/lib/python3.5/site-packages/matplotlib/colors.py", line 376, in to_rgba
    'to_rgba: Invalid rgba arg "%s"\n%s' % (str(arg), exc))

ValueError: to_rgba: Invalid rgba arg "1.15569"
to_rgb: Invalid rgb arg "1.15569"
cannot convert argument to rgb sequence

您只需将 flux 的值更改为 matplotlib 颜色。我们可以使用颜色图来执行此操作,或者在您的情况下,您可以使用 flux 来定义颜色,假设有一些最小值和最大值。

由于黄色只是红色和绿色的混合,我们可以使用 1 减去 R 和 G 通道的归一化通量,并将归一化通量作为 RGB 元组的 B 通道来制作 matplotlib 颜色。

# Change these based on your definition of a 'high' value and a 'low' value (or the min/max of the data)
minflux = data[:][5].min()
maxflux = data[:][5].max()

for i in range(len(data)):
    ra,dec,maj,minor,ang,flux =data[i][0],data[i][1],data[i][2],data[i][3],data[i][4],data[i][5]

    # Normalise the flux value to the range 0-1
    normflux = (flux - minflux) / (maxflux - minflux)
    # RGB tuple. This will be yellow for min value and blue for max value
    fluxcolor = (1.-normflux, 1.-normflux, normflux)

    ellipse = Ellipse(xy=(ra, dec), width=maj, height=minor, angle=ang, edgecolor=fluxcolor, lw=3, fc='None')
    ax.add_patch(ellipse) 

这里有一个最简单的例子来检查它是否有效:

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
import numpy as np

fig,ax = plt.subplots(1)

minflux = 0.
maxflux = 10.

for i in range(10):

    flux = float(i)

    normflux = (flux - minflux) / (maxflux - minflux)
    fluxcolor = (1.-normflux, 1.-normflux, normflux)

    ell = Ellipse(xy=(i+1,0.5), width=0.5, height=0.3, angle=90., edgecolor=fluxcolor, lw=3, fc='None')

    ax.add_patch(ell)

ax.set_xlim(0,11)
plt.show()


要同时添加颜色条,也许最简单的方法使用颜色图而不是我上面显示的方法。在这种情况下,我们还可以使用 PatchCollection 将所有椭圆添加到轴上,然后将集合的数组设置为通量值以定义它们的颜色。

例如:

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
import numpy as np

import matplotlib.colors as colors
from matplotlib.collections import PatchCollection

# Define our colormap here. 
# Want red and green to be 1 at 0, and 0 at 1. Blue to be 0 at 0, and 1 at 1.
cdict = {'red':  ((0.0,1.0,1.0),
                  (1.0,0.0,0.0)),
        'green': ((0.0,1.0,1.0),
                  (1.0,0.0,0.0)),
        'blue':  ((0.0,0.0,0.0),
                  (1.0,1.0,1.0))
        }
# Use that dictionary to define the Linear SegmentedColormap
YlBu = colors.LinearSegmentedColormap('YlBu',cdict)

# Create figure
fig,ax = plt.subplots(1)

# Set the aspect ratio
ax.set_aspect('equal')

# We will populate these lists as we loop over our ellipses
ellipses = []
fluxes = []

for i in range(9):

    # Use i as a dummy value for our flux
    flux = float(i)

    # Store the fluxes. You have this already in your data array
    fluxes.append(flux)

    # Angle is in degrees
    angle = float(i) * 45.

    # Create the ellipse patch. Don't add to the axes yet
    ell = Ellipse(xy=(i,2.), width=0.8, height=0.2, angle=angle)

    # Just add it to this list
    ellipses.append(ell)

# Now, create a patch collection from the ellipses. 
# Turn off facecolor, and set the colormap to the one we created earlier
# For now, set edgecolor to black; we will change this in the next step
pc = PatchCollection(ellipses, match_original=False, lw=3, cmap=YlBu, facecolor='None', edgecolor='k')

# Set the color array here.
pc.set_array(np.array(fluxes))

# Now we add the collection to the axes
ax.add_collection(pc)

# And create a colorbar
fig.colorbar(pc,orientation='horizontal')

# Set the axes limits
ax.set_xlim(-1,9)
ax.set_ylim(0,4)

plt.show()