We have a (Hermitian) matrix of some finite dimension (n) whose elements are functions of real variables x and y. We wish to plot contours of the spectrum (level sets of the n real eigenvalues) at chosen values.

Here's a simple solution using ContourPlot:

matrix = Table[3 i x + j y, {i, 5}, {j, 5}]; 
ContourPlot[Sort@Re@Eigenvalues[matrix], {x, -2, 2}, {y, -2, 2},Contours->{0.3, 1.7}] /. _Polygon -> Sequence[]  

To be honest, I am not quite sure why this does work--although it does--as the syntax does not appear to follow the documentation for ContourPlot precisely. Here, the argument of ContourPlot is an 5-dimensional list of eigenvalues, presumably sampled at some point in the x-y domain. Using PlotPoints seems to increase the grain size in the domain mesh.

Also, obviously in this example, the eigenvalues have analytic closed-form expressions as functions of x and y, but in my general problem, that is not possible. However, this ContourPlot method has worked in the past nonetheless.

However, I wish to discretize this process manually using ListContourPlot. I hope to gain the ability to manually control the domain and mesh size and also make the contour plotting significantly faster (the ContourPlot version above is quite slow in the real problem).

I am really struggling with the syntax of ListContourPlot, though. Note that the matrix we examine is given. I need to

  1. Construct a domain (presumably a List of Lists like {0.234,-0.412}, etc., a list of {x,y} points in the domain).
  2. Numerically evaluate the Eigenvalues of the matrix at every point in the domain, and store these results (n-dimensional lists) somehow.
  3. Compile the many eigenvalue lists (one at every site in the discrete domain) into a complex array which fits the syntax for ListContourPlot
  4. Perform the ListContourPlot and isolated chosen level sets using the Contours option.

The start of a weak working example

matrix = Table[3 i x + j y, {i, 5}, {j, 5}];
domain = Table[{x, y}, {x, -1, 1, 0.5}, {y, -1, 1, 0.5}];
II = Dimensions[domain][[1]];
JJ = Dimensions[domain][[2]];
array = domain;
Do[array[[i, j]] = {array[[i, j, 1]], array[[i, j, 2]], 
   matrix, {x -> domain[[i, j, 1]], 
    y -> domain[[i, j, 2]]}]]}, {i, 1, II}, {j, 1, JJ}]

This is my best effort so far. However, I'm certain that someone can help me find much more elegant solutions to many of these steps.

  1. I build a domain using Table, but this could definitely be improved. For example, suppose I wished to use all points (x,y) on a square lattice with some density which lie within a Polygon instead of a simple rectangle?

  2. This point is at least accomplished in array, which contains a matrix of lists {x,y,{eigenvalues}}

  3. However, this part is a huge failure. The syntax is not commensurable with ListContourPlot in the slightest, so we've really accomplished little.

Please help!

  • $\begingroup$ does a contour represent the locus where "any" eigenvalue is equal to some specified value? As noted your first example is not a documented usage and its not really clear what its doing. $\endgroup$
    – george2079
    Mar 28, 2016 at 23:24
  • $\begingroup$ Yes, the contours should represent level sets of any eigenvalue in the spectrum. So the contour at value 1.35 should represent the set (disjoint union of 1-dimensional closed curves) of all points in the x,y plane where there is an eigenvalue with value 1.35. $\endgroup$
    – Steve
    Mar 29, 2016 at 21:08

1 Answer 1


here is one approach: create a separate plot for each contour and combine.

matrix = Table[3 i x + j y, {i, 5}, {j, 5}];
domain = Table[{x, y}, {x, -2, 2, 0.05}, {y, -2, 2, 0.05}]; 
cp[lambda_, color_] := ListContourPlot[Flatten[Map[ Append[#,
             matrix /. { x -> #[[1]] , y -> #[[2]]  } ], _Real]
          - lambda , 
         Abs, 1]]] & , domain, {2}], 1], Contours -> {0},
  ContourShading -> None, ContourStyle -> color]
contours = Range[-5, 5];
cf = ColorData["DarkRainbow"];
  cp[contours[[i]], cf[i/Length@contours]], {i, Length@contours}]]

enter image description here

note this is based on the real eigenvalues, not the real parts of all the eigenvalues. You can just stick a Re in there if that's what you really want.

for reference here is the ContourPlot version with the same contours. (this takes a long time with PlotPoints->100)

matrix = Table[3 i x + j y, {i, 5}, {j, 5}];
  Sort@Cases[Chop@Eigenvalues[matrix], _Real], {x, -2, 2}, {y, -2, 2},
   Contours -> Range[-5, 5], PlotPoints -> 100] /. _Polygon -> 

enter image description here

obviously similar. Not sure why my version has that extra set of bands.

  • $\begingroup$ Since the OP claims his matrix is Hermitian, the eigenvalues ought to be always real. $\endgroup$ Mar 29, 2016 at 14:20
  • $\begingroup$ @J.M. not so for this example. Actually those spurious bands are in the region where there are complex eigenvalues. I guess not worth worrying about since its a toy example. $\endgroup$
    – george2079
    Mar 29, 2016 at 14:58
  • $\begingroup$ Unfortunately, your discrete version above gives errors (despite the Quiet) and does not work for me. Your continuous code below works, (but is quite slow, as you mentioned). edit: This is because MinimalBy was added in mma version 10, but I am using only version 9.0 $\endgroup$
    – Steve
    Mar 29, 2016 at 21:26
  • $\begingroup$ In the real problem, all of the matrices I care about are indeed Hermitian. I should have given a Hermitian toy example, sorry. However, numerical machine error will often give eigenvalues with imaginary parts on the order of 10^(-17), etc., so I remove these confusions typically by just using a Re. $\endgroup$
    – Steve
    Mar 29, 2016 at 21:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.