Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Plotting 2d vector fields – how to delay function evaluation

I want to plot, for example, the following 2d vector field: $$\vec{F}(x,y)= \begin{cases} (0.1,0.1), & \text{for }r\le d_{min}\newline \frac{\vec{r}}{r^3}, & \text{otherwise}. \end{cases}$$ In one SageMath cell I have defined corresponding Python function:

reset()
dmin = 0.03
def my_vector_field_2D(x,y):
    vector_field = vector([0.1,0.1])
    r = vector([x,y])
    if r.norm()>dmin:
        vector_field = 1/ r.norm()^3 * r
    return vector_field

In another cell, I use function plot_vector_field to plot the field:

var('x','y')
plot_vector_field(my_vector_field_2D(x,y),(x,-0.3,0.3),(y,-0.3,0.3))

However, function my_vector_field_2D(x,y) is evaluated before it is given to the function plot_vector_field and because in this evaluation my_vector_field_2D receives instead of numbers symbolic variables x and y, expression r.norm()>dmin is always False. As a result, my_vector_field_2D(x,y) is evalueted to: (0.100000000000000, 0.100000000000000). So the plotted filed is actually $\vec{F}(x,y)=(0.1,0.1)$ everywhere and that is not what I want.

How can I prevent this function evaluation?

I tried something that works with the plot function (provide the plot function with just the name of a function that you want to plot (without parameters) in order to prevent function evaluation):

plot_vector_field(my_vector_field_2D,(-0.3,0.3),(-0.3,0.3))

But here this method does not work: TypeError: 'function' object is not iterable.

My first why question: Why this does not work? It works for plot function and also for contour_plot function and probably for some other plot functions.

Then I found in the SageMath documentation that “when plotting non-symbolic functions, they should be wrapped in lambda”. So I tried:

plot_vector_field(lambda x,y:my_vector_field_2D(x,y),(-0.3,0.3),(-0.3,0.3))

And the same error popped up: TypeError: 'function' object is not iterable.

But this works:

plot_vector_field((lambda x,y:my_vector_field_2D(x,y)[0],lambda x,y:my_vector_field_2D(x,y)[1]),(-0.3,0.3),(-0.3,0.3))

My second why question: Why do I need two lambda functions or why do I need to manually decompose vector returned by my_vector_field_2D function into its two components?

Plotting 2d vector fields – how to delay function evaluation

I want to plot, for example, the following 2d vector field: $$\vec{F}(x,y)= \begin{cases} (0.1,0.1), & \text{for }r\le d_{min}\newline \frac{\vec{r}}{r^3}, & \text{otherwise}. \end{cases}$$ In one SageMath cell I have defined corresponding Python function:

reset()
dmin = 0.03
def my_vector_field_2D(x,y):
    vector_field = vector([0.1,0.1])
    r = vector([x,y])
    if r.norm()>dmin:
        vector_field = 1/ r.norm()^3 * r
    return vector_field

In another cell, I use function plot_vector_field to plot the field:

var('x','y')
plot_vector_field(my_vector_field_2D(x,y),(x,-0.3,0.3),(y,-0.3,0.3))

However, function my_vector_field_2D(x,y) is evaluated before it is given to the function plot_vector_field and because in this evaluation my_vector_field_2D receives instead of numbers symbolic variables x and y, expression r.norm()>dmin is always False. As a result, my_vector_field_2D(x,y) is evalueted to: (0.100000000000000, 0.100000000000000). So the plotted filed is actually $\vec{F}(x,y)=(0.1,0.1)$ everywhere and that is not what I want.

How can I prevent this function evaluation?

I tried something that works with the plot function (provide the plot function with just the name of a function that you want to plot (without parameters) in order to prevent function evaluation):

plot_vector_field(my_vector_field_2D,(-0.3,0.3),(-0.3,0.3))

But here this method does not work: TypeError: 'function' object is not iterable.

My first why question: Why this does not work? It works for plot function and also for contour_plot function and probably for some other plot functions.

Then I found in the SageMath documentation that “when plotting non-symbolic functions, they should be wrapped in lambda”. So I tried:

plot_vector_field(lambda x,y:my_vector_field_2D(x,y),(-0.3,0.3),(-0.3,0.3))

And the same error popped up: TypeError: 'function' object is not iterable.

But this works:

plot_vector_field((lambda x,y:my_vector_field_2D(x,y)[0],lambda x,y:my_vector_field_2D(x,y)[1]),(-0.3,0.3),(-0.3,0.3))

My second why question: Why do I need two lambda functions or why do I need to manually decompose vector returned by my_vector_field_2D function into its two components?

Plotting 2d vector fields – how to delay function evaluation

I want to plot, for example, the following 2d vector field: $$\vec{F}(x,y)= \begin{cases} (0.1,0.1), & \text{for }r\le d_{min}\newline \frac{\vec{r}}{r^3}, & \text{otherwise}. \end{cases}$$ In one SageMath cell I have defined corresponding Python function:

reset()
dmin = 0.03
def my_vector_field_2D(x,y):
    vector_field = vector([0.1,0.1])
    r = vector([x,y])
    if r.norm()>dmin:
        vector_field = 1/ r.norm()^3 * r
    return vector_field

In another cell, I use function plot_vector_field to plot the field:

var('x','y')
plot_vector_field(my_vector_field_2D(x,y),(x,-0.3,0.3),(y,-0.3,0.3))

However, function my_vector_field_2D(x,y) is evaluated before it is given to the function plot_vector_field and because in this evaluation my_vector_field_2D receives instead of numbers symbolic variables x and y, expression r.norm()>dmin is always False. As a result, my_vector_field_2D(x,y) is evalueted to: (0.100000000000000, 0.100000000000000). So the plotted filed is actually $\vec{F}(x,y)=(0.1,0.1)$ everywhere and that is not what I want.

How can I prevent this function evaluation?

I tried something that works with the plot function (provide the plot function with just the name of a function that you want to plot (without parameters) in order to prevent function evaluation):

plot_vector_field(my_vector_field_2D,(-0.3,0.3),(-0.3,0.3))

But here this method does not work: TypeError: 'function' object is not iterable.

My first why question: Why this does not work? It works for plot function and also for contour_plot function and probably for some other plot functions.

Then I found in the SageMath documentation that “when plotting non-symbolic functions, they should be wrapped in lambda”. So I tried:

plot_vector_field(lambda x,y:my_vector_field_2D(x,y),(-0.3,0.3),(-0.3,0.3))

And the same error popped up: TypeError: 'function' object is not iterable.

But this works:

plot_vector_field((lambda x,y:my_vector_field_2D(x,y)[0],lambda x,y:my_vector_field_2D(x,y)[1]),(-0.3,0.3),(-0.3,0.3))

My second why question: Why do I need two lambda functions or why do I need to manually decompose vector returned by my_vector_field_2D function into its two components?