Farbvektor an Plot-Befehl übergeben

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mcatis
User
Beiträge: 20
Registriert: Donnerstag 29. August 2013, 01:11
Wohnort: Köln

Hallo Leute,

ich habe mit matplotlib-Basmap eine Karte erzeugt und will dort animiert Markers mit verschiedenen Farben drauf malen. Soweit klappt das auch alles.
Nur meckert er bei der Übergabe des Color-Vektors, dass er RGBA haben will.

Hier mein Code:

Code: Alles auswählen

l, = m.plot([], [], c=[], markersize=3)

xx=[]
yy=[]
ww=[]

for i in range(len(a)):
    print longitude[i],latitude[i]
    xpt,ypt = m(longitude[i],latitude[i])
    xx.append(xpt)
    yy.append(ypt)
    ww.append(float(weight[i]/100))

data = np.vstack([xx,yy,ww])

colormap = np.array(["0.35","0.78","0.35","0.78","0.35","0.78","0.35","0.78","0.35","0.78",
          "0.35","0.78","0.35","0.78","0.35","0.78","0.35","0.78","0.35","0.78",
          "0.35","0.78","0.35","0.78","0.35","0.78","0.35","0.78","0.35","0.78"])

def animate(num, data, point):
    num = num+1
    print num
    print data
    point.set_data(data[0,:num],data[1,:num])
    #print data[2,:num+1]                                                                                                    
    print data[2,:num]
    point.set_color(colormap)
    return point,

ani = animation.FuncAnimation(fig, animate, frames=len(data[1]), blit=True, fargs=(data,l), interval=500, repeat=False)
Es kommt der Fehler:
ValueError: to_rgba: Invalid rgba arg "['0.35' '0.78' '0.35' '0.78' '0.35' '0.78' '0.35' '0.78' '0.35' '0.78'
'0.35' '0.78' '0.35' '0.78' '0.35' '0.78' '0.35' '0.78' '0.35' '0.78'
'0.35' '0.78' '0.35' '0.78' '0.35' '0.78' '0.35' '0.78' '0.35' '0.78']"
number in rbg sequence outside 0-1 range
Hat jemand eine Idee, wie ich den Vektor übergebe. Er muss ja die Farbinfo von Schritt zu Schritt beibehalten, wie bei den Koordinaten.
1. Marker zb rot, 2. Marker grün (aber er muss dann trotzdem den 1. rot lassen). Ich hatte es geschafft die Farbe zu ändern, aber dann hat er das auf alle Marker angewendet :cry:

Kann jemand helfen?

Lg
Zuletzt geändert von Anonymous am Mittwoch 21. Mai 2014, 12:13, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
BlackJack

@mcatis: Das ist alles sehr unvollständig. Man wüsste ohne raten ja nicht einmal wo `set_color()` dokumentiert ist. Also schau Du doch mal nach: Was sagt die Dokumentation dazu?

Ein Array mit Zeichenketten scheint mir auf jeden Fall falsch zu sein, selbst wenn das nur vier Werte für RGBA enthalten würde.
mcatis
User
Beiträge: 20
Registriert: Donnerstag 29. August 2013, 01:11
Wohnort: Köln

Hallo BlackJack,

hier der komplette Quellcode:

Code: Alles auswählen

import matplotlib
matplotlib.use('Agg')
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import matplotlib.animation as animation

lon = [7.3, 8.7, 8.4, 11.2]
lat = [52.9, 52.0, 53.8, 50.9]

fig = plt.figure(figsize=(8,8),facecolor='w')

m = Basemap(llcrnrlon=4.0,urcrnrlon=15.0,llcrnrlat=46.0,urcrnrlat=56.0,\
            rsphere=(6378137.00,6356752.3142),\
            resolution='l',projection='merc',\
            lat_ts=0.,suppress_ticks=True)

m.drawmapboundary(fill_color='w')
m.drawcoastlines(linewidth=0.3)

l, = m.plot([], [], c=[], marker="+", markersize=3)

xx = []
yy = []

for i in range(len(lon)):
    xpt,ypt = m(lon[i],lat[i])
    xx.append(xpt)
    yy.append(ypt)

data = np.vstack([xx,yy])

colormap = np.array(["0.35","0.78","0.35","0.78","0.35","0.78","0.35","0.78","0.35","0.78",
          "0.35","0.78","0.35","0.78","0.35","0.78","0.35","0.78","0.35","0.78",
          "0.35","0.78","0.35","0.78","0.35","0.78","0.35","0.78","0.35","0.78"])

