Energy band plotting [duplicate]

Is there some way in which I could plot energy bands using Mathematica in a manner that is given in the image below? I have $$E$$ as a function of $$k_x$$ and $$k_y$$. How can the plot given below be made with these specific points on the $$(k_x,k_y)$$ axis? My function for the energy $$E$$ is:

energy[kx_,ky_]:=Sqrt[1-(Cos[kx/2]Cos[ky/2])^2]

and I can plot parts of the graph with something like:

Plot[energy[kx,0],{kx,0,Pi}]
Plot[energy[kx,0],{kx,Pi,2 Pi}]

How do I stitch these together?

• Please add some functions you have defined and code you have tried. Sep 27 '18 at 16:23
• Don't forget to take the tour now and learning about asking and what's on-topic. There you will learn why you should edit your question to show due diligence, give brief context that is meaningful for non-physicist, include minimal working example of code and data in formatted form. By doing all this you help us to help you and likely you will inspire great answers. Not doing that risks getting you question closed as off-topic. Sep 27 '18 at 16:42
• I have tried setting ky=0, and then Plot[E[kx,0],{kx,0,Pi}], and I get one branch of that whole graph. Is there a way to concatenate all these parts with one plotting? Sep 27 '18 at 16:44
• Give me an hour or two, I have existing code for this, but it needs a little polishing to post. Sep 27 '18 at 17:03

Construct an Interpolation function that translates from the $$x$$-value to the $$\{k_x,k_y\}$$ coordinates:

xkData = {{0,{Pi,0}},{1,{0,0}},{2,{Pi,-Pi}},{3,{Pi,0}},{4,{2Pi,0}}};
if = Interpolation[xkData, InterpolationOrder->1];

Then, use the above interpolating function to construct the plot, and use xkData again to create the ticks:

Plot[
energy @@ if[x],
{x, 0, 4},
Frame -> True,
FrameTicks->{
{Automatic,None},
{xkData, None}
},
GridLines->{Range[0,4], None}
] • Thank you very much! This is really useful. Sep 27 '18 at 17:15
• Can I add some points in specific parts of plot after creating this plot, say I want these points represented as black dots, and for example only in interval from (Pi,0) to (0,0)? Feb 11 '19 at 17:01

Compared to my old solution, Carl's is much better. But, there is a subtle flaw in it, and in the original image that the OP posted: the distances between the intervals are not identical. The correct parameterization is to use arc-length. Essentially, we need to Accumulate the arc-length between the points in k-space, as follows:

pts = {{π, 0}, {0, 0}, {π, -π}, {π, 0}, {2 π, 0}};
arcs = {0}~Join~Map[
ArcLength[Line[#]]&,
Rest@FoldList[Join[#1, {#2}] &, {First @ #}, Rest @ #]& @ pts
]
(* {0, π, π + Sqrt π, 2 π + Sqrt π, 3 π + Sqrt π} *)

xkData = Transpose[{arcs, pts}];
if = Interpolation[xkData, InterpolationOrder -> 1];
Plot[energy @@ if[x], {x, arcs[], arcs[[-1]]},
Frame -> True,
FrameTicks -> {{Automatic, None}, {xkData, None}},
GridLines -> {arcs, None}
] • The code doesn't seem to work on Mathematica 12, would you consider updating it? Jul 21 '21 at 2:16
• @Dwagg interesting. The original code relied on ArcLength[Line[{{Pi, 0}}]] returning 0. Now it just returns unevaluated. Fixed. Jul 21 '21 at 11:47

There have been some great answers, but I decided to add an alternative, which uses Piecewise and Rescale instead.

kList = {{\[Pi], 0}, {0, 0}, {\[Pi], -\[Pi]}, {\[Pi], 0}, {2 \[Pi],
0}};
xList = Range[0, 4, 1];

mapXToK[x_] :=
Piecewise@
MapThread[{Rescale[x, {#1, #2}, {#3, #4}], x < #2} &, {Most[xList],
Rest[xList], Most[kList], Rest[kList]}];

energy[kx_, ky_] := Sqrt[1 - (Cos[kx/2] Cos[ky/2])^2];

Plot[energy @@ mapXToK[x], {x, 0, 4}, GridLines -> {xList, None},
FrameTicks -> {Automatic, {Transpose[{xList, kList}], None}},
Frame -> True] Taking the arc-length length comment into account:

xList = Prepend[
Accumulate@ 