A version of the cover pre-addition is the following.

This is based on the work in A transformation between stationary point vortex equilibria, which concerns solutions to Euler’s equation for inviscid (2D) fluid motion $$ \frac{\partial \mathbf{V}}{\partial t} + (\mathbf{V} \cdot \nabla) \mathbf{V} = – \frac{\nabla p}{p_0}, $$ where $\nabla = (\partial/\partial x, \partial / \partial y)$ is the 2D gradient operator. There is a notion of vortices for these systems, and the paper examines configurations of point vortices under certain idealized conditions that leads to particularly nice analysis. In the situation studied, one can sometimes begin with one configurations of point vortices and perform a transformation that yields another, bigger and more complicated configuration.

This is the situation depicted on the cover — begin with a simple configuration and iterate the process. The spiral shape was added afterwards and doesn’t describe underlying mathematical phenomena. The different colors of each vortex shows whether that vortex is a sink or a source, essentially.

I was told most of this after the fact by Miles — who researches fluid dynamics, is a friend from grad school, and was my coauthor on a paper about the mean value theorem. I do not typically think about fluid dynamics (and did not write the paper), and it’s a bit funny how I got involved in the production of this cover. But it was fun, and we produced many arresting images. In the future Miles and I intend to revisit these images and better describe how the various aspects of the image describes and reflects the underlying mathematical behavior.

As a fun aside — we didn’t only produce one image. We made many, and we made many configurations.^{2} In my work on visualizing modular forms, I developed a few techniques for color selection from matplotlib style colormaps, and produced several variants. I’ve collected a few of these below.

I’ve gotten several requests to make these plotting libraries available, and so I’ve made davidlowryduda/phase_mag_plot available on github as a sage library. See the github page and README for examples and up-to-date information.

This version is capable of producing contour-type plots of complex functions.

This does not include any colormap capability yet, as that is a substantially more involved^{2} process. But at some point in the future, I intend to look at revisiting the complex plotting within sage itself, perhaps updating it to allow plots of this nature.

$$ \sum_{n \geq 1} \frac{1}{F(2n-1)^s},$$

where $F(n)$ is the nth Fibonacci number. The theme is that the Fibonacci zeta function can be recognized as coming from an inner product of automorphic forms, and the continuation of the zeta function can be understood in terms of the spectral expansion of the associated automorphic forms.

This is a talk from ongoing research. I do not yet understand “what’s really going on”. But within the talk I describe a few different generalizations; firstly, there is a generalization to other zeta functions that can be viewed as traces of units on quadratic number fields, and secondly there is a generalization to quadratic forms recognizing solutions to Pell’s equation.

I intend to describe additional ideas from this talk in the coming months, as I figure out how pieces fit together. But for now, here are the slides.

]]>This note is the first in a series of notes dedicated to exploring this type of equidistribution visually. In this note, we will investigate a simpler case — rational points on the line.

We know that $\mathbb{Q}$ is dense in $\mathbb{R}$. An equidistribution statement is roughly a way of quantifying this density. Let $I \subseteq \mathbb{R}$ be a finite interval. We will say that a sequence ${x_n}_{n \geq 1}$ of elements $x_n \in I$ is $\mu$-equidistributed on $I$ (or equidistributed with respect to $\mu$) if for each subinterval $J \subset I$ we have that