def animate(num, data, point):
    num = num+1
    point.set_data(data[0,:num],data[1,:num])
    point.set_color('r')                   # --> geht (aber alles rot)
    #point.set_color(colormap)      # --> geht nicht                                                                                                                                                                           
    return point,

ani = animation.FuncAnimation(fig, animate, frames=len(data[1]), blit=True, fargs=(data,l), interval=500, repeat=False)
ani.save('animation_markers.gif', writer='imagemagick')
Hoffe das wird jetzt klarer. Es ist eine lauffähige Version auf jeden Fall.

Nachtrag:

Ich habe mal die Strings weggenommen im colormap-Vektor und dann das hier gemacht:

Code: Alles auswählen

point.set_color(colormap)
Dann plottet er alles grün. :? :shock:

Hingegen

Code: Alles auswählen

point.set_color(colormap[:num])
verursacht den Fehler:
ValueError: to_rgba: Invalid rgba arg "[ 0.35]"
need more than 1 value to unpack
Lg mcatis
mcatis
User
Beiträge: 20
Registriert: Donnerstag 29. August 2013, 01:11
Wohnort: Köln

Ich hab das alles mit dem return mal wegelassen und zur Vereinfachung den Plot-Befehl mit in die Animations-Funktion gezogen:

Code: Alles auswählen

def get_marker_color(nn):
    if nn < 2:
        return (0.11)
    elif nn < 3:
        return (0.55)
    else:
        return (0.99)

markers = []

def animate(num):
    num = num+1
    marker_string = get_marker_color(num)
    markers.append(marker_string)
    m.plot(data[0,:num],data[1,:num], c=float(str(markers[:num])), marker="o", markersize=3)
ValueError: could not convert string to float: [0.11]
Er kommt einfach mit diesen Strings und floats nicht klar.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

mcatis hat geschrieben:Er kommt einfach mit diesen Strings und floats nicht klar.
Du meinst, dass du nicht mit den Strings klar kommst ;-) Schau dir doch die Fehlermeldung an, da steht ganz klar, dass "[0.11]" nicht in einen String umgewandelt werden kann. Jetzt solltest du dir die Frage stellen, warum du eine Liste bekommst. Zerlege Zeile 15 man in Einzelstücke, dann siehst du das Problem.

Allerdings hättest du das Problem gar nicht erst, wenn du von Anfang an vernünftig Arbeitest. Das Problem ist ja nicht, dass du mit Strings arbeiten musst, sondern dass du an dieser Stelle überhaupt strings in die Hände bekommst und dass es nicht von Anfang an floats sind.
Das Leben ist wie ein Tennisball.
mcatis
User
Beiträge: 20
Registriert: Donnerstag 29. August 2013, 01:11
Wohnort: Köln

Ja, das hab ich ja schon alles durch. Auch reine floats gehen nicht, wie folgendes Programm zeigt:

Code: Alles auswählen

import matplotlib
matplotlib.use('Agg')
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import matplotlib.animation as animation

lon = [7.3, 8.7, 8.4, 11.2]
lat = [52.9, 52.0, 53.8, 50.9]

fig = plt.figure(figsize=(8,8),facecolor='w')

m = Basemap(llcrnrlon=4.0,urcrnrlon=15.0,llcrnrlat=46.0,urcrnrlat=56.0,\
            rsphere=(6378137.00,6356752.3142),\
            resolution='l',projection='merc',\
            lat_ts=0.,suppress_ticks=True)

m.drawmapboundary(fill_color='w')
m.drawcoastlines(linewidth=0.3)

l, = m.plot([], [], c=[], marker="+", markersize=3)

xx = []
yy = []

for i in range(len(lon)):
    xpt,ypt = m(lon[i],lat[i])
    xx.append(xpt)
    yy.append(ypt)

data = np.vstack([xx,yy])

colormap = np.array([0.35,0.78,0.35,0.78,0.35,0.78,0.35,0.78,0.35,0.78,
           0.35,0.78,0.35,0.78,0.35,0.78,0.35,0.78,0.35,0.78,
           0.35,0.78,0.35,0.78,0.35,0.78,0.35,0.78,0.35,0.78])

def animate(num, data, point):
    num = num+1
    point.set_data(data[0,:num],data[1,:num])
    #point.set_color('r')            # --> geht (aber alles rot)                                                                                                                                               
    point.set_color(colormap[:num])      # --> geht nicht                                                                                                                                                      
    return point,

