5
$\begingroup$

I need to make a plot (in this case a ListPlot) in which the x (horizontal) scale varies: either piecewise linear or a single nonconstant function. The purpose is to plot data for graphs like this one:

gr

(never mind that the graph shows multiple curves), which shows the advance of HIV within a patient on multiple timescales (first the acute stage, then the longer chronic stage). But I can't figure out how to rescale the x-axis (I saw a post on this site involving a ListDatePlot scatterplot but couldn't make sense of the code); I suspect it requires some sort of virtuoso use of exotic plot options and rescaling functions.

For grins here is a list which follows one of the graphs in the HIV plot, with the x coordinate in years; I'd want either a linear scale from 0 to 1/4 and then a different linear scale from 1/4 to 11, or a scaling function which expands [0,1/4] relative to [1/4,11], like (1 - Exp[-10 x]) (0.7 x + 3).

CD4list = {{1/52, 1020}, {3/52, 900}, {6/52, 500}, {9/52, 600}, {12/52, 660},
 {1, 600}, {2, 575}, {3, 500}, {4, 400}, {5, 400}, {6, 350}, {7, 280},
 {8, 220}, {9, 60}, {10, 30}, {11, 20}};
$\endgroup$
6
  • 1
    $\begingroup$ This may be a duplicate of (8241). That one deals with the y axis but at first glance I believe the methods given can be applied here. $\endgroup$
    – Mr.Wizard
    Jan 3, 2015 at 7:51
  • 1
    $\begingroup$ This may be true; unfortunately I can't even read (parse) the code there to understand whether the undesired y-interval is being rescaled or removed altogether--the emphasis in that question is to suppress an interval but show y-ranges on either side of the suppressed interval at the same scale. Here I don't want to suppress any interval, just stretch one part of the domain relative to the rest (different scales). If those methods can be used here, I'm afraid I need a little more hand-holding to get there. $\endgroup$ Jan 3, 2015 at 17:59
  • $\begingroup$ I agree. If I understand you may be able to accomplish this by creating multiple plots and (hopefully seamlessly) joining them together, therefore also see: (6877). (You would want to turn off the Frame on the joined edges.) If I have time later I may attempt an implementation. $\endgroup$
    – Mr.Wizard
    Jan 4, 2015 at 3:09
  • $\begingroup$ I agree two joined plots should work. Unfortunately the code in #6877 uses no commands I know. I don't even know what @ means here. Another possibility might be the approach used in mathematica.stackexchange.com/questions/66354/… to transform the axes (in this case just the x-axis). $\endgroup$ Jan 5, 2015 at 4:17
  • 1
    $\begingroup$ FYI to all, I finally achieved what I was looking for, in a manual, kludgy, non-generalizable way, by defining a transform function (in this case, f[x_] = Min[40 x/3, 80 (x - 1/4)/129 + 10/3], piecewise linear with slope change at x=1/4), using it to transform the list's x coordinates, ListPlotting the transformed list, and using FrameTicks to specify tick labels which are the inverse transforms of the apparent labels (e.g., I told it to place a tick at f[1] and label it 1). I also used FrameTicks to place a dotted vertical line at f[1/4] (labeled 1/4) to mark where the scale changes. $\endgroup$ Jan 5, 2015 at 5:25

1 Answer 1

2
$\begingroup$

This is likely more or less what @Christopher describes in his comment. Note by using Interpolation and ParametricPlot we ensure the curve is continuous (and correct) across the transition breaks (otherwise you would need to ensure you had a data point at the breaks )

 CD4listf = Interpolation[CD4list, InterpolationOrder -> 1];
 breaks = {1/4, 3, Infinity};
 slopes = {1, 1/10, 1/50};
 xmap[x_] = 
    Piecewise[
       Fold[ Append[ # , {(#[[-1, 1]] /. 
           x ->  #[[-1, 2, 2]]) + #2[[2]] (x - #[[-1, 2, 2]]) , 
            x < #2[[1]] }] & ,
            {{x slopes[[1]], x < breaks[[1]]}} , 
               Transpose[{breaks[[2 ;;]], slopes[[2 ;;]]}]]];
 SetAttributes[xmap, Listable]
 ds = 0.005; dy = 30;(*axis cut parameters*)
 ParametricPlot[Through[{xmap, CD4listf}[x]], {x, 1/52, 11},
     AspectRatio -> 1/GoldenRatio ,
     Ticks -> {Through[{xmap, # &}[#]] & /@ {.05, .1, .15, .2, .5, 1, 1.5,
                                               2, 2.5, 5, 8, 11}, Automatic} ,
     PlotRangeClipping -> False,
     PlotPoints -> 1000,
     PlotRange -> {xmap[{0, 11}], Automatic},
     Epilog -> ({
         Line[{{# - ds, -dy}, {# + ds, dy}}] & /@ xmap[breaks[[;; -2]]] ,
         Point[{xmap[#[[1]]], #[[2]]} & /@ CD4list]})]

enter image description here

here is the scale mapping for reference:

     Plot[xmap[x], {x, 0, 11}]

enter image description here

$\endgroup$

Your Answer

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

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