$$\lim_{X \to \infty} \frac{\#\{n \leq X : x_n \in J\}}{X} = \int_J \mu(x) dx.$$

If $I = (\alpha, \beta)$ and $\mu = 1/(\beta – \alpha)$, then we will simply say that the sequence ${x_n}$ is equidistributed in $I$.

Note that $\mu$-equidistribution of a sequence implies that the sequence is dense in $I$, but the converse is not true. Further, ordering within the sequence matters — it is possible (and indeed, not hard at all) to reorder an equidistributed sequence ${ x_n }$ on $[0, 1]$ into a sequence ${ y_n }$ that is not equidistributed on $[0, 1]$. (For example, interlace rationals in $[0, 1/2]$ sparsely among the rationals $[1/2, 1]$, ordered by denominator size).

In this note, we will consider $\mathbb{Q}$. There are many enumerations of $\mathbb{Q}$ — but which enumeration will form our sequence? We will consider two such enumerations.

Let $q$ be a rational, written as $q = a/b$ (written in least terms). Define $h_1(q) = b$, and define $h_2(q) = \sqrt{a^2 + b^2}$. These are two *height* functions, giving some notion of the complexity of a number. The first, $h_1$, says that the complexity of a rational is roughly the size of the denominator. $h_2$ says that the complexity of a rational depends on both the numerator and denominator, and numbers with a large numerator or denominator are more complex.

For an implicit (finite) inverval $I$, let $X_1$ be an enumeration of rationals $q \in I$, ordered by $h_1$, and let $X_2$ be an enumeration ordered by $h_2$. We will consider equidistribution statements of the form

$$\lim_{X \to \infty} \frac{\#\{x_n \in J: h_i(x_n) \leq X\}}{\#\{x_n \in I : h_i(x_n) \leq X \}} = \int_J \mu(x) dx.$$

(This makes the ambiguous ordering of elements with the same height unimportant).

It turns out that both $X_1$ and $X_2$ are sequences with some sense of equidistribution, **but they are equidistributed with respect to different functions.** The sequence $X_1$ is simply equidistributed (and this can be proved using little more than the pigeonhole principle). The sequence $X_2$ is equistributed with respect to $$ \mu(x) = \frac{1}{\pi} \frac{1}{1 + t^2}. $$ I do not find this result obvious at all. I only learned this fact recently, and I do not reproduce a proof here.

Let us now turn to visualizing rational points in the two sequences $X_1$ and $X_2$. Given a rational point $q$, we will visualize the data pair $(q, h(q))$, where $h$ is a height function. Thus the *higher* that a point is within the visualization, the higher the height.

These are images formed from all rationals on $[0, 3]$ with denominator bounded by $400$ (first image) and $100$ (second image). Each point corresponds to a point $(q, h_1(q))$.

These are images formed from all rationals $q$ on $[0, 3]$ with $h_2(q)^2 \leq 70000$ (first image) and $20000$ (second image). Each point corresponds to a point $(q, h_2(q))$.Several patterns emerge from the images. At the bottom of each graph, there are *wells* in which no points occur. If you examine these wells, you can see that at the bottom center of each well, there is a single rational point. These notably occur around points of low height — most notably around $0, 1/2, 1, 3/2, 2, 5/2, 3$. The reason is simple: for a rational $q = a/b$ to be near $1/2$ (say), we need $1/2 – a/b \sim 1/2b$ to be small, and thus $b$ to be large. In both $h_1$ and $h_2$, the height grows linearly in the denominator $b$. On the other hand, there will be many other pairs of points of similarly bounded height that are much closer. For example, $1/b$ and $1/(b-1)$ are approximately $1/b^2$ apart, which can be significantly closer.^{1}

The graphs of $X_1$ visually become uniform, and appear almost to be mildly textured swaths of grey. We can make this even more pronounced, which we do in the next image. Graphs of $X_2$ show a clearly denser set of points at the left (favoring smaller numerators).

We now make a set of related images. In the images that follow, we extend each line from a point $(q, h(q))$ upwards. The effect is that at any designated height $H$, the horizontal line through $h(q) = H$ will include points whose heights are bounded above by $H$. To indicate the density of lines, we use shades of grey. The darker the line, the more rational points.For $X1$, we make two images. First we have a *full* image, consisting of points with $h(q) \leq 400$ and $20$ different shades of grey. Second, we have a *sparser* image, consisting of points with $h(q) \leq 100$ and $12$ different shades of grey. These are still over the interval $[0, 3]$.

In the next post, we will look at rational points on circles.

]]>Stated differently, suppose that $I$ is an arc on the circle $X^2 + Y^2 = 2$. Then asymptotically, the number of rational points on the arc $I$ with height bounded by a number $H$ is equal to what you would expect if $\lvert I\rvert /2\sqrt{2}\pi$ of all points with height up to $H$ were on this arc. Here, $\lvert I\rvert /2\sqrt{2}\pi$ the ratio of the arclength of the arc $I$ with the total circumference of the circle.

This only makes sense if we define the height of a rational point on the circle. Given a point $(a/c, b/c)$ (written in least terms) on the circle, we define the height of this point to be $c$.