ani = animation.FuncAnimation(fig, animate, frames=len(data[1]), blit=True, fargs=(data,l), interval=500, repeat=False)
Fehler:
ValueError: to_rgba: Invalid rgba arg "[ 0.35]"
need more than 1 value to unpack
Lg
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Die Fehlermeldung nennt dir doch das Problem: Statt der Stringrepräsentation einer Liste, übergibst du nun eine einelementige Liste. Es wird aber ein Wert erwartet, der in RGBA umgewandelt werden kann.
Das Leben ist wie ein Tennisball.
mcatis
User
Beiträge: 20
Registriert: Donnerstag 29. August 2013, 01:11
Wohnort: Köln

Wie sieht denn eine "Stringrepräsentation einer Liste" bzw. "ein Wert, der in RGBA umgewandelt werden kann" aus? :roll:
BlackJack

@mcatis: Bezüglich der Datentypen solltest Du mal ein Python-Grundlagentutorial durcharbeiten.

RGBA sind ja normalerweise vier Werte, für jede Komponente Einer. Mal anders herum gefragt, was hättest Du denn bei einer Funktion die RGBA erwartet bei [0.35] erwartet wie die Farbe aussieht und zustande kommt?
mcatis
User
Beiträge: 20
Registriert: Donnerstag 29. August 2013, 01:11
Wohnort: Köln

Ich weiß das ein RGBA-Wert 4 Werte hat! Das soll kein RGBA werden sondern ein Grauwert.
Die kann man ja bekanntlich mit 0.0 bis 1.0 angeben, z.B color='0.67'.
Will nur wissen wie ich dem sagen soll, dass er die Werte nimmt. Und nicht irgndwas von RGBA erwartet. Weiß nicht was er von mir will. Ich hab ihm nie gesagt
das ich ein RGBA-Wert nehmen möchte :D
BlackJack

@mcatis: Eine Zeichenkette mit einer Zahlrepräsentation ist halt nicht das gleiche wie eine Liste oder ein Array mit diesem Wert als einzigen Element. Und wenn Du eine Sequenz übergibst, dann sagst Du im Grunde schon das Du eine RGB- oder RGBA-Farbe übergeben möchtest, denn so werden die übergeben. Steht so in der Dokumentation: Sequenzen mit 3 oder 4 Werten sind RGB bzw. RGBA-Angaben.
mcatis
User
Beiträge: 20
Registriert: Donnerstag 29. August 2013, 01:11
Wohnort: Köln

Und wie müsste ich es stattdessen schreiben? Ich sehe ja keine Vorschläge ?

Lg
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

@mcatis: Du mußt Dir halt überlegen, wie man einen Grauwert in einen RGB-Wert umrechnet.
BlackJack

@mcatis: Oder den Grauwert als *eine* Zeichenkette mit einer Zahldarstellung zwischen 0.00 und 1.00 übergeben.
mcatis
User
Beiträge: 20
Registriert: Donnerstag 29. August 2013, 01:11
Wohnort: Köln

So, hab es jetzt versucht mit HEX-Werten in einem Array und die dann nach RGB umgerechnet:

Code: Alles auswählen

def hex_to_RGB(hex):
    return [int(hex[i:i+2], 16) for i in range(1,6,2)]


colormap = np.array(['#550000','#C0C0C0','#550000','#C0C0C0','#550000','#C0C0C0','#550000','#C0C0C0','#550000','#C0C0C0',
           '#550000','#C0C0C0','#550000','#C0C0C0','#550000','#C0C0C0','#550000','#C0C0C0','#550000','#C0C0C0',
           '#550000','#C0C0C0','#550000','#C0C0C0','#550000','#C0C0C0','#550000','#C0C0C0','#550000','#C0C0C0'])

hexcolor = []

for i in range(len(colormap)):
    hexcolor.append(hex_to_RGB(colormap[i]))

def animate(num, data, point):
    num = num+1
    point.set_data(data[0,:num],data[1,:num])                                                                                                                             
    point.set_color(hexcolor[:num])                                                                                                                                   
    return point,

ani = animation.FuncAnimation(fig, animate, frames=len(data[1]), blit=True, fargs=(data,l), interval=500, repeat=False)
ani.save('test.gif', writer='imagemagick')

Es kommt wieder die Fehlermeldung
ValueError: to_rgba: Invalid rgba arg "[[85, 0, 0]]"
need more than 1 value to unpack
BlackJack

