|
| 1 | +\documentclass{ximera} |
| 2 | +\title{Extra graph test} |
| 3 | + |
| 4 | + |
| 5 | +\begin{document} |
| 6 | +\begin{abstract} |
| 7 | + Tests/Demo for the graph command. |
| 8 | +\end{abstract} |
| 9 | +\maketitle |
| 10 | + |
| 11 | +%% Default \begin{tikzpicture} options |
| 12 | +\tikzset{ |
| 13 | + xmGraphTikz/.style={}, |
| 14 | + panel/.style={}, |
| 15 | +% xmDesmosWidth/.code 2 args={\def\xmDesmosWidth{#2}}, % sets a macro when applied |
| 16 | +% xmDesmosWidth/.default=600, % pixels |
| 17 | +% xmDesmosHeight/.code 2 args={\def\xmDesmosHeight{#2}}, % sets a macro when applied |
| 18 | +% xmDesmosHeight/.default=300, % pixels |
| 19 | + } |
| 20 | + |
| 21 | + %% Default \begin{axis} options |
| 22 | +\pgfplotsset{ |
| 23 | + xmGraphPlotAxis/.style={ |
| 24 | + xlabel={$x$}, % x-axis label |
| 25 | + ylabel={$y$}, % y-axis label |
| 26 | + axis lines=middle, |
| 27 | + axis equal image, |
| 28 | + axis line style={->}, |
| 29 | +% panel, |
| 30 | + }, |
| 31 | + panel/.code={\def\xmGraphShowPanel{true}}, % sets a macro when applied |
| 32 | + % xmGraphShowDesmos/.code={\def\xmGraphShowDesmos{true}}, % sets a macro when applied |
| 33 | + % % xmGraphShowDesmos/.default={true}, |
| 34 | + % xmGraphNoDesmos/.code={\let\xmGraphShowDesmos\undefined}, |
| 35 | + % % xmGraphShowDesmos, |
| 36 | + xmGraphShowCommand/.code={\def\xmGraphShowCommand{true}}, % sets a macro when applied |
| 37 | + % xmGraphShowTikZ/.code={\def\xmGraphShowTikZ{true}}, % sets a macro when applied |
| 38 | + % xmGraphNoTikZ/.code={\let\xmGraphShowTikZ\undDefInEd}, % sets a macro when applied |
| 39 | + xmDesmosWidth/.store in=\xmDesmosWidth, |
| 40 | + xmDesmosWidth/.default=600px, |
| 41 | + xmDesmosHeight/.store in=\xmDesmosHeight, |
| 42 | + xmDesmosHeight/.default=300px, |
| 43 | +} |
| 44 | + |
| 45 | +% \pgfkeys{ |
| 46 | +% /pgfplots/xmGraphShowDesmos/.store in=\xmGraphShowDesmos, |
| 47 | +% /pgfplots/xmGraphShowDesmos/.initial=false, % initial default |
| 48 | +% /pgfplots/xmGraphShowDesmos/.default=true, % if used as 'xmGraphShowDesmos' -> true |
| 49 | +% /pgfplots/xmGraphNoDesmos/.code={% explicit "off" |
| 50 | +% \pgfkeyssetvalue{/pgfplots/xmGraphShowDesmos}{false}% |
| 51 | +% }, |
| 52 | +% } |
| 53 | + |
| 54 | +\def\xmGraphShowDesmos{true} % default NOT inside the style: DOES NOT WORK |
| 55 | + |
| 56 | +% \pgfplotsset{ |
| 57 | +% % plot-level style |
| 58 | +% xmGraphPlot/.style={ |
| 59 | +% /pgfplots/.cd, % <- ensures keys are interpreted as pgfplots keys |
| 60 | +% domain=-2:2, |
| 61 | +% samples=50, |
| 62 | +% thick, |
| 63 | +% }, |
| 64 | +% % axis-level style |
| 65 | +% xmGraphPlotAxis/.style={ |
| 66 | +% /pgfplots/.cd, |
| 67 | +% xmin=-2.3, xmax=2.3, |
| 68 | +% ymin=-1, ymax=4, |
| 69 | +% axis equal image, |
| 70 | +% axis lines=middle, |
| 71 | +% axis line style=->, |
| 72 | +% } |
| 73 | +% } |
| 74 | + |
| 75 | +\ExplSyntaxOn |
| 76 | + |
| 77 | +% Helper function to process each item |
| 78 | +%%% The 'multi'-part, with f(x),g(x,f(x), does NOT yet work ) |
| 79 | +\cs_new_protected:Nn \__multiplot_get_function:n { |
| 80 | + % Check if the item contains slashes (legend and/or options separator) |
| 81 | + % IN 2025 ? \seq_set_split_with_nested:nnnN { / } { | | } { #1 } \l_tmpa_seq |
| 82 | + \seq_set_split:Nnn \l_tmpa_seq { // } { #1 } |
| 83 | + \int_case:nn { \seq_count:N \l_tmpa_seq } { |
| 84 | + { 1 } { |
| 85 | + % No legend, no options: just plot function |
| 86 | + #1 |
| 87 | + } |
| 88 | + { 2 } { |
| 89 | + \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl % function |
| 90 | + \l_tmpa_tl |
| 91 | + } |
| 92 | + { 3 } { |
| 93 | + \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl % function |
| 94 | + \l_tmpa_tl |
| 95 | + } |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +\cs_new_protected:Nn \__multiplot_process:nn { |
| 100 | + % Check if the item contains slashes (legend and/or options separator) |
| 101 | + % IN 2025 ? \seq_set_split_with_nested:nnnN { / } { | | } { #1 } \l_tmpa_seq |
| 102 | + \seq_set_split:Nnn \l_tmpa_seq { // } { #2 } |
| 103 | + \int_case:nn { \seq_count:N \l_tmpa_seq } { |
| 104 | + { 1 } { |
| 105 | + % No legend, no options: just plot function |
| 106 | + \addplot[xmGraphPlot, #1] { #2 }; |
| 107 | + } |
| 108 | + { 2 } { |
| 109 | + % Has legend: plot function and add legend entry |
| 110 | + \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl % function |
| 111 | + \seq_pop_left:NN \l_tmpa_seq \l_tmpb_tl % legend |
| 112 | + \addplot[xmGraphPlot, #1] { \l_tmpa_tl }; |
| 113 | + % Only add legend if not empty |
| 114 | + %\tl_if_empty:NF \l_tmpb_tl { |
| 115 | + \addlegendentry{\l_tmpb_tl} |
| 116 | + %} |
| 117 | + } |
| 118 | + { 3 } { |
| 119 | + % Has legend and options: plot function with custom options |
| 120 | + \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl % function |
| 121 | + \seq_pop_left:NN \l_tmpa_seq \l_tmpb_tl % legend |
| 122 | + \seq_pop_left:NN \l_tmpa_seq \l_tmpc_tl % options |
| 123 | + \addplot[xmGraphPlot, #1, \l_tmpc_tl] { \l_tmpa_tl }; |
| 124 | + % Only add legend if not empty |
| 125 | + \tl_if_empty:NF \l_tmpb_tl { |
| 126 | + \addlegendentry{\l_tmpb_tl} |
| 127 | + } |
| 128 | + } |
| 129 | + } |
| 130 | +} |
| 131 | + |
| 132 | +\cs_new_protected:Nn \xmultiplot:nn { |
| 133 | + \clist_map_inline:nn { #2 } { |
| 134 | + \__multiplot_process:nn { #1 } { ##1 } |
| 135 | + } |
| 136 | +} |
| 137 | + |
| 138 | +\NewDocumentCommand \xmGraphPlot { o m } { \xmultiplot:nn {#1} {#2} } |
| 139 | +\NewDocumentCommand \xmGraphGetFunction { m } { \__multiplot_get_function:n {#1} } |
| 140 | +\ProvideDocumentCommand \xmGraphLegend { m } {} |
| 141 | +\ProvideDocumentCommand \xmGraphExtra { m } {} |
| 142 | + |
| 143 | +\ExplSyntaxOff |
| 144 | + |
| 145 | +\newcommand\GetKeyFromStyle[2]{% |
| 146 | + \pgfkeys{/pgfplots/.cd,#1}% |
| 147 | + \pgfkeysvalueof{/pgfplots/#2}% |
| 148 | +} |
| 149 | + |
| 150 | +\newcommand\GetPGFplotsKeyFromStyle[2]{% |
| 151 | + % #1 = style name |
| 152 | + % #2 = key name |
| 153 | + % Save current value (to restore if undefined) |
| 154 | + \pgfkeys{/pgfplots/.cd,#1}% |
| 155 | + \pgfkeys{/pgfplots/#1} % executes the style code |
| 156 | + |
| 157 | + \typeout{KEY #2 in #1} |
| 158 | + |
| 159 | + % Try global key first |
| 160 | + \pgfkeysifdefined{/pgfplots/#2}{% |
| 161 | + \pgfkeysvalueof{/pgfplots/#2}% |
| 162 | + \typeout{KEY found: #2 in #1: \pgfkeysvalueof{/pgfplots/#2}} |
| 163 | + }{% |
| 164 | + % Try axis key |
| 165 | + \pgfkeysifdefined{/pgfplots/axis/#2}{% |
| 166 | + \pgfkeysvalueof{/pgfplots/axis/#2}% |
| 167 | + \typeout{KEY found in axis: #2 in #1: \pgfkeysvalueof{/pgfplots/axis/#2}} |
| 168 | + }{% |
| 169 | + % Try dummy option |
| 170 | + \pgfkeysifdefined{/mydymmyoption/#2}{% |
| 171 | + \pgfkeysvalueof{/mydymmyoption/#2}% |
| 172 | + \typeout{KEY found dummyoption: #2 in #1: \pgfkeysvalueof{/mydymmyoption/#2}} |
| 173 | + } |
| 174 | + { |
| 175 | + % Key not found → return empty |
| 176 | + \typeout{KEY not found: #2 in #1} |
| 177 | + }% |
| 178 | + }% |
| 179 | + } |
| 180 | +} |
| 181 | + |
| 182 | +\makeatletter |
| 183 | +\renewcommand\GetPGFplotsKeyFromStyle[2]{% |
| 184 | + % #1 = style name |
| 185 | + % #2 = key name |
| 186 | + \pgfkeys{/pgfplots/.cd,#1}% activate style |
| 187 | + %\typeout{KEY #2 in #1} |
| 188 | + \pgfkeysifdefined{/pgfplots/#2}{% |
| 189 | + \pgfkeysvalueof{/pgfplots/#2}% |
| 190 | + % \typeout{KEY found: #2 in #1: \pgfkeysvalueof{/pgfplots/#2}} |
| 191 | + }{% |
| 192 | + \pgfkeysifdefined{/pgfplots/axis/#2}{% |
| 193 | + \pgfkeysvalueof{/pgfplots/axis/#2}% |
| 194 | + %\typeout{KEY axis found: #2 in #1: \pgfkeysvalueof{/pgfplots/#2}} |
| 195 | + }{% |
| 196 | + %\pgfkeysifdefined{/pgfplots/.@cmd/#2}{TRUE}{FALSE}% |
| 197 | + % undefined → return empty |
| 198 | + }% |
| 199 | + }% |
| 200 | +} |
| 201 | +\makeatother |
| 202 | + |
| 203 | +\makeatletter |
| 204 | +% #1 = macro to store value |
| 205 | +% #2 = style name |
| 206 | +% #3 = key name |
| 207 | +\newcommand\GetPGFplotsKeyFromStyleToMacro[3]{% |
| 208 | + %\begingroup |
| 209 | + \def#1{}% initialize macro to empty |
| 210 | + \pgfkeys{/pgfplots/.cd,#2}% activate the style |
| 211 | + % Try normal key |
| 212 | + \pgfkeysifdefined{/pgfplots/#3}{% |
| 213 | + \pgfkeysgetvalue{/pgfplots/#3}{#1}% |
| 214 | + }{% |
| 215 | + % Try axis key |
| 216 | + \pgfkeysifdefined{/pgfplots/axis/#3}{% |
| 217 | + \pgfkeysgetvalue{/pgfplots/axis/#3}{#1}% |
| 218 | + }{% |
| 219 | + % Key not found → leave empty |
| 220 | + \def#1{}% |
| 221 | + }% |
| 222 | + }% |
| 223 | + %\endgroup |
| 224 | +} |
| 225 | + |
| 226 | +\makeatother |
| 227 | + |
| 228 | +\renewcommand{\graph}[2][]{ |
| 229 | + \begingroup |
| 230 | + \ifdefined\xmGraphShowDesmos % generic tikz-options confuse the pgfkeys ... |
| 231 | + %\typeout{SETTING tmpstyle (\xmGraphShowDesmos\ for #1)} |
| 232 | +\pgfplotsset{ %% The #1 will process the additional options, so that \xmGraphShowTikZ works !!! |
| 233 | + tmpstyle/.style={ |
| 234 | + /pgfplots/xmGraphPlot, % apply plot keys |
| 235 | + /pgfplots/xmGraphPlotAxis, % apply axis keys |
| 236 | + % /pgfplots/.cd, % ensure any extra keys are interpreted in pgfplots |
| 237 | + #1 % allow overrides |
| 238 | + } |
| 239 | +} |
| 240 | + \pgfkeys{/pgfplots/.cd,#1}% activate style |
| 241 | +\else |
| 242 | + %\typeout{SKIPPING tmpstyle for #1} |
| 243 | +\fi |
| 244 | + |
| 245 | +\ifdefined\HCode |
| 246 | + \HCode{<div class="xmdesmos">} |
| 247 | +\else |
| 248 | + \def\xmGraphShowTikZ{true} %% ALWAYS show TikZ in PDF !!! |
| 249 | +\fi |
| 250 | +
|
| 251 | + \ifdefined\xmGraphShowCommand |
| 252 | + \ifdefined\HCode |
| 253 | + % \HCode{<h1> Command: \string\graph[#1]{#2} </h1> } |
| 254 | + \else |
| 255 | + % {\Large\bf With options #1 } |
| 256 | + \fi |
| 257 | + \fi |
| 258 | +
|
| 259 | +
|
| 260 | +
|
| 261 | +\ifdefined\HCode\ifdefined\xmGraphShowDesmos |
| 262 | +% \pgfplotsset{ |
| 263 | +% xxxxtmpstyle/.style = { |
| 264 | +% /pgfplots/.append style={xmGraphPlot} % apply xmGraphPlot in axis context |
| 265 | +% /pgfplots/axis/.append style={xmGraphPlotAxis} % apply xmGraphPlot in axis context |
| 266 | +% /pgfplots/axis/.append style={#1} % apply xmGraphPlot in axis context |
| 267 | +% }, |
| 268 | +% } |
| 269 | +
|
| 270 | +
|
| 271 | +
|
| 272 | +% \GetPGFplotsKeyFromStyleToMacro{\myval}{tmpstyle}{axis equal image} |
| 273 | +% axis equal image = \myval % prints "-2:2" |
| 274 | +
|
| 275 | +% \GetPGFplotsKeyFromStyleToMacro{\myval}{tmpstyle}{xlabel} |
| 276 | +% xlabel = \myval % prints "-2:2" |
| 277 | +% xlabel = \HCode{\myval} % prints "-2:2" |
| 278 | +
|
| 279 | +%\typeout{AXIS KEY: \GetPGFplotsKeyFromStyle{tmpstyle}{axis equal image}} |
| 280 | +% AXIS : \GetPGFplotsKeyFromStyle{tmpstyle}{axis equal image} |
| 281 | +% PANEL : \GetPGFplotsKeyFromStyle{tmpstyle}{panel} |
| 282 | +% XLABEL : \GetPGFplotsKeyFromStyle{tmpstyle}{xlabel} |
| 283 | +
|
| 284 | + \HCode{<div class="desmos-placeholder" data-options="} |
| 285 | + %%% still an issue with $x$ vs x (Desmos prints the $'s !) |
| 286 | + % \GetPGFplotsKeyFromStyleToMacro{\myval}{tmpstyle}{xlabel} |
| 287 | + % xlabel=\HCode{\myval}, |
| 288 | + % \GetPGFplotsKeyFromStyleToMacro{\myval}{tmpstyle}{ylabel} |
| 289 | + % ylabel=\HCode{\myval}, |
| 290 | + % ylabel=\HCode{\GetPGFplotsKeyFromStyle{tmpstyle}{ylabel}}, |
| 291 | + xmax=\GetPGFplotsKeyFromStyle{tmpstyle}{xmax}, |
| 292 | + xmin=\GetPGFplotsKeyFromStyle{tmpstyle}{xmin}, |
| 293 | + ymin=\GetPGFplotsKeyFromStyle{tmpstyle}{ymin}, |
| 294 | + ymax=\GetPGFplotsKeyFromStyle{tmpstyle}{ymax}, |
| 295 | + \ifdefined\xmGraphShowPanel panel=true, \fi |
| 296 | + \ifdefined\xmDesmosWidth xmDesmosWidth=\xmDesmosWidth, \fi |
| 297 | + \ifdefined\xmDesmosHeight xmDesmosHeight=\xmDesmosHeight, \fi |
| 298 | + \if\relax\detokenize\expandafter{\GetPGFplotsKeyFromStyle{tmpstyle}{axis equal image}}\relax |
| 299 | + axis equal image=true, |
| 300 | + \fi |
| 301 | + \HCode{" data-graph='}\detokenize{#2}\HCode{'"></div>}% |
| 302 | +\fi\fi% |
| 303 | +\ifdefined\xmGraphShowTikZ% |
| 304 | + \begin{tikzpicture}[xmGraphTikz] |
| 305 | + \begin{axis}[xmGraphPlotAxis,#1] |
| 306 | + \xmGraphPlot[]{#2} |
| 307 | + % \xmGraphPlot[#1]{#2} |
| 308 | + \xmGraphLegend{} |
| 309 | + \xmGraphExtra{} |
| 310 | + \end{axis} |
| 311 | + \end{tikzpicture} |
| 312 | +\fi |
| 313 | +
|
| 314 | +\endgroup |
| 315 | +} |
| 316 | +
|
| 317 | +\ExplSyntaxOn |
| 318 | +\bool_set_true:N \l__trace_errors_bool |
| 319 | +\ExplSyntaxOff |
| 320 | +
|
| 321 | +\NewDocumentCommand{\xmgraph}{ O{} m } |
| 322 | +{ |
| 323 | + % #1 = optional key-value options |
| 324 | + % #2 = the math expression (can include \frac, \sqrt, etc.) |
| 325 | + |
| 326 | + % Store argument verbatim |
| 327 | + \tl_set:Nn \l_tmpa_tl {#2} |
| 328 | +
|
| 329 | + % Expand token list at use, safely passing to \graph |
| 330 | + \exp_args:No \graph [#1] {\l_tmpa_tl} |
| 331 | +} |
| 332 | +
|
| 333 | +\ExplSyntaxOff |
| 334 | +
|
| 335 | +% \newcommand{\xmgraph}[2][]{$\graph{#2}$} |
| 336 | +\pgfplotsset{ |
| 337 | + xmGraphPlot/.append style={ |
| 338 | + domain=-2:2, |
| 339 | + }, |
| 340 | + % Axis-only keys go in a separate style |
| 341 | + xmGraphPlotAxis/.append style={ |
| 342 | + xmin=-2.3, |
| 343 | + xmax=2.3, |
| 344 | + ymin=-1, ymax=4, |
| 345 | + % xmDesmosWidth=500px, |
| 346 | + % xmDesmosHeight=500px, |
| 347 | + % ymin, ymax, tick settings etc. |
| 348 | + } |
| 349 | + } |
| 350 | +
|
| 351 | +
|
| 352 | +% xmax=\GetPGFplotsKeyFromStyle{xmGraphPlot}{xmax} |
| 353 | +
|
| 354 | +% xmax=\GetPGFplotsKeyFromStyle{xmGraphPlotAxis}{xmax} |
| 355 | +% \graph{x^2/2//function//blue} |
| 356 | +
|
| 357 | +
|
| 358 | +\def\xmGraphShowCommand{true} |
| 359 | +
|
| 360 | + \graph[xmin=-7, xmax=5, ymin=-5, ymax=5]{\frac{4}{x+2},x=-2} |
| 361 | +
|
| 362 | +
|
| 363 | + \pgfplotsset{ |
| 364 | + xmGraphPlot/.append style={ |
| 365 | + domain=-2:2, |
| 366 | + }, |
| 367 | + % Axis-only keys go in a separate style |
| 368 | + xmGraphPlotAxis/.append style={ |
| 369 | + xmin=-2.3, |
| 370 | + xmax=2.3, |
| 371 | + ymin=-1, ymax=4, |
| 372 | + xmDesmosWidth =200px, |
| 373 | + xmDesmosHeight=200px, |
| 374 | + % ymin, ymax, tick settings etc. |
| 375 | + } |
| 376 | + } |
| 377 | +
|
| 378 | + \graph[panel,xmin=-2.5, xmax=2.5,ymin=-0.5,ymax=8]{\frac{1}{x^2}} |
| 379 | +
|
| 380 | + \graph[panel]{1/x^2, 1/x^4, 1/x^6, (1,1), (-1,1),x=2} |
| 381 | + |
| 382 | + |
| 383 | + \graph[panel,xmin=-2.5, xmax=2.5,ymin=-0.5,ymax=8]{\frac{1}{x^2}, \frac{1}{x^4}, \frac{1}{x^6}, (1,1), (-1,1)} |
| 384 | + |
| 385 | + \end{document} |
0 commit comments