In forthcoming work with my frequent collaborators Chan Ieong Kuan, Thomas Hulse, and Alexander Walker, we count three term arithmetic progressions of squares. If $C^2 – B^2 = B^2 – A^2$, then clearly $A^2 + C^2 = 2B^2$, and thus a 3AP of squares corresponds to a rational point on the circle $X^2 + Y^2 = 2$. We compare one of our results to what you would expect from equidistribution. From general principles, we expected such equidistribution to be true. But I wasn’t sure how to prove it.

With helpful assistance from Noam Elkies, Emmanuel Peyre, and John Voight (who each immediately knew how to prove this), I learned how to prove this fact.

The rest of this note contains this proof.

*Which height function is natural* is itself a natural question. Perhaps the most obvious height function would come from looking at the magnitude of a point on the circle after homogenization. Rational points on $X^2 + Y^2 = 2$ are the same as integer points on $X^2 + Y^2 = 2Z^2$. If $p = (x : y : z)$ is such a point, then perhaps the most natural definition of the *size* of this point would be $\lvert p \rvert = x^2 + y^2 + z^2$.

But since this point satisfies $x^2 + y^2 = 2z^2$, we have that

$$ \lvert p \rvert = 3z^2,$$

which is essentially the same as the height we actually use. Ordering rational points $(x, y)$ on $X^2 + Y^2 = 2$ by the size of the denominator is the same ordering of points $p$ on $X^2 + Y^2 = 2Z^2$ by $\lvert p \rvert$.

Thus this actually is a natural notion of height.

To prove this equidistribution, we do the following steps.

- Parametrize rational points by projection,
- Study the problem in the parametrization space,
- Translate this problem into a lattice-point problem in regions,
- Then we execute this lattice-point counting argument.

Rational points on $X^2 + Y^2 = 2$ are the same as integer points on $X^2 + Y^2 = 2Z^2$. These points are parametrized by

$$

(x:y:z) = (m^2 + 2mn – n^2 : m^2 – 2mn – n^2 : m^2 + n^2).

$$

This is a classical argument. The idea is to find a rational point (like $(-1, -1)$) and then consider lines with rational slope $t$ through this point. Every rational point on the circle will appear from such a slope (with the exception of the single point $(-1, 1)$, which would have infinite slope).

Projecting from this point gives rational points in terms of the rational parameter $t = m/n$. Clearing denominators gives the result.

Although this is not a complicated argument, it can be done in sage.

```
var('x y t')
show(solve([
x^2 + y^2 == 2,
y == t*(x+1) + 1
], [x, y]))
```

When counting rational points, we do not want to count (for example) $(-1, -1)$ and $(-2/2, -2/2)$, as these are the same point. Stated projectively, we want to count each point $(x : y : z) \in \mathbb{P}^2(\mathbb{Z})$ precisely once (and use its simplest form as its height, of course). These are primitive points.

We need to find conditions for $m,n$ such that the parametrization of points in terms of $m$ and $n$ yields only the primitive points. Each primitive point corresponds to a pair $(\pm m,\pm n)$ such that $\gcd(m,n)=1$ and the parity of $m$ is opposite from the parity of $n$.

It is very easy to see that if either $\gcd(m,n) \neq 1$ or if the parities of $m$ and $n$ are the same, then the resulting point $(x : y : z)$ is not primitive.

Conversely, suppose that the resulting point $(x : y : z)$ is not primitive. Then $\gcd(m^2 – 2mn – n^2, m^2 + 2mn – n^2, m^2 + n^2) > 1$, and thus

$$ \gcd(4mn, m^2 + n^2) = g > 1.$$

The prime factors of $4mn$ are exactly $2$ and the primes diving $m$ and $n$. If $p \mid g$ divides $m$ or $n$, then it divides $m^2 + n^2$, and thus $p \mid \gcd(m, n)$. If $2 \mid g$, then $2 \mid m^2 + n^2$, and thus the parities of $m$ and $n$ are the same.

Thus we see that primitive points are precisely those obtained from $(m, n)$ with $\gcd(m,n) = 1$, $m, n$ having opposite parity, and $m \geq 0$.

In terms of the parametrization $$ (x : y : z) = (m^2 – 2mn – n^2, m^2 + 2mn – n^2, m^2 + n^2),$$ one can explicitly check that

$$ (1+i)(m-in)^2 = x + iy.$$

(Noam Elkies pointed this out to me). Thus points $(x, y)$ are equidistributed (when ordered by denominator) if and only if the numbers $m + in$ are angularly equidistributed (when ordered by $m^2 + n^2$).

