Skip to main content

plotting - How to align 3 plots horizontally without spacing?


Suppose I have 3 plots a, b and c, where


a = Plot[x, {x, 0, 1}, Frame -> True, 
FrameTicks -> {{All, None}, {All, None}}, PlotRangePadding -> None];
b = Plot[-x, {x, 1, 2}, Frame -> True,
FrameTicks -> {{None, All}, {All, None}}, PlotRangePadding -> None];

c = Plot[-2 + 3 x, {x, 2, 2.5}, Frame -> True,
FrameTicks -> {{None, All}, {All, None}}, PlotRangePadding -> None,
Frame -> True, FrameTicks -> All];

Now I want to combine them into one, exactly as what this figure depicts. chirs That is, the final result looks like this, on which the lines connected to each other:


this


I tried to use this plotGrid function here:


plotGrid[{{a, b, c}}, 500, 300, ImagePadding -> 40]

However, the function is intentionally written for even width figures. What I want to do is different width, proportional to each plot's x ranges, i.e., width of a$:$b$:$c=$1:1:0.5$. I have also tried other ways like this:



c = Plot[-2 + 3 x, {x, 2, 2.5}, Frame -> True, 
FrameTicks -> {{All, All}, {All, All}}, PlotRangePadding -> None,
Frame -> True, FrameTicks -> All, AspectRatio -> 2];
Row[Show[#, ImagePadding -> {{0, 0}, {20, 20}}] & /@ {a, b, c}]

It works but I need to adjust the figure manually, how can I make it automatically?


=======


If the above question is solved, what if I change the code to


a = Plot[-x, {x, 0, 1}, Frame -> True, 
FrameTicks -> {{All, None}, {All, None}}, PlotRangePadding -> None]

b = Plot[x, {x, 1, 2.5}, Frame -> True,
FrameTicks -> {{None, All}, {All, None}}, PlotRangePadding -> None]
c = Plot[-2.5 + 3 x, {x, 2, 2.5}, Frame -> True,
PlotRangePadding -> None, ScalingFunctions -> {"Reverse", Identity}]

Actually this is the result I want.



Answer



Since you give an example of a bandstructure, I am going to provide the code I have used to generate them, instead of directly answering the question you asked. The code is part of a package at the end, but I will walk through the reasoning for the functions, first. My apologies if this is somewhat rambling, it was culled from a larger document.


Preliminaries


The goal is to create a plotting function that accepts a list of points, and labels, if desired, and displays a function, $f$, along the path connecting those points. By necessity, that entails crafting a Piecewise function, $g$, that we compose with the function to be plotted, $f\circ{g}$. Most of the support functionality is aimed at crafting that.



Support functions


There are five support functions: getVariables, multiDimComposition, makeFunction, arcLength, and paramPath.


getVariables


The built-in function Variables is specifically geared towards polynomials, so it cannot extract the variables from more "exotic" functions like


In[22]:= Sin[x y^2] // Variables
(*Out[22]= {Sin[x y^2]}*)

But, getVariables is able to extract the independent variables from most nested structures, e.g.


In[9]:= getVariables @ {Exp[f[x]], Sin[x y^2]}
(*Out[9]= {x, y}*)


In[10]:= getVariables[{Exp[f[x]], Sin[x y^2]}, Hold]
(*Out[10]= {Hold[x], Hold[y]}*)

Note, getVariables is intentionally not Listable, so that the above expression can be treated as a single function. As per usual, Map can be used, if this behavior is not desirable.


Multidimensional Composition


The built-in Composition cannot handle compositions, $f\circ{g}$, where $f:\mathbf{R}^M\to\mathbf{R}^N$ and $g:\mathbf{R}^N\to\mathbf{R}$. A simple example is


In[11]:= Clear[f, g]
f[x_, y_] := Sin[2 \[Pi] x y^2]
g[s_] := {s, s^3}

Composition[f, g][s]
(*Out[14]= f[{s, s^3}]*)

So, I created multiDimComposition which can


In[15]:= multiDimComposition[f, g][s]
(*Out[15]= Sin[2 \[Pi] s^7]*)

Or, more interestingly


GraphicsRow[{Show[
DensityPlot[f[x, y], {x, -1, 1}, {y, -1, 1}],

ParametricPlot[g[s], {s, -1, 1}, PlotStyle -> Black]
], Plot[multiDimComposition[f, g][s], {s, -1, 1}]}]

enter image description here


A more useful application is changing variables, for instance


In[9]:= Clear[f, g]
f[x_, y_, z_] := Exp[Sqrt[x^2 + y^2 + z^2]]
g[r_, t_, f_] := {r Sin[t] Cos[f], r Sin[t] Sin[f], r Cos[t]}
multiDimComposition[f, g][\[Rho], \[Theta], \[Phi]] //
Simplify[#, \[Rho] > 0] &

(*Out[12]= E^\[Rho]*)

As written, multiDimComposition has a flaw, as illustrated in the following:


In[13]:= multiDimComposition[f, {s, s^2}][s]
(*Out[13]= f[s]*)

So, it requires the use of functions, not expressions.


makeFunction


The function makeFunction takes an expression an turns it into a Function, e.g.


In[112]:= makeFunction[x^2]

(*Out[112]= Function[{x}, x^2]*)

In[113]:= Through @ (makeFunction /@ {x^2, Sin[x y^2], x + I y})[3, 4]
(*Out[113]= {9, Sin[48], 3 + 4 I}*)

By default, makeFunction lists the variables in the order they are encountered, but, for completeness, this can be overridden by supplying them in the second argument.


In[114]:= makeFunction[x^2,  {y, x}]
(*Out[114]= Function[{y, x}, x^2]*)

Interlude



At this point, there are enough support functions to create plotPath, and here are a few examples of its use at this stage:


plotPath[{Sin[2 \[Pi] x y^2], Cos[2 \[Pi] x y^2], Exp[x + y]}, 
{s, s^3}, {s, -1, 1}]

enter image description here


GraphicsRow[{
ContourPlot[Sin[x + y^2], {x, -3, 3}, {y, -2, 2},
Epilog -> {Thickness[Medium], Circle[{0, 0}]}],
plotPath[
Sin[x + y^2], {Cos[\[Theta]], Sin[\[Theta]]}, {\[Theta], 0,

2 \[Pi]}]}]

enter image description here


GraphicsRow[{
Show[
ContourPlot[Sin[x + y^2], {x, -3, 3}, {y, -2, 2}],
Plot[x^2, {x, -3, 3},
PlotStyle -> Directive[Thickness[Medium], Black]],
PlotRange -> {-2, 2}
],

plotPath[Sin[x + y^2], {x, x^2}, {x, -3, 3}]}]

enter image description here


But, that is unwieldy, and does not quite allow us to make a bandstructure. We need two additional functions.


arcLength and paramPath


Since writing this, there has been an ArcLength function added, but it only works along a known parameterization, and this application needs a way to calculate the length along line segments connected by known points, e.g.


In[139]:= arcLength[{{0, 0}, {1, 0}}]
arcLength[{{0, 0}, {1, 0}, {1, 1}}]
arcLength[{{0, 0}, {1, 0}, {1, 1}, {0, 0}}]
(*Out[139]= 1

Out[140]= 2
Out[141]= 2 + Sqrt[2] *)

Then, we can combine that with a function that will parameterize such a path, and we can do some interesting things.


{path, length} = {paramPath[#][s], 
arcLength[#]} &@{{{0, 0, 0}, "\[CapitalGamma]"}, {{1, 0, 0},
"X"}, {{1, 1, 0}, "M"}, {{0, 0, 0},
"\[CapitalGamma]"}, {{1, 1, 1}, "R"}, {{1, 0, 0},
"X"}, {{1, 1, 0}, "M"}, {{1, 1, 1}, "R"}}[[All, 1]];


ParametricPlot3D[path, {s, 0, length}]

enter image description here


This is still a bit unwieldy, though:


\[CurlyEpsilon][kx_, ky_] := - 2 (Cos[\[Pi] kx] + Cos[\[Pi] ky])
plotPath[\[CurlyEpsilon][kx, ky],
Evaluate[paramPath[{{0, 0}, {1, 0}, {1, 1}, {0, 0}}][s]], {s, 0,
arcLength[{{0, 0}, {1, 0}, {1, 1}, {0, 0}}]}, Frame -> True]

enter image description here



So, we need to add a little syntactic sugar, as shown in the examples, below.


Examples


Single s-orbital with nearest neighbor hopping


plotPath[-2 ( Cos[\[Pi] kx] + Cos[\[Pi] ky] ), {{{0, 0}, 
"\[CapitalGamma]"}, {{1, 0}, "M"}, {{1, 1}, "X"}, {{0, 0},
"\[CapitalGamma]"}},
Frame -> True,
FrameTicks -> {{#, #} & @
Thread[{Range[-4, 4, 2], Range[-2, 2] "t"}], {Automatic,
Automatic}}

]

s-orbitals


P-orbitals with nearest neighbor hopping


Another example is p-orbitals also on a square lattice. This has two parameters, p\[Sigma] and p\[Pi], representing the two types of bonds. Note, that this function is multivalued.


orbitals = 
2 {p\[Sigma] Cos[\[Pi] kx] + p\[Pi] Cos[\[Pi] ky],
p\[Pi] Cos[\[Pi] kx] + p\[Sigma] Cos[\[Pi] ky],
p\[Pi] (Cos[\[Pi] kx] + Cos[\[Pi] ky])};
(* Setting -3 p\[Pi] \[Equal] p\[Sigma] \[Equal] 1 for convenience *)

\
plotPath[Evaluate[% /. {p\[Pi] -> -1/3, p\[Sigma] -> 1}], {{{0, 0},
"\[CapitalGamma]"}, {{1, 0}, "M"}, {{1, 1}, "X"}, {{0, 0},
"\[CapitalGamma]"}},
Frame -> True]

p-orbitals


One primary observation from these multi-orbital Hamiltonians is the splitting of the orbitals as k changes, and this is directly related to how the local symmetry is changing with respect to k. The points where the $\pi$-orbitals cross the $\sigma$-orbital are likely accidental degeneracies as they have different group representations.


D-orbitals with nearest neighbor hopping


Or, d-orbitals on the same lattice. Note, this explicitly requires solving for the eigenvalues.



plotPath[
Evaluate[
Eigenvalues[{{1/
2 (dd\[Delta] + 3 dd\[Sigma]) (Cos[kx \[Pi]] + Cos[ky \[Pi]]),
0, 0, 0,
1/2 Sqrt[
3] (dd\[Delta] - dd\[Sigma]) (Cos[kx \[Pi]] - Cos[ky \[Pi]])},
{0, 2 dd\[Pi] (Cos[kx \[Pi]] + Cos[ky \[Pi]]), 0, 0, 0},
{0, 0, 2 (dd\[Pi] Cos[kx \[Pi]] + dd\[Delta] Cos[ky \[Pi]]), 0,
0},

{0, 0, 0, 2 (dd\[Delta] Cos[kx \[Pi]] + dd\[Pi] Cos[ky \[Pi]]),
0},
{1/2 Sqrt[
3] (dd\[Delta] - dd\[Sigma]) (Cos[kx \[Pi]] - Cos[ky \[Pi]]),
0, 0, 0,
1/2 (3 dd\[Delta] + dd\[Sigma]) (Cos[kx \[Pi]] +
Cos[ky \[Pi]])}} /. {dd\[Sigma] -> 1, dd\[Pi] -> -1/2,
dd\[Delta] -> 1/3}]
],
{{{0, 0}, "\[CapitalGamma]"}, {{1, 0}, "M"}, {{1, 1}, "X"}, {{0, 0},

"\[CapitalGamma]"}},
Frame -> True]

d--orbitals


Package


BeginPackage["PlotPath`"];
getVariables;
multiDimComposition;
makeFunction;
variableList;

arcLength;
paramPath;
plotPath;

Begin["`Private`"];

Clear[getVariables]
SetAttributes[getVariables, HoldFirst];
getVariables[expr_, f_:Identity,
Optional[excludedContexts:{__String},{"System`"}]]:=

Cases[Unevaluated[expr],
a_Symbol/;!(MemberQ[excludedContexts, Context[a]] || MemberQ[Attributes[a], Locked | ReadProtected]) :> f[a],
{0, Infinity}
]//DeleteDuplicates

Clear[multiDimComposition]
multiDimComposition[flst__]:=
With[{fcns = Reverse@List[flst]},Fold[#2[ Sequence @@ #1 ]&, First[fcns][##], Rest[fcns]]&]

Clear[makeFunction];

SetAttributes[makeFunction, HoldAll];

(* This first form allows pure functions to be used *)
makeFunction[afcn_Function, _.]:= afcn
makeFunction[fexpr_] := makeFunction[fexpr, Automatic]
makeFunction[fexpr_, vars:{__Symbol}|Automatic]:=
Module[{ivars = Hold[vars]},
ivars = If[ivars===Hold[Automatic],
(* GetVariables returns {Hold[x_] ..} we want Hold[{x_ ..}] *)
Distribute[Sort[getVariables[fexpr, Hold]], Hold],

ivars
];
Function @@ Join[ivars, Hold[fexpr]]
]


Clear[plotPath];
Options[plotPath] = Options[Plot];

plotPath[fcn:Except[_List],args__]:=plotPath[{fcn},args]

plotPath[fcns_List, params_, {s_Symbol, smin_,smax_}, opts:OptionsPattern[]]:=
With[{pfcn=makeFunction[params], fcnlst = makeFunction/@fcns},
Plot @@ {
multiDimComposition[#,pfcn][s]& /@ fcnlst,
{s,smin,smax},
FilterRules[{opts},Options[Plot]]
}
]



Clear[arcLength];
arcLength[p1_List, p2_List]/; (Length[p1]==Length[p2]):=Norm[p2 - p1]
arcLength[p:{_List ..}]/; Check[Transpose[p];True, False]:= Plus @@ arcLength @@@ Partition[p,2,1]

Clear[paramPath]
paramPath[p1_List, p2_List][s_]/;
(Length[p1]>= 2 && Length[p2]>= 2 && Length[p1] == Length[p2]):=
p1 + s (p2 - p1)/Norm[p2 - p1]



paramPath[p:{_List ..}][s_] /; Check[Transpose[p];True, False] :=
Block[{ptpairs = Partition[p, 2, 1], conds, paths, dists},
dists = {0}~Join~Accumulate[arcLength@@@ptpairs];
conds = dists // Partition[#,2,1]&;
paths = paramPath[Sequence @@ #[[1]] ][s - #[[2]] ]& /@
Thread[List[ptpairs, Most[dists]] ] // Transpose;
(*
This creates seperate Piecewise functions, one for the x, y, etc. coords,
respectively.
*)

Piecewise[ {#[[1]], #[[2,1]]<= s <= #[[2,2]]}& /@ Thread[List[#, conds]]]& /@ paths
]


(* Accepts lists of points *)
plotPath[fcn_, pts_List, opts:OptionsPattern[]]:=
Module[{s},plotPath[fcn, paramPath[ pts ][s], {s, 0, arcLength[pts]}, opts]]

(* Accepts points plus labels *)
plotPath[fcn_, pts:{{_List, _String} ..}, opts:OptionsPattern[]]:=

Module[{s, xticks, rls, ticks, xgrid, grid,tname},
(* generate tick marks/gridlines for the labels*)
xgrid = {0}~Join~Accumulate[arcLength@@@Partition[pts[[All,1]], 2,1]];
xticks = Thread[{xgrid,pts[[All,2]]}];
(* Substitute in tick and grid specifications *)
tname = If[OptionValue[Frame], FrameTicks,Ticks];
ticks = OptionValue[tname ];
ticks = tname -> Which[
ticks === None (* Don't override this one only *),
None,

ticks === Automatic,
{xticks, Automatic},
True,
MapAt[#/.Automatic-> xticks&, ticks, If[OptionValue[Frame], 2, 1]]
];
grid = GridLines -> If[
OptionValue[GridLines]===Automatic || OptionValue[GridLines]===None,
{xgrid, None},
MapAt[#/.Automatic -> xgrid&,OptionValue[GridLines],1]
];

rls = {ticks, grid,FilterRules[List@opts, Except[{Ticks, FrameTicks}]]};
plotPath[fcn, Evaluate[pts[[All,1]]], Evaluate[rls]]
]
End[(*`Private`*)];
EndPackage[(*PlotPath*)];

Comments

Popular posts from this blog

plotting - Filling between two spheres in SphericalPlot3D

Manipulate[ SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, Mesh -> None, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], {n, 0, 1}] I cant' seem to be able to make a filling between two spheres. I've already tried the obvious Filling -> {1 -> {2}} but Mathematica doesn't seem to like that option. Is there any easy way around this or ... Answer There is no built-in filling in SphericalPlot3D . One option is to use ParametricPlot3D to draw the surfaces between the two shells: Manipulate[ Show[SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], ParametricPlot3D[{ r {Sin[t] Cos[1.5 Pi], Sin[t] Sin[1.5 Pi], Cos[t]}, r {Sin[t] Cos[0 Pi], Sin[t] Sin[0 Pi], Cos[t]}}, {r, 1, 2 - n}, {t, 0, Pi}, PlotStyle -> Yellow, Mesh -> {2, 15}]], {n, 0, 1}]

plotting - Plot 4D data with color as 4th dimension

I have a list of 4D data (x position, y position, amplitude, wavelength). I want to plot x, y, and amplitude on a 3D plot and have the color of the points correspond to the wavelength. I have seen many examples using functions to define color but my wavelength cannot be expressed by an analytic function. Is there a simple way to do this? Answer Here a another possible way to visualize 4D data: data = Flatten[Table[{x, y, x^2 + y^2, Sin[x - y]}, {x, -Pi, Pi,Pi/10}, {y,-Pi,Pi, Pi/10}], 1]; You can use the function Point along with VertexColors . Now the points are places using the first three elements and the color is determined by the fourth. In this case I used Hue, but you can use whatever you prefer. Graphics3D[ Point[data[[All, 1 ;; 3]], VertexColors -> Hue /@ data[[All, 4]]], Axes -> True, BoxRatios -> {1, 1, 1/GoldenRatio}]

plotting - Mathematica: 3D plot based on combined 2D graphs

I have several sigmoidal fits to 3 different datasets, with mean fit predictions plus the 95% confidence limits (not symmetrical around the mean) and the actual data. I would now like to show these different 2D plots projected in 3D as in but then using proper perspective. In the link here they give some solutions to combine the plots using isometric perspective, but I would like to use proper 3 point perspective. Any thoughts? Also any way to show the mean points per time point for each series plus or minus the standard error on the mean would be cool too, either using points+vertical bars, or using spheres plus tubes. Below are some test data and the fit function I am using. Note that I am working on a logit(proportion) scale and that the final vertical scale is Log10(percentage). (* some test data *) data = Table[Null, {i, 4}]; data[[1]] = {{1, -5.8}, {2, -5.4}, {3, -0.8}, {4, -0.2}, {5, 4.6}, {1, -6.4}, {2, -5.6}, {3, -0.7}, {4, 0.04}, {5, 1.0}, {1, -6.8}, {2, -4.7}, {3, -1.