# ScalingFunctions option works for ListPlot but only if there's no Frame: how to work around this?

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]


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


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"}]


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]


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?

-
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. –  Jens Jun 30 '12 at 5:12
@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 –  Verbeia Jun 30 '12 at 5:19
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. –  Mike Honeychurch Jun 30 '12 at 8:28

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

g = ListLogPlot[test];

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


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.

-
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 –  Verbeia Jun 30 '12 at 7:44
@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. –  Sjoerd C. de Vries Jun 30 '12 at 10:07

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 @@ %


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}}]


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]}}]


-
+1: certainly food for thought, but there are some strange overlaps. –  Verbeia Jun 30 '12 at 7:07
@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. –  Mr.Wizard Jun 30 '12 at 7:09
@Verbeia it just hit me: with "Reverse" working that should probably be Min@test -- would you try that, please? –  Mr.Wizard Jun 30 '12 at 7:10
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. –  Verbeia Jun 30 '12 at 7:19
@Verbeia I agree this is not looking good. Do you think my second answer is more promising? –  Mr.Wizard Jun 30 '12 at 7:27