To prove this, we study the following question: given an arc $I = [\theta_1, \theta_2]$, how many pairs $(m, n)$ (with $\gcd(m, n) = 1$, where $m$ and $n$ have opposite parity, and where $m^2 + n^2 \leq H$) project to the arc $I$ under $m+in \mapsto (m+in)/\lvert m + in \rvert$? We want to show that the answer to this question is linear in the length of the arc $I$; this would give the required equidistribution for $m + in$, and thus for our initial question.

The points $m + in$ form the typical $\mathbb{Z}^2$ lattice when $m$ and $n$ are unconstrained. We can handle the gcd condition later, but the opposite parity condition is annoying. Points $m+in$ when $m$ and $n$ are constrained to have opposite parity *do not* form a lattice. For example, $(1, 2) + (1, 2) = (2, 4)$, which is unfortunate.

But points $m + in$ where $m$ and $n$ are constrained to have **the same** parity do form a lattice. Let $\Lambda_1$ be the typical $\mathbb{Z}^2$ lattice formed from all $m + in$ as $m, n$ range across $\mathbb{Z}$. Let $\lambda_2$ be the lattice formed from $m + in$ where $m, n$ have the same parity. The points we are interested in are precisely those points in $\Lambda_1 \backslash \Lambda_2$.

Now we ask: which points in $\Lambda_1$ and $\Lambda_2$ project to a given arc under the projection map $z \mapsto z/\lvert z \rvert$, and have $\lvert z \rvert \leq H$? These are precisely the points contained within the region

$$

\Omega_H =

\{ re^{i\theta} : 0 \leq r \leq H, \theta_1 \leq \theta \leq \theta_2 \}.

$$

For a given lattice $\Lambda$, we can mimic Gauss’s heuristic for the Gauss Circle Problem to approximate the number of points $N(H; \Lambda)$ contained within the region $\Omega_H$. The Gaussian heuristic gives the estimate

$$

N(H; \Lambda) = \mathrm{Area}(\Omega_H) \cdot \rho(\Lambda)

+ O(\lvert \delta \Omega_H \rvert) + O(1),

$$

where $\rho(\Lambda)$ is the density of the lattice $\Lambda$ (how many lattice points there are per unit square, on average), and where $\lvert \delta \Omega_H \rvert = O(H)$ is the length of the boundary of the region $\Omega_H$.

The density of $\Lambda_1$ is $1$. The density of $\Lambda_2$ is $1/2$. Thus the number of points $(m, n)$ with $m, n$ having opposite parity that project to the arc $I$ and which have $m^2 + n^2 \leq H^2$ is given by

$$

N(H) = \mathrm{Area}(\Omega_H) \cdot \tfrac{1}{2}

+ O(H) + O(1).

$$

Finally, we restrict attention to primitive points (equivalently, points where $\gcd(m, n) = 1$) through an inclusion-exclusion argument. Notice that if $(n, m)$ is a point in our region, then the points $(3n, 3m)$, $(5n, 5m)$, and so on are also in the region. (But **not** the point $(2n, 2m)$, as this violates the parity constraint).

To remove them, we can thus use inclusion-exclusion (e.g. remove points such that $(3n, 3m)$ are counted, and points such that $(5n, 5m)$ are counted, but then add back in points such that $(15n, 15m)$ should be counted, etc.). This is accomplished by the mobius sum $$\widetilde{N}(H) = \sum_{d \leq H, 2 \nmid d} \mu(d) N(h/d).$$

From the Gaussian heuristic and the fact that $\mathrm{Area}(\Omega_H) =A H^2$ for the constant $A = \pi \cdot (\theta_2 – \theta_1)/2\pi$, we have that

$$\widetilde{N}(H)

= A H^2 \cdot \frac{1}{2} \sum_{d \leq H, 2 \nmid d} \frac{\mu(d)}{d^2} + O\Big( \sum_{d \leq H}

\frac{H}{d} \Big) + O(H).

$$

The error term is of size $O(H \log H)$. The main can be understood by extending the sum to all $d \geq 1$ with $2 \nmid d$. This introduces an error term bounded by

$$

\sum_{d \geq H} \frac{H^2}{d^2} \ll H,

$$

which is swallowed by the other error term. And thus we have that