@mcatis: Weil Du immer noch den gleichen Fehler machst: Ein Array mit einem Element ist nicht das gleiche wie ein Element.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Du übergibst schon wieder eine Liste, welche eine Liste enthält. Du solltest unbedingt noch einmal die Grundlagen von Indexzugriffen durcharbeiten und die Unterschiede von ``data``, ``data[i:]`` und ``data[:i]`` verstehen. Warum machst du überhaupt den Umweg über ein numpy-Array, wenn es eine einfache Liste auch tun würde?

Das Muster

Code: Alles auswählen

for i range(len(data)):
    data[i] ...
ist in Python ein Anti-Pattern. Du kannst direkt über Elemente einer Liste iterieren. Wenn du doch mal den Index brauchst, dann verwende die enumerate-Funktion.

Und bitte zeige immer die gesamte Fehlermeldung und zwar inklusive des gesamten Tracebacks, nicht nur den Teil, den du für wichtig erachtest. Dort stehen noch viel mehr Informationen, zum Beispiel *wo* der Fehler auftritt, drin.
Das Leben ist wie ein Tennisball.
mcatis
User
Beiträge: 20
Registriert: Donnerstag 29. August 2013, 01:11
Wohnort: Köln

Also so klappt's:

Code: Alles auswählen


import matplotlib
matplotlib.use('Agg')
import matplotlib.cm as cm
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import matplotlib.animation as animation

lon = [7.3, 8.7, 8.4, 11.2]
lat = [52.9, 52.0, 53.8, 50.9]

fig = plt.figure(figsize=(8,8),facecolor='w')

m = Basemap(llcrnrlon=4.0,urcrnrlon=15.0,llcrnrlat=46.0,urcrnrlat=56.0,\
            rsphere=(6378137.00,6356752.3142),\
            resolution='l',projection='merc',\
            lat_ts=0.,suppress_ticks=True)

m.drawmapboundary(fill_color='w')
m.drawcoastlines(linewidth=0.3)

l, = m.plot([], [], c=[], marker="+", markersize=3)

xx = []
yy = []

for i in range(len(lon)):
    xpt,ypt = m(lon[i],lat[i])
    xx.append(xpt)
    yy.append(ypt)

data = np.vstack([xx,yy])

colormap = ('0.1','0.3','0.6','0.9','0.35','0.78','0.35','0.78','0.35','0.78',
           '0.35','0.78','0.35','0.78','0.35','0.78','0.35','0.78','0.35','0.78',
           '0.35','0.78','0.35','0.78','0.35','0.78','0.35','0.78','0.35','0.78')

def animate(num, data, point):
    num = num+1
    point.set_data(data[0,:num],data[1,:num])                                                                                                                          
    point.set_color(colormap[num])                                                                                                                     
    return point,

ani = animation.FuncAnimation(fig, animate, frames=len(data[1]), blit=True, fargs=(data,l), interval=500, repeat=False)
ani.save('test.gif', writer='imagemagick')
Aber das hatte ich ja schon mal. Dann setzt er die Farben zwar, aber ich verliere die Information der ersten Farben.
Er zeichnet den 1. Marker in der korrekten Farbe. Dann kommt der 2. Marker: Auch hier nimmt er die korrekte Farbe, setzt dann aber den 1. in der gleichen Farbe wie
den 2. Genau das ist ja das Problem. Deshalb wollte ich ähnlich wie bei den data-Vektoren für die lat-lon-Infos auch bei den Farben einen Vektor übergeben
der sich von Durchlauf zu Durchlauf weiter "aufbläht".
Wie kann ich denn erreichen, dass er die Farbe des 1. Markers nicht überschreibt?

Lg und danke schonmal für alles.
BlackJack

@mcatis: Das geht mit `plot()` gar nicht. Ich habe gerade etwas gemacht was man vielleicht viel früher mal hätte machen sollen: In die Dokumentation geschaut. Ich ging ja davon aus das Du das setzen von `c` auf eine *Liste* schon mal nicht-animiert ausprobiert hast, aber das geht grundsätzlich nicht. Die Dokumentation von `plot()` ist da eigentlich auch recht deutlich das dort *ein* Farbwert für die *Linie* erwartet wird. Das was Du `point` genannt hast ist ein `Line2D`-Exemplar. Ist etwas irreführend das `point` zu nennen. ;-)

Was Du wahrscheinlich möchtest ist ein `scatter()`-Plot. *Da* sagt die Dokumentation nämlich das man auch eine Sequenz von Farben angeben kann.
mcatis
User
Beiträge: 20
Registriert: Donnerstag 29. August 2013, 01:11
Wohnort: Köln

Gut, danke. Mit einem scatter funktioniert es dann auch.

Lieben Dank für eure Hilfe.
Antworten