2
$\begingroup$

Python's matplotlib has the possibility to use a symmetric log (symlog) axis, as demonstrated in the documentation. You can set a negative threshold and positive threshold, between which the plot is linear (so it can go through 0), and then beyond those thresholds the scale is logarithmic (decades go in both the positive and negative directions).

Then, you can show sign-indefinite functions that grow large in absolute value, even if in some places they grow very negative.

Is there any easy way to achieve this effect or a utility to make such a plot in Mathematica?

$\endgroup$
  • $\begingroup$ A Mathematica equivalent is to apply the LogisticSigmoid to your function. $\endgroup$ – yarchik Mar 15 at 6:57
  • $\begingroup$ That doesn't seem to be true. In mpl's symplot asymptotically you'd plot linear growth if your function were exp(x). But LogisticSigmoid[f[x]] = 1/(1+Exp[-f[x]]) which asymptotes to 1. Moreover, interpreting such a graph would tricky, because the ticks wouldn't show logarithmic decades. $\endgroup$ – evanb Mar 15 at 13:41
  • $\begingroup$ Yes, you are right, it was a provocative comment. But I use it to quickly get an idea about some functions. At least it has a linear behavior around zero and smoothly represents diverging functions. $\endgroup$ – yarchik Mar 15 at 15:26
3
$\begingroup$

Creating this plot we need the function that maps from and to these new axes. Just like we have with logarithmic axes we need the function Log and its opposite Exp in the ScalingFunction option.

So let's define these two functions:

ClearAll[ConvertPoint, UnConvertPoint]
ConvertPoint[n_?NumericQ, {down_, up_}] := Module[{},
  If[n < 0,
   -ConvertPoint[-n, {-up, -down}]
   ,
   If[n < up,
    n
    ,
    Log[n/up] + up
    ]
   ]
  ]
UnConvertPoint[n_?NumericQ, {down_, up_}] := Module[{},
  If[n < 0,
   -UnConvertPoint[-n, {-up, -down}]
   ,
   If[n < up,
    n
    ,
    Exp[n - up] up
    ]
   ]
  ]

Given an input these will convert these back and from these new coordinates.

Now we modify the built-in ListPlot function:

ClearAll[ListSymmetricLogPlot];
ListSymmetricLogPlot[data_List, threshold_?NumericQ, opts : OptionsPattern[]] := 
 ListSymmetricLogPlot[data, {-threshold, threshold}, opts]
ListSymmetricLogPlot[data_List, thresholds : {downthres_, upthres_}, opts : OptionsPattern[]] := 
 Module[{xmin, xmax, ymin, ymax, vticks1, vticks2, vticks3, vticks, vticksright, tmp},
  {{xmin, xmax}, {ymin, ymax}} = CoordinateBounds[data];
  vticks1 = If[ymin < downthres,
    tmp = Charting`ScaledTicks[{Log, Exp}][Log[-downthres], Log[-ymin]];
    tmp[[All, 1]] = Minus@*Exp /@ tmp[[All, 1]];
    tmp[[All, 2]] = Replace[tmp[[All, 2]], {x_?NumericQ :> -x, _Superscript[a_, b_] :> Superscript[-a, b]}, {1}];
    tmp
    ,
    {}
    ];
  vticks2 = Charting`ScaledTicks["Linear"][downthres, upthres, 4];
  vticks3 = If[ymax > upthres,
    tmp = Charting`ScaledTicks[{Log, Exp}][Log@upthres, Log@ymax];
    tmp[[All, 1]] = Exp /@ tmp[[All, 1]];
    tmp
    ,
    {}
    ];
  vticks = vticksright = DeleteDuplicatesBy[SortBy[Join[vticks1, vticks2, vticks3], First],
      First];
  vticksright[[All, 2]] = "";
  ListPlot[data, opts,
   ScalingFunctions -> {None, {ConvertPoint[#, thresholds] &, UnConvertPoint[#, thresholds] &}},
   PlotRange -> All,
   FrameTicks -> {{vticks, vticksright}, Automatic},
   Ticks -> {Automatic, vticks}
   ]
  ]

We can now test it out:

ListSymmetricLogPlot[{#,#}&/@Range[-10,10,0.2],0.5,ImageSize->600]
ListSymmetricLogPlot[{#,Tan[#]}&/@Range[-0.4995Pi,0.4995Pi,0.001Pi],{-1,1},Joined->True,Frame->True,ImageSize->600]

Giving:

enter image description here

Another test:

ListSymmetricLogPlot[Join[Table[{-x,-Exp[x-5]},{x,0,10,0.01}],Table[{x,Exp[x-5]},{x,0,10,0.01}]],{-3,3}]

Giving:

enter image description here

One limitation is now that you need to input {x,y} pairs as data just the y values {y1,y2,y3,…} does not work.

| improve this answer | |
$\endgroup$
3
$\begingroup$

You may use the ScalingFunctions option which is available for most plotting functions.

We need a logarithmic function that passes through zero that we can flip and mirror in the negative domain. With such a function we will not need to specify a linear portion and thus have a smooth function over the domain. A simple solution is Log[x + 1].

Plot[Log[x + 1], {x, 0, 10}]

Mathematica graphics

Using Abs and Sign this equation and its inverse can be setup as scaling functions.

symlog =
  {
   Function[x, Sign[x] Log[Abs[x] + 1]],
   Function[y, Sign[y] Exp[Abs[y]] - 1]
   };

Then with Plot

Plot[x, {x, -10, 10},
 ScalingFunctions -> symlog]

Mathematica graphics

and ListPlot

ListPlot[
 Transpose@ConstantArray[Range[-10, 10, .25], 2],
 ScalingFunctions -> symlog]

Mathematica graphics

Hope this helps.

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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