$$\widetilde{N}(H) = \pi\frac{\theta_2 – \theta_1}{2\pi} \frac{H^2}{2} \sum_{d \geq

1, 2 \nmid d} \frac{\mu(d)}{d^2} + O(H \log H).$$

The sum is exactly $$\frac{1}{\zeta^{(2)}(2)} = \frac{8}{\pi^2},$$ where $\zeta^{(2)}(s)$ is the Riemann zeta function, but with the $2$-factor of the Euler product removed. This gives the evaluation $$\widetilde{N}(H) = \frac{\theta_2 – \theta_1}{2\pi} H^2 \frac{4}{\pi} + O(H \log H).$$

And thus the number of points that project to the arc $I$ is linear in the length of the arc, as expected. The points equidistribute as claimed.

From the relationship $(x + iy) = (1 + i)(m – in)^2$, an arc of length $\ell$ in $(m, n)$ coordinates will correspond to an arc of length $2\ell$ in $(x + iy)$ coordinates.

On the other hand, $N(H)$ as defined above counted all $n, m$ of opposite parity, with $n^2 + m^2 \leq H^2$, such that $m+in$ projected to the arc $I$. This includes points with $m$ coordinate positive and negative. But from the analysis of primitive parameters above, we see that this double counts actual lattice points $x + iy$ (as $(-m, -n)$ and $(m, n)$ correspond to the same lattice point).

These two facts are deeply related. The effect is that the asymptotic $\widetilde{N}(H)$ above counts lattice points in $(x, y)$ coordinates. (That is, the doubling of the arc length and the double-counting of points cancel each other).

It follows that if we were to take an arc of length $2\pi$, i.e. take the whole circle, we have computed that there will be

$$

\widetilde{N}(H) = \frac{4}{\pi}H^2 + O(H \log H)

$$

points in the circle.

We can compute this in another way.

Let $A(b)$ denote the number of rational points on $x^2 + y^2 = 2$ of the (reduced) form $(a/b, c/b)$. We see that

$$

\sum_ {d \mid b} A(d)= \#\{(a, c) \in \mathbb{Z}^2 : a^2 + c^2 = 2b^2\} = r_ 2(2b^2) = r_ 2(b^2),

$$

where $r_2(n)$ is the number of ways of writing $n$ as a sum of $2$ squares. The function $r_2(n)/4$ is multiplicative, and we can compute the Dirichlet series

$$

\sum _{n \geq 1} \frac{A(n)}{n^s} =

\frac{4 \zeta(s) L(s, \chi _4)}{(1 + 2^{-s})\zeta(2s)},

$$

where $\chi _4 = (\frac{-1}{\cdot})$ is the non-trivial character of modulus $4$. This can be seen upon comparing Euler products.

A simple application of Perron’s formula then shows that the number of rational points on $x^2 + y^2 = 2$ of the (reduced) form $(a/b, c/b)$ with $b \leq X^2$ is

$$

\sum _{b \leq X^2} A(b) =

\frac{4}{\pi} X^2 + O(X^{\frac{4}{3} + \epsilon}).

$$

The leading asymptotics agree! (And a more sophisticated analysis in the Perron estimate would allow one to lower the error there).

To see a current visualization, look at this modular form page. The image from that page (as it is currently) looks like this.

This is a plot on a disk model. To make sense of this plot, I note that the real axis in the upper-half-plane model is the circumference of the circle, and the imaginary axis in the upper-half-plane model is the vertical diameter of the circle. In particular, $z = 0$ is the bottom of the circle, $z = i$ is the center of the circle, and $z = \infty$ is the top of the circle. The magnitude is currently displayed — the big blue region is where the magnitude is very small. In a neighborhood of the blue blob, there are a few bands of color that are meaningful — but then things change too quickly and the graph becomes a graph of noise.

I propose one of the following alternatives. I maintain the same badge and model for the space, but I change what is plotted and what colors to use. Also, I plot them larger so that we can get a good look at them; for the LMFDB they would probably be produced at the same (small) size.

I have made three plots with contours. They are all morally the same, except for the underlying colorscheme. The “default” sage colorscheme leads to the following plot.

The good thing is that it’s visually striking. But I recently learned that this colorscheme is hated, and it’s widely thought to be a poor choice in almost every situation.

A little bit ago, matplotlib added two colorschemes designed to fix the problems with the default colorscheme. (sage’s preferences are behind — the new matplotlib default has changed). This is one of them, called *twilight*.

