Pasando funciones de Python a Gnuplot

Trazar una función de Python en Gnuplot no es sencillo, aunque hay algunas soluciones. Por ejemplo, uno podría convertir sus valores en una matriz o traducir manualmente su expresión a la syntax de Gnuplot. Aquí hay un ejemplo que usa el módulo Gnuplot.py como una interfaz:

 #!/usr/bin/env python import Gnuplot import numpy as np ## define function ## func = lambda x, x0, y0, w: y0 * np.exp( -4*np.log(2) * ( (x-x0) / w )**2 ) # also works with a regular function: # def func(x, x0, y0, w): # return y0 * np.exp( -4*np.log(2) * ( (x-x0) / w )**2 ) popt = (10.1, 5, 2) ## linspace ## x = np.linspace(0, 20, num=1000) # (x min, x max, number of points) y = func(x, *popt) func_linspace = Gnuplot.Data(x, y, with_='lines', title='linspace') ## expression “translation” (lambda only) ## func_translation = Gnuplot.Func( '{y0} * exp( -4*log(2) * ( (x-{x0}) / {w} )**2 )'.format( x0=popt[0], y0=popt[1], w=popt[2], ), title='expression translation') ## plot ## g = Gnuplot.Gnuplot() g.plot(func_linspace, func_translation) 

El primer método funciona bien con un número decente de puntos, pero falla al acercarse demasiado o al cambiar la ventana fuera de los límites de la matriz, mientras que el segundo funciona en cualquier nivel de zoom. Para ilustrar este punto, ampliemos la salida del script anterior:

Función de muestreo vs expresión de traducción

Por esta razón, sería interesante encontrar una manera de trazar funciones de Python (lambda o funciones regulares) como funciones de Gnuplot . Se me ocurren dos soluciones: la traducción automática de la expresión (funciona solo para las funciones lambda “simples”), o hacer que Gnuplot use directamente la función Python.

Primera solución: traducción de expresiones (solo funciones lambda simples)

Este método no solo sería complicado de automatizar, sino que también sería imposible de implementar con funciones elaboradas. Sin embargo, todavía podríamos usar este método para funciones lambda simples. Para esbozar el comportamiento de una implementación:

 >>> def lambda_to_gnuplot(func, popt): ... # determine if translation is possible ... # extract function expression and replace parameters with values ... return func_expression # str >>> lambda_to_gnuplot( ... lambda x, x0, y0, w: y0 * np.exp( -4*np.log(2) * ( (x-x0) / w )**2), ... (10.1, 5, 2)) '5 * exp( -4*log(2) * ( (x-10.1) / 2 )**2 )' 

¿Habría una manera de implementar esta función lambda_to_gnuplot en python?

Segunda solución: pasar directamente la función Python a Gnuplot

La solución “perfecta” sería que Gnuplot usara la función Python. En mis sueños más atrevidos, es algo como:

 >>> def func(x, x0, y0, w): ... if x >> func_direct = Gnuplot.PyFunction(lambda x: func(x, 10.1, 5, 2)) >>> g.plot(func_direct) 

Esta es la solución más fácil de usar, pero su implementación sería muy difícil, si no imposible. ¿Algún consejo sobre cómo se podría implementar esta solución? La respuesta puede, por supuesto, evitar Gnuplot.py .

No estoy seguro de si estoy respondiendo completamente a tu pregunta, pero podrías intentar ejecutar tu script de Python como una llamada al sistema dentro de gnuplot pasando los argumentos.

Por ejemplo, imagine el simple script de python test.py :

 import sys x=float(sys.argv[1]) print x**2 

que devolverá el cuadrado del argumento cuando se llame así desde un shell:

 :~$ python test.py 2 4.0 :~$ python test.py 3 9.0 :~$ python test.py 4 16.0 

Ahora, dentro de gnuplot, convierte esto en una función:

 gnuplot> f(x) = real(system(sprintf("python test.py %g", x))) gnuplot> print f(1) 1.0 gnuplot> print f(2) 4.0 gnuplot> print f(3) 9.0 gnuplot> print f(4) 16.0 

Agregué el real() para que la salida de cadena de la llamada del sistema se convierta en flotante. Esto ahora le permite usarlo como una función gnuplot regular. No necesito mencionar que esto llevará mucho más tiempo de ejecución que la plot x**2 :

 f(x) = real(system(sprintf("python test.py %g", x))) plot f(x) 

introduzca la descripción de la imagen aquí