Funktion mit Daten zeichnen

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
lila_Erdmaennchen
User
Beiträge: 2
Registriert: Freitag 29. Januar 2016, 22:18

Hallihallo!

Ich habe nicht sonderlich viel Ahnung vom Programmieren, aber ich gebe mein Bestes.
Ich möchte die Funktion CHI(x) plotten. Sie besteht aus mehreren termen, die teilweise die Summen (über i) von Messreihen N_i und t_i enthalten. Das x steht manchmal in der Summe mit drin, manchmal aber auch noch davor. Jedenfalls kann man es nicht mathematisch umformen, sodass es einfach aussieht. Dabei sind N_i und t_i jeweils Spalten mit Messwerten, die habe ich in zwei .dat Dateien geschrieben und in meinem Code als np.arrays (?) N und t importiert. dt t_1 und t_k sind einfach nur Zahlenwerte. Das soll also eine Funktion von x werden. Später muss ich noch das Minimum bestimmen, da weiß ich auch noch nicht, wie das geht, aber zunächst der Plot: Hier ist mein Code bis jetzt:

Code: Alles auswählen

##!/usr/bin/python
# -*- coding: utf-8 -*-
import numpy as np
import math as m
from matplotlib import pyplot as plt

def Nnullfkt(Nges,x,t1,tk,dt):
	Nnull=Nges/(m.exp(-t1/x)-m.exp(-(tk-dt)/x))
	return(Nnull)
	
def sum1(x,dt):
	global s1
	s1=0
	for i in range(len(t)):
		s1=s1 + m.exp(-(t[i]+0.5*dt)/x)
	sum1=s1
	return(sum1)
	
def sum2(x,dt):
	global s2
	s2=0
	for i in range(len(t)):
		s2=s2 + (1/N[i])*(m.exp(-(2*t[i]+dt)/x))
	sum2=s2
	return(sum2)
			
			
if __name__=="__main__":
	N=np.loadtxt("Ni.dat")
	t=np.loadtxt("ti.dat")
	
	t1=t[0]
	tk=t[len(t)-1]
	dt=t[1]-t[0]
	Nges=np.sum(N)
	
	x=np.linspace(1,3,2000)
	chi=np.empty_like(x)
	
	chi=np.sum(N)-2*Nnullfkt(Nges,x,t1,tk,dt)*dt*(1/x)*sum1(x,dt)
	+(((Nnullfkt(Nges,x,t1,tk,dt)*dt)/x)**2)*sum2(x,dt)		
		
	plt.plot(x,chi)
	plt.grid(True)
	plt.xlim(1.5,3.5)
	plt.ylim(0,50000)
	plt.show()
Ich bekomme die Fehlermeldung für Zeile 8 und 40 "only length-1 arrays can be converted into python scalars" Damit kann ich leider nix anfangen, denn weder Nnull, noch chi sind ja arrays (dachte ich jedenfalls) :D

Ich hoffe ihr könnt mir helfen!
Liebe Grüße :)
Zuletzt geändert von Anonymous am Freitag 29. Januar 2016, 22:49, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@lila_Erdmaennchen: Nun ja, der Gedanke ist dann offensichtlich falsch gewesen. Dann musst Du also herausfinden wo und warum das Programm anfängt (Zwischen)Ergebnisse zu produzieren die vom Typ und/oder Wert nicht Deinen Erwartungen entsprechen. Das geht ganz gut in einer interaktiven Python-Shell, denn da wirst Du sehr schnell auf folgendes stossen:

Code: Alles auswählen

In [20]: np.linspace(1, 3, 10)
Out[20]: 
array([ 1.        ,  1.22222222,  1.44444444,  1.66666667,  1.88888889,
        2.11111111,  2.33333333,  2.55555556,  2.77777778,  3.        ])

In [21]: 42 / np.linspace(1, 3, 10)
Out[21]: 
array([ 42.        ,  34.36363636,  29.07692308,  25.2       ,
        22.23529412,  19.89473684,  18.        ,  16.43478261,
        15.12      ,  14.        ])

In [22]: math.exp(42 / np.linspace(1, 3, 10))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-22-00b5b9945336> in <module>()
----> 1 math.exp(42 / np.linspace(1, 3, 10))

TypeError: only length-1 arrays can be converted to Python scalars
Du benutzt Numpy-Arrays auch in den anderen Funktion nicht so wie sie gedacht sind, weil Du in Python-Schleifen über die einzelnen Elemente iterierst, statt mit dem ganzen Array zu rechnen.