I’ve also prepared these plots without the contours, and I think they’re quite nice as well.

First *jet.*

Then *twilight*. At the talk I recently gave, this was the favorite — but I hadn’t yet implemented the contour-plots above for non-default colorschemes.Then *viridis.* (I’m still not serious about this one — but I think it’s pretty).Note on other Possibilities

There are other possibilities, such as perhaps plotting on a portion of the upper half-plane instead of a disk-model. I describe a few of these possibilities and give examples in the notes from my last talk. I should note that I can now produce contour-type plots there as well, though I haven’t done that.

For fun, here is the default colorscheme, but rotated. This came about accidentally (as did so many other plots in this excursion), but I think it highlights how odd jet is.

This concludes my proposal. I am collecting opinions. If you are struck by an idea or an opinion and would like to share it with me, please let me know, email me, or leave a comment below.

]]>This is a talk heavily inspired by the ICERM semester program on Illustrating Mathematics (currently wrapping up). In particular, I draw on^{2} conversations with Frank Farris (about using color to highlight desired features), Elias Wegert (about using logarithmically scaling contours), Ed Harriss (about the choice of colorscheme), and Brendan Hassett (about overall design choices).

There are very many pictures in the talk!

Here are the slides for the talk.

I wrote a few different complex-plotting routines for this project. At their core, they are based on sage’s complex_plot. There are two major variants that I use.

The first (currently called “ccomplex_plot”. Not a good name) overwrites how sage handles lightness in complex_plot in order to produce “contours” at spots where the magnitude is a two-power. These contours are actually a sudden jump in brightness.

The second (currently called “raw_complex_plot”, also not a good name) is even less formal. It vectorizes the computation and produces an object containing the magnitude and argument information for each pixel to be drawn. It then uses numpy and matplotlib to convert these magnitudes and phases into RGB colors according to a matplotlib-compatible colormap.

I am happy to send either of these pieces of code to anyone who wants to see them, but they are very much written for my own use at the moment. I intend to improve them for general use later, after I’ve experimented further.

In addition, I generated all the images for this talk in a single sagemath jupyter notebook (with the two .spyx cython dependencies I allude to above). This is also available here. (Note that using a service like nbviewer or nbconvert to view or convert it to html might be a reasonable idea).

As a final note, I’ll add that I mistyped several times in the preparation of the images for this talk. Included below are a few of the interesting-looking mistakes. The first two resulted from incorrectly applied conformal mappings, while the third came from incorrectly applied color correction.

]]>Inspired by the images and ideas of Elias Wegert, I thought it might be interesting to attempt to implement a version of his colorizing technique for complex functions in sage. The purpose is ultimately to revisit how one plots modular forms in the LMFDB (see lmfdb.org and click around to see various plots — some are good, others are less good).

The challenge is that plotting a function from $\mathbb{C} \longrightarrow \mathbb{C}$ is that the graph is naturally 4-dimensional, and we are very bad at visualizing 4d things. In fact, we want to use only 2d to visualize it.

A complex number $z = re^{i \theta}$ is determined by the magnitude ($r$) and the argument ($\theta$). Thus

one typical approach to represent the value taken by a function $f$ at a point $z$ is to represent the magnitude of $f(z)$ in terms of the brightness, and to represent the argument in terms of color.

For example, the typical complex space would then look like the following.

In [1]:

```
P = complex_plot(x, [-2, 2], [-2, 2])
P.axes(False)
P.show()
```

To get an idea for a slightly more complicated plot, we might look at $z^2(z-0.5)(z-0.5i)$

In [2]:

```
complicated_func = x**2 * (x - 0.5) * (x - 0.5*i)
```

In [3]:

```
P = complex_plot(complicated_func, [-2, 2], [-2, 2])
P.axes(False)
P.show()
```

In [4]:

```
def normalize(complexval):
return 2*exp(2 * pi * i * complexval.abs())
```

In [5]:

```
f = lambda x: normalize(x)
P = complex_plot(f, [-2, 2], [-2, 2])
P.axes(False)
P.show()
```

Doing this with our slightly more complicated function gives

In [6]:

```
f = lambda x: normalize(complicated_func(x))
P = complex_plot(f, [-2, 2], [-2, 2], plot_points=200)
P.axes(False)
P.show()
```