2016-05-16 1 views
0

Je veux que l'edgecolor d'une ellipse soit une fonction d'une troisième variable. Supposons que la troisième variable s'appelle flux. Si la valeur de la variable 'flux' est haute, je veux que la couleur de l'ellipse soit bleu foncé, si la valeur est basse, je veux que la couleur soit jaune. Toutes les valeurs intermédiaires doivent être un mélange de ces couleurs. Je veux que ce dégradé de couleurs soit visible sur l'axe z du graphique avec les valeurs les plus hautes et les plus basses. J'ai essayé de me référer à ce lien Matplotlib scatterplot; colour as a function of a third variable mais cela ne semble pas s'appliquer dans mon cas. Je lis les paramètres nécessaires pour tracer l'ellipse d'un fichier texte qui ressemble à ceci:Edgecolor d'Ellipse en fonction d'une troisième 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 

La cinquième colonne est la colonne nommée « flux » sur la base duquel le gradient de couleur doit être tracée.

Voici un exemple de ma tentative.

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="https://stackoverflow.com/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') 

Comme prévu, cela n'a pas fonctionné. Voici mon journal des erreurs.

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 "https://stackoverflow.com/users/vishnu/anaconda3/lib/python3.5/site-packages/spyderlib/widgets/externalshell/sitecustomize.py", line 699, in runfile 
    execfile(filename, namespace) 

    File "https://stackoverflow.com/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 "https://stackoverflow.com/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 "https://stackoverflow.com/users/vishnu/anaconda3/lib/python3.5/site-packages/matplotlib/patches.py", line 1378, in __init__ 
    Patch.__init__(self, **kwargs) 

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

    File "https://stackoverflow.com/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 "https://stackoverflow.com/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 

Répondre

2

Vous avez juste besoin de changer la valeur de flux en une couleur matplotlib. Nous pourrions utiliser une palette de couleurs pour ce faire, ou dans votre cas, vous pouvez utiliser flux pour simplement définir la couleur, en supposant des valeurs minimales et maximales. Comme le jaune est juste un mélange de rouge et de vert, nous pouvons utiliser 1 moins le flux normalisé pour les canaux R et G, et le flux normalisé comme canal B de votre tuple RGB pour faire la couleur 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) 

Voici un exemple minimal pour vérifier fonctionne:

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() 

enter image description here


Pour ajouter aussi un colorbar, peut-être la façon plus facile est d'utiliser une palette de couleurs au lieu de la méthode que j'ai montrée ci-dessus. Dans ce cas, nous pouvons également utiliser PatchCollection pour ajouter toutes les ellipses aux axes, puis définir le tableau de la collection sur les valeurs de flux pour définir leurs couleurs.

Par exemple:

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 
pc = PatchCollection(ellipses,False,lw=3,cmap=YlBu,facecolor='None') 

# 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() 

enter image description here

+0

Comment afficher la carte de couleur sur l'axe z de sorte que si quelqu'un voit le complot, ils savent que le jaune indique une faible valeur et le bleu indique la valeur plus élevée? – Vishnu

+0

Je pense que c'est plus facile en utilisant un 'PatchCollection' et en définissant une palette de couleurs. Voir ma réponse éditée ci-dessus. – tom

+0

C'était une réponse très bien expliquée. Je vous remercie. :) – Vishnu