Anmerkungen zum Quelltext: Vergiss bitte sofort das es ``global`` gibt. Das hat in sauberen Programmen nichts zu suchen und ist bei dem Quelltext sogar noch komplett sinnlos weil die Namen `s1` und `s2` jeweils nur innerhalb der Funktion verwendet werden. Ebenfalls sinnfrei ist es dort jeweils in der vorletzten Zeile den Namen an einen anderen zu binden der danach dann ausschliesslich für das ``return`` verwendet wird. Lokale Namen die den gleichen Namen wie die Funktion tragen sind auch nicht gerade gut für die Lesbarkeit. Falls Du von Pascal oder einem Basic-Dialekt kommst, der Rückgabewerte so zuweist: Lass das bitte bleiben und fang an in Python zu programmieren. ;-)

Funktionen sollten weder mit ``global`` Namen ausserhalb (neu) binden, noch auf Werte von ausserhalb zugreifen die keine Konstanten sind und nicht als Argument übergeben wurden. Das macht Programme sehr schwer nachvollziehbar und damit schwer testbar, wartbar, und erweiterbar. Eine Funktion sollte eine in sich geschlossene Einheit sein, die man nachvollziehen kann ohne das gesamte restliche Programm im Kopf zu haben. Deswegen schreibt man am besten auch das Hauptprogramm in eine Funktion, so dass auf Modulebene nur Konstanten, Funktionen, und Klassen definiert werden.

Ein paar Leerzeichen nach Kommas und um Operatoren erhöhen die Lesbarkeit.

``return`` ist keine Funktion, sollte also auch nicht so geschrieben werden als wäre es eine.

``for i in range(len(sequence)):`` um dann `i` als Indexwert für `sequence` zu verwenden ist in Python ein „anti pattern“. Man kann in Python direkt über die Werte von Sequenztypen iterieren, ohne den Umweg über einen Index. Wenn man über zwei (oder mehr) iterierbare Objekte ”parallel” iterieren muss, gibt es `zip()` oder `itertools.izip()`. Braucht man einen Indexwert *zusätzlich* zum Element, gibt es `enumerate()`.

Statt in einer Schleife selber aufzusummieren, gibt es die `sum()`-Funktion.

``sequence[len(sequence) - 1]`` ist als ``sequence[-1]`` kürzer geschrieben.

Die 2000 bei der Definition von `n` ist gewagt. Das soll ja wahrscheinlich immer so lang das wie die Eingabedaten, also sollte man das auch so schreiben.

Die erste Zuweisung an `chi` wird nirgends verwendet, kann also weg.

Die Berechnung von `chi` ist so gequetscht geschrieben sehr schwer zu durchschauen.

`Nnullfkt()` wird in der selben Rechnung zweimal mit den gleichen Argumenten aufgerufen.

Ein äquivalentes (also mit den gleichen Fehlern), „pythonischeres“ Programm könnte so aussehen:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8
import math
from itertools import izip
import numpy as np
from matplotlib import pyplot as plt


def Nnullfkt(Nges, x, t1, tk, dt):
    return Nges / (math.exp(-t1 / x) - math.exp(-(tk - dt) / x))

   
def sum1(t, x, dt):
    return sum(math.exp(-(t_i + 0.5 * dt) / x) for t_i in t)

   
def sum2(N, t, x, dt):
    return sum(
        (1 / N_i) * math.exp(-(2 * t_i + dt) / x) for N_i, t_i in izip(N, t)
    )
           

def main():
    N = np.loadtxt('Ni.dat')
    t = np.loadtxt('ti.dat')
    if len(N) != len(t):
        raise ValueError('Length of data differs.')
   
    t1 = t[0]
    tk = t[-1]
    dt = t[1] - t[0]
    Nges = np.sum(N)
    x = np.linspace(1, 3, len(t))
    nnullfkt_result = Nnullfkt(Nges, x, t1, tk, dt)
    chi = (
        Nges
        - 2 * nnullfkt_result * dt * (1 / x) * sum1(t, x, dt)
        + ((nnullfkt_result * dt) / x)**2 * sum2(N, t, x, dt)
    )
    
    plt.plot(x, chi)
    plt.grid(True)
    plt.xlim(1.5, 3.5)
    plt.ylim(0, 50000)
    plt.show()


if __name__ == '__main__':
    main()
lila_Erdmaennchen
User
Beiträge: 2
Registriert: Freitag 29. Januar 2016, 22:18

Wow Vielen Dank für die ausführliche Hilfe!

Ich habe es jetzt (nach viel Herumprobieren) Hinbekommen :D :) 8)

Tausend Dank!!!
Antworten