我用 LaTeX 寻找好的电磁波谱时,没有找到合适的,因此我需要创建自己的图像。下面是我创建图像的方法。
答案1
%
\documentclass[12pt]{article}
\usepackage[dvipsnames,table]{xcolor}
\usepackage{siunitx} % SI-units
\usepackage{pgfplots}
\usepgfplotslibrary{units} % to add units easily to axis
\usepgfplotslibrary{fillbetween} % to fill inbetween curves
\usepgfplotslibrary{colormaps} % to create colormaps
\pgfplotsset{width=12.2cm, height=7cm}
\pgfplotsset{compat=newest} %(making it only compatalbe with
%new releases of pgfplots)
\pgfdeclarehorizontalshading{visiblelight}{50bp}{
color(0.00000000000000bp)=(violet);
color(8.33333333333333bp)=(blue);
color(16.66666666666670bp)=(cyan);
color(25.00000000000000bp)=(green);
color(33.33333333333330bp)=(yellow);
color(41.66666666666670bp)=(orange);
color(50.00000000000000bp)=(red)
}%
\begin{document}
\begin{tikzpicture}[fill between/on layer={axis grid}]
\begin{axis}[
xlabel={Wavelength},
xticklabel style = {font=\tiny,yshift=0.2ex},
xmin=10^-5,
xmax=10^9,
x unit=\si{\micro\meter},
xmode=log,
ymin=0,
ymax=1,
height=3cm,
yticklabels={},
ytick=\empty,
legend cell align=left,
legend style={at={(0.85,-0.77)},anchor=north}
]
\addplot[draw=none, name path=start, forget plot] coordinates{(10^-5,0)(10^-5,1)};
\addplot[draw=none, name path=gamma, forget plot] coordinates{(10^-3,0)(10^-3,1)};
\addplot[draw=none, name path=xrays, forget plot] coordinates{(10^-2,0)(10^-2,1)};
\addplot[draw=none, name path=uv, forget plot] coordinates{(0.4,0)(0.4,1)};
\addplot[draw=none, name path=visible, forget plot] coordinates{(0.7,0)(0.7,1)};
\addplot[draw=none, name path=ir, forget plot] coordinates{(10^2.5,0)(10^2.5,1)};
\addplot[draw=none, name path=microwave, forget plot] coordinates{(10^5,0)(10^5,1)};
\addplot[draw=none, name path=radiowave, forget plot] coordinates{(10^9,0)(10^9,1)};
\addplot[violet!20, area legend] fill between[of=start and gamma];
\addlegendentry{$\gamma$-ray}
\addplot[violet!60, area legend] fill between[of=gamma and xrays];
\addlegendentry{X-ray}
\addplot[violet, area legend] fill between[of=xrays and uv];
\addlegendentry{Ultra violet}
\addplot[shading=visiblelight, area legend] fill between[of=uv and visible];
\addlegendentry{Visible light}
\addplot[red, area legend] fill between[of=visible and ir];
\addlegendentry{Infrared}
\addplot[Bittersweet, area legend] fill between[of=ir and microwave];
\addlegendentry{Micro wave}
\addplot[Brown, area legend] fill between[of=microwave and radiowave];
\addlegendentry{Radio wave}
\end{axis}
\end{tikzpicture}
\end{document}
示例输出:
答案2
基于现有的答案,我还创建了一种方法。它有一些问题可能需要解决,尤其是对于“可见光谱”刻度和底部颜色的名称。除了代码中已经指定的波长指数之外,它基本上对任何其他波长指数都不起作用。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc, positioning, shapes, backgrounds, fit, arrows}
\usepackage{pgf-spectra}
\usepackage{siunitx}
\usepackage{contour}
\begin{document}
\pgfdeclarehorizontalshading{visiblelight}{50bp}{% https://tex.stackexchange.com/a/348492/120853
color(0bp)=(violet!25);
color(8.33bp)=(blue!25);
color(16.67bp)=(cyan!25);
color(25bp)=(green!25);
color(33.33bp)=(yellow!25);
color(41.5bp)=(orange!25);
color(50bp)=(red!25)
}%
\begin{tikzpicture}[%
raylabel/.style={font=\scriptsize}
]
\def\minexponent{-6}
\def\maxexponent{6}
\def\spectrumheight{9em}
\pgfmathtruncatemacro{\nextminexponent}{\minexponent + 1}
% Main foreach loop, drawing the wavelengths as powers of 10 in an alternating fashion: even on top, odd at bottom. Then connects them with help lines
\foreach [count=\i, remember=\exponent as \previousexponent, evaluate=\i as \currentposition using int(\i/2)] \exponent in {\minexponent, \nextminexponent, ..., \maxexponent}{
\ifodd\exponent
\def\height{0}
\else
\def\height{\spectrumheight}
\fi
% Anchor at baseline to get all nodes on same baseline.
% https://tex.stackexchange.com/questions/133227/how-to-align-text-in-tikz-nodes-by-baseline#comment300863_133227
\node[anchor=base] (WAVELENGTH_\exponent) at (\exponent, \height) {\contour{white}{\num{e\exponent}}};
\ifnum\i > 1
\ifodd\i
\node (LABEL_\currentposition)
at ($(WAVELENGTH_\exponent)!0.5!(WAVELENGTH_\previousexponent)$)
{};% This is left as a node as opposed to coordinate: fill it out with '\currentposition' for debugging
\else
% Do not draw connection at exponent 1:
\pgfmathparse{\exponent != 1}% \pgfmathparse stores result (0 or 1) in macro \pgfmathresult
\ifnum\pgfmathresult = 1
\draw[help lines]
(WAVELENGTH_\previousexponent) --(WAVELENGTH_\exponent)
node[midway] (CONNECTION_\currentposition) {}% This is left as a node as opposed to coordinate: fill it out with '\currentposition' for debugging
coordinate[at start] (CONNECTION_\currentposition_START)
coordinate[at end] (CONNECTION_\currentposition_END);
\fi
\fi
\fi
}
% Create an arrow shape that fits around all relevant nodes, but do not draw it.
% Draw it manually later to leave out the 'bottom' of the arrow.
% We still need this invisible arrow for lining up of coordinates
\node[
single arrow,
single arrow head extend=0pt,
single arrow tip angle=150,% Inner angle of arrow tip
fit={([xshift=-3em]CONNECTION_1_START)(CONNECTION_1_END)(CONNECTION_\maxexponent_START)([xshift=5em]CONNECTION_\maxexponent_END)},
inner sep=0pt
]
(ARROW) {};
\node[align=center] (THERM) at ([yshift=3em]WAVELENGTH_1|-ARROW.after tail) {thermal\\radiation};% Only works because exponent 1 is between -1 and 3
\draw (THERM) -| ([yshift=-1.5em]WAVELENGTH_-1|-THERM);
\draw (THERM) -| ([yshift=-1.5em]WAVELENGTH_3|-THERM);
% On background layer so already drawn arrow and scale lines cover it up nicely
\begin{scope}[on background layer]
\node[
inner sep=0pt,
outer sep=0pt,
fit={([xshift=-2.2em]WAVELENGTH_0|-ARROW.after tail)([xshift=-2.2em]WAVELENGTH_1|-ARROW.before tail)}, shading=visiblelight]
(SMALL_VISIBLE_LIGHT) {};
\shade[
left color=white,
right color=violet!25,
middle color=violet!5,
outer sep=0pt
]
(CONNECTION_3_START) -- (CONNECTION_3_END) -- ([xshift=\pgflinewidth]SMALL_VISIBLE_LIGHT.south west) -- ([xshift=\pgflinewidth]SMALL_VISIBLE_LIGHT.north west) -- cycle;
\shade[
left color=red!25,
right color=white,
middle color=red!5,
outer sep=0pt,
]
(CONNECTION_5_START) -- (CONNECTION_5_END) -- ([xshift=-\pgflinewidth]SMALL_VISIBLE_LIGHT.south east) -- ([xshift=-\pgflinewidth]SMALL_VISIBLE_LIGHT.north east) -- cycle;
\end{scope}
% Some labels can be drawn automatically at the designated label coordinates:
\foreach [count=\i] \label in {
{Gamma\\rays},
{X-rays},
{},%Skip this one
{infrared}
}{
\node[raylabel, align=center] at (LABEL_\i) {\label};
}
% These do not fit the loop and are drawn manually:
\node[raylabel, align=right, anchor=north] at ([yshift=-1em]$(WAVELENGTH_-2)!0.45!(WAVELENGTH_0)$) {Ultra-\\violet};
\node[raylabel, fill=white] at (CONNECTION_6) {radio waves};
\node[raylabel, left=0.1em of CONNECTION_1, align=right] {cosmic\\rays};
\node[
draw,
fill=black!20,
below=4em of SMALL_VISIBLE_LIGHT,
align=center,
label=above:{\textbf{Visible Spectrum}}
] (FULL_VISIBLE_LIGHT) {%
\pgfspectra[width=13em,height=3em]\\%pgfspectra also has a builtin axis which of course much better than this terrible approach, but it is in nanometer
{\num{0.38} \hfill\num{0.48} \hfill\num{0.58}\hfill \num{0.68} \hfill\num{0.78}}\\
{\hfill blue \hspace{0.1em} green yellow \hfill red \hfill}
};
% Draw 'magnifying' trapeze, on background so it is covered by scale labels
\begin{scope}[on background layer]
\filldraw[help lines, fill=black!10] (FULL_VISIBLE_LIGHT.north east) -- (SMALL_VISIBLE_LIGHT.south east) -- (SMALL_VISIBLE_LIGHT.south west) -- (FULL_VISIBLE_LIGHT.north west) -- cycle;
\end{scope}
% Draw around arrow manually, leaving its tail open
\draw[draw, thick] (ARROW.after tail) -- (ARROW.before head) -- (ARROW.before tip) -- (ARROW.tip) -- (ARROW.after tip) -- (ARROW.after head) -- (ARROW.before tail);
\end{tikzpicture}
\end{document}
给出一个带有一些注释的电磁波谱,半自动生成:
答案3
这里我给出了一些已经很棒的答案的“改进”版本。主要区别在于,随着pgf-spectra
v2.1.1 现在也提供对数光谱。
由于图像中可见光的光谱非常小,因此差异很小,但在其他应用中可能非常有用。
\documentclass[border=5pt]{standalone}
\usepackage[dvipsnames,table]{xcolor}
\usepackage{siunitx}
\usepackage{pgf-spectra}
\usepackage{pgfplots}
\usepgfplotslibrary{
colormaps,
fillbetween,
units,
}
\pgfplotsset{
compat=1.18,
width=12.2cm,
height=3cm,
}
% % make the horizontal shading and set the UV and IR colors -->
% \pgfspectraStyle[gamma=.6] % uncomment to change the gamma
\wlcolor{380}\colorlet{UV}{wlcolor}%
\wlcolor{780}\colorlet{IR}{wlcolor}%
\pgfspectraplotshade[logarithmic, UVcolor=UV]{logvisiblelight}
\pgfspectraplotshade{visiblelight}
% \pgfspectraStyleReset% uncomment to reset the style
\begin{document}
\begin{tikzpicture}
\begin{axis}[
xmode=log,
xmin=1e-5,
xmax=1e9,
x unit=\si{\micro\meter},
xlabel={Wavelength},
xticklabel style={font=\tiny,yshift=0.2ex},
ymin=0,
ymax=1,
ytick=\empty,
legend cell align=left,
legend style={at={(0.85,-0.77)},anchor=north},
axis on top,
area legend,
]
\addplot [draw=none,forget plot,name path=start] coordinates {(1e-5,0)(1e-5,1)};
\addplot [draw=none,forget plot,name path=gamma] coordinates {(1e-3,0)(1e-3,1)};
\addplot [draw=none,forget plot,name path=xrays] coordinates {(1e-2,0)(1e-2,1)};
\addplot [draw=none,forget plot,name path=uv] coordinates {(0.38,0)(0.38,1)};
\addplot [draw=none,forget plot,name path=visible] coordinates {(0.78,0)(0.78,1)};
\addplot [draw=none,forget plot,name path=ir] coordinates {(10^2.5,0)(10^2.5,1)};
\addplot [draw=none,forget plot,name path=microwave] coordinates {(1e5,0)(1e5,1)};
\addplot [draw=none,forget plot,name path=radiowave] coordinates {(1e9,0)(1e9,1)};
\addplot [violet!20] fill between [of=start and gamma];
\addlegendentry{$\gamma$-ray}
\addplot [violet!60] fill between [of=gamma and xrays];
\addlegendentry{X-ray}
\addplot [UV!50,area legend] fill between [of=xrays and uv];
\addlegendentry{Ultra violet}
% forget this plot ...
\addplot [shading=logvisiblelight,forget plot] fill between [of=uv and visible];
% ... and add a legend image with the "normal"/non-log shading
% (why? Because we can :))
\addlegendimage{shading=visiblelight}
\addlegendentry{Visible light}
\addplot [IR!50,area legend] fill between [of=visible and ir];
\addlegendentry{Infrared}
\addplot [IR!50!Bittersweet] fill between [of=ir and microwave];
\addlegendentry{Micro wave}
\addplot [Brown] fill between [of=microwave and radiowave];
\addlegendentry{Radio wave}
\end{axis}
\end{tikzpicture}
\end{document}
\documentclass[border=5pt]{standalone}
\usepackage{contour}
\usepackage{tikz}
\usepackage{siunitx}
\usetikzlibrary{
arrows,
backgrounds,
calc,
fit,
positioning,
shapes,
}
\usepackage{pgf-spectra}
\begin{document}
\begin{tikzpicture}[
raylabel/.style={font=\scriptsize}
]
% % make the horizontal shading and set the UV and IR colors -->
% \pgfspectraStyle[gamma=.6] % uncomment to change the gamma
\wlcolor{380}\colorlet{UV}{wlcolor}
\wlcolor{780}\colorlet{IR}{wlcolor}
\pgfspectraplotshade[logarithmic,shade opacity=0.3]{visiblelight}
% \pgfspectraStyleReset % uncomment to reset the style
\def\minexponent{-6}
\def\maxexponent{6}
\def\spectrumheight{9em}
\pgfmathtruncatemacro{\nextminexponent}{\minexponent + 1}
% Main foreach loop, drawing the wavelengths as powers of 10 in an alternating
% fashion: even on top, odd at bottom. Then connects them with help lines
\foreach [
count=\i,
remember=\exponent as \previousexponent,
evaluate=\i as \currentposition using int(\i/2),
] \exponent in {\minexponent,\nextminexponent,...,\maxexponent}{
\ifodd\exponent
\def\height{0}
\else
\def\height{\spectrumheight}
\fi
\node [anchor=base] (WAVELENGTH_\exponent) at (\exponent, \height)
{\contour{white}{\num[print-unity-mantissa = false]{e\exponent}}};
\ifnum\i > 1
\ifodd\i
\node (LABEL_\currentposition)
at ($(WAVELENGTH_\exponent)!0.5!(WAVELENGTH_\previousexponent)$)
% This is left as a node as opposed to coordinate:
% fill it out with '\currentposition' for debugging
{}
;
\else
% Do not draw connection at exponent 1:
% (`\pgfmathparse` stores result (0 or 1) in macro `\pgfmathresult`)
\pgfmathparse{\exponent != 1}
\ifnum\pgfmathresult = 1
\draw[help lines]
(WAVELENGTH_\previousexponent) --(WAVELENGTH_\exponent)
% This is left as a node as opposed to coordinate:
% fill it out with '\currentposition' for debugging
node [midway] (CONNECTION_\currentposition) {}
coordinate [at start] (CONNECTION_\currentposition_START)
coordinate [at end] (CONNECTION_\currentposition_END);
\fi
\fi
\fi
}
% Create an arrow shape that fits around all relevant nodes, but do not draw it.
% Draw it manually later to leave out the 'bottom' of the arrow.
% We still need this invisible arrow for lining up of coordinates
\node [
single arrow,
single arrow head extend=0pt,
% Inner angle of arrow tip
single arrow tip angle=150,
fit={
([xshift=-3em]CONNECTION_1_START)
(CONNECTION_1_END)
(CONNECTION_\maxexponent_START)
([xshift=5em]CONNECTION_\maxexponent_END)
},
inner sep=0pt
]
(ARROW) {};
% Only works because exponent 1 is between -1 and 3
\node [align=center] (THERM) at ([yshift=3em]WAVELENGTH_1|-ARROW.after tail)
{thermal\\radiation};
\draw (THERM) -| ([yshift=-1.5em]WAVELENGTH_-1|-THERM);
\draw (THERM) -| ([yshift=-1.5em]WAVELENGTH_3|-THERM);
% On background layer so already drawn arrow and scale lines cover it up nicely
\begin{scope}[on background layer]
\node [
inner sep=0pt,
outer sep=0pt,
fit={
([xshift=-1.9em]WAVELENGTH_0|-ARROW.after tail)
([xshift=-3em]WAVELENGTH_1|-ARROW.before tail)
},
shading=visiblelight,
] (SMALL_VISIBLE_LIGHT) {};
\shade [
left color=white,
right color=UV!25,
middle color=UV!5,
outer sep=0pt
] (CONNECTION_3_START)
-- (CONNECTION_3_END)
-- ([xshift=\pgflinewidth]SMALL_VISIBLE_LIGHT.south west)
-- ([xshift=\pgflinewidth]SMALL_VISIBLE_LIGHT.north west)
-- cycle
;
\shade [
left color=IR!25,
right color=white,
middle color=IR!5,
outer sep=0pt,
] (CONNECTION_5_START)
-- (CONNECTION_5_END)
-- ([xshift=-\pgflinewidth]SMALL_VISIBLE_LIGHT.south east)
-- ([xshift=-\pgflinewidth]SMALL_VISIBLE_LIGHT.north east)
-- cycle
;
\end{scope}
% Some labels can be drawn automatically at the designated label coordinates:
\foreach [count=\i] \label in {
{Gamma\\rays},
{X-rays},
{},%Skip this one
{infrared}
}{
\node[raylabel, align=center] at (LABEL_\i) {\label};
}
% These do not fit the loop and are drawn manually:
\node [raylabel, align=right, anchor=north] at
([yshift=-1em,xshift=-2.5pt]$(WAVELENGTH_-2)!0.45!(WAVELENGTH_0)$)
{Ultra-\\violet};
\node [raylabel, fill=white] at (CONNECTION_6) {radio waves};
\node [raylabel, left=0.1em of CONNECTION_1, align=right] {cosmic\\rays};
\node [
draw,
fill=black!20,
below=4em of SMALL_VISIBLE_LIGHT,
align=center,
label=above:{\textbf{Visible Spectrum}}
] (FULL_VISIBLE_LIGHT) {%
\pgfspectra[
width=13em,height=3em,axis,axis unit=micron,axis step=100,
axis ticks=4,axis unit precision=2,axis color=black!20,
axis font=\normalsize,axis font color=black,
]\\%
\footnotesize
blue \hspace{0.5em}
green
yellow \hspace{1.5em}
red
};
% Draw 'magnifying' trapeze, on background so it is covered by scale labels
\begin{scope}[on background layer]
\filldraw [help lines, fill=black!10] (FULL_VISIBLE_LIGHT.north east)
-- (SMALL_VISIBLE_LIGHT.south east)
-- (SMALL_VISIBLE_LIGHT.south west)
-- (FULL_VISIBLE_LIGHT.north west)
-- cycle
;
\end{scope}
% Draw around arrow manually, leaving its tail open
\draw [draw, thick] (ARROW.after tail)
-- (ARROW.before head)
-- (ARROW.before tip)
-- (ARROW.tip)
-- (ARROW.after tip)
-- (ARROW.after head)
-- (ARROW.before tail)
;
\end{tikzpicture}
\end{document}