8
$\begingroup$

Mathematica has quite a nice ScalingFunctions option to BarChart, BubbleChart and the various financial charting functions, which simplifies log scaling, reverse scales and so on. Consider:

test = FoldList[0.85 #1 + #2 &, 0., 
  Abs@RandomVariate[NormalDistribution[0, 3], 25]]

{0., 1.40961, 4.59418, 9.49233, 11.4004, 9.93797, 11.0347, 11.0437, 
9.39412, 8.46501, 10.5416, 10.3413, 9.60696, 8.47968, 9.45521, 
9.44406, 12.3554, 15.3821, 17.8863, 15.5349, 17.2376, 18.3164, 
 18.5506, 16.459, 14.6381, 13.7955}

BarChart[test, Frame -> True]

enter image description here

BarChart[test, ScalingFunctions -> "Log", Frame -> True]

enter image description here

As has been previously noted on the site, the option actually works for ListPlot and ListLinePlot (but not DateListPlot) as well, even though this fact is not documented.

ListLinePlot[test, ScalingFunctions -> {"Log10", "Reverse"}]

enter image description here

However that breaks down where there is a frame. The tick labels (FrameTicks) are now the rescaled values, not the original values. The data are correctly rescaled.

ListLinePlot[test, ScalingFunctions -> {"Log10", "Reverse"}, Frame -> True]

enter image description here

Obviously the undocumented insertion of this functionality into ListPlot and ListLinePlot only affected Ticks and not FrameTicks.

Is there any way to get the correct tick labels back?
Even better, is there a reasonably straightforward way to use OptionValue[ScalingFunctions] to ensure that custom tick mark placement is correct when the data have been rescaled like this?

$\endgroup$
3
  • 1
    $\begingroup$ When I specify PlotRange it never seems to take ScalingFunction into account, even in the documented uses. I could imagine that PlotRange is used in the FrameTicks calculation. If this turns out to be too hard, maybe you can use this work-around: BarChart[test, Frame -> True, ScalingFunctions -> "Reverse", Joined -> Automatic, ChartStyle -> Directive[Red, FaceForm[], EdgeForm[]] ] However you can only apply ScalingFunctions to the y axis here. $\endgroup$
    – Jens
    Jun 30, 2012 at 5:12
  • $\begingroup$ @Jens that's very clever, thank, but unfortunately only it works if you only have one series. In my actual application, I have a set of custom functions to plot various kinds of plots with highly customised settings, so that they fit nicely in my multipanel graphs $\endgroup$
    – Verbeia
    Jun 30, 2012 at 5:19
  • 1
    $\begingroup$ FWIW, when thinking of a similar application, :) , I put the undocumented use of ScalingFunction in the too hard basket and went with a switch to ListLogPlot and similar. $\endgroup$ Jun 30, 2012 at 8:28

2 Answers 2

3
$\begingroup$

Extracting tick locations with AbsoluteOptions appears promising, despite error messages.

g = ListLogPlot[test];

Show[g, Frame -> True, FrameTicks -> AbsoluteOptions[g, Ticks][[1, 2]]]

Mathematica graphics

I am using ListLogPlot as a proxy for ScalingFunctions. Again, v7 works differently so I see little point in me carefully tweaking this method, but I think this shows that it should be possible.

$\endgroup$
2
  • $\begingroup$ Sorry, this was the one that the comment " It's a good idea, but if one is drawing a ListLogPlot anyway one may as well just do that instead of using ScalingFunctions." was about $\endgroup$
    – Verbeia
    Jun 30, 2012 at 7:44
  • 1
    $\begingroup$ @verbeia With mr.wiz at v7 this is the closest he could get to answering with a tested answer. The intention is to replace the ListLogPlot with your plot and ScalingFunction. $\endgroup$ Jun 30, 2012 at 10:07
1
$\begingroup$

Version 7 doesn't support ScalingFunctions so I cannot test this, and I suppose that Overlay (also absent from v7) may work better.

Nevertheless here is one approach that may work with modification:

ListLinePlot[
  test,
  ScalingFunctions -> {"Log10", "Reverse"},
  ImagePadding -> 20, AxesOrigin -> #
] & /@ {{0, 0}, {Length@test, Max@test}};

ImageCompose @@ %

enter image description here

Here it is with Overlay: not pixelated, but still some clashes of ticks.

Overlay[ListLinePlot[test, ScalingFunctions -> {"Log10", "Reverse"}, 
ImagePadding -> 20, AxesOrigin -> #] & /@ {{0, 0}, {Length@test, 
Max@test}}]

enter image description here

It turns out that you need to scale the values of the AxesOrigin according to the scaling function you want to use. In this case, one must Log the x-coordinate and reverse the sign of the y-coordinate.

Overlay[ListLinePlot[test, ScalingFunctions -> {"Log", "Reverse"}, 
    PlotRange -> All, ImagePadding -> 20, AxesOrigin -> #] & /@ {{0, 
    0}, {Log@Length@test, -Max[test]}}]

enter image description here

$\endgroup$
6
  • $\begingroup$ +1: certainly food for thought, but there are some strange overlaps. $\endgroup$
    – Verbeia
    Jun 30, 2012 at 7:07
  • $\begingroup$ @Verbeia thanks for the image. I am surprised to see that the lower "frame" is missing; can you tell why? Also, I posted another answer that is rough but promising. $\endgroup$
    – Mr.Wizard
    Jun 30, 2012 at 7:09
  • $\begingroup$ @Verbeia it just hit me: with "Reverse" working that should probably be Min@test -- would you try that, please? $\endgroup$
    – Mr.Wizard
    Jun 30, 2012 at 7:10
  • $\begingroup$ Yes, but I realised that isn't the issue - one actually has to rescale the points for the AxisOrigin: {Log@Length@test, -Max[test]}} in this case. Given that, it will probably be easier for me to just catch the value of the option and change the head of the plotting function to ListLogPlot or ListLogLogPlot depending on its value. The tick labels inside the plot area would also have to be fixed. $\endgroup$
    – Verbeia
    Jun 30, 2012 at 7:19
  • $\begingroup$ @Verbeia I agree this is not looking good. Do you think my second answer is more promising? $\endgroup$
    – Mr.Wizard
    Jun 30, 2012 at 7:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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