Menu

#426 Apply function to tic marks

open
nobody
None
5
2015-10-18
2015-10-15
No

I have had several times that I have had to have tic marks that were not directly possible through a format string. For instance on an axis that ranges from 0 - 1, I would like to mark these as percentages (0.1 should be marked as 10%, 0.33 as 33% and so on), or an axis that ranges from 0 - 30,000,000, I would like to mark it off in millions (labels such as "1 million", "10 million" and so on). There is no way to do this by a format string.

It is possible to do this by adding the marks explicity:
set for[i=0:10] ytics add (sprintf("%d%%",i10) i/10.0)
and
set for [i=0:6] xtics add (sprintf("%d million",5
i) i*5000000)

It would be nice to have a function that could be applied to the tic marks before applying a format command, so this would not be needed. For example (for the second case):

f(x) = x/1000000
set xtics format "%0.0f million" map f

which would apply the tic marks in the normal manner but apply the function f before applying the format string.

I lot of times positioning the tic marks explicitly isn't necessary, but being able to apply a function as part of the formatting is. For example in the percentage case, I really don't care which marks are labeled and would let gnuplot figure that out on it's own, but I need to be able to mark those as percentages.

I don't know how difficult or easy it may be to do something like this. In fact, I suspect that implementing it would be easy, but parsing the syntax may not be. My example gives a function by name, and I figure it would be easier to implement by that kind of syntax, but I don't know if it would be possible to specify an inline syntax as well (by requiring a specific dummy variable and deliminator character(s)). Something like: set xtics format "%0.0f million" map {r/1000000}.

Discussion

  • Matthew Halverson

    Looking at the set link command, I see that it handles inline functions so my example syntax that shows a deliminator character doesn't really need that.

    So something like
    set xtics format "%0.0f million" map r/1000000
    is what I would want there (again depending on what the dummy variable is).

    And of course, the "map" term there could be whatever you would judge to be appropriate (maybe "via" like used in the set link command might be more intuitive).

     
  • Ethan Merritt

    Ethan Merritt - 2015-10-15

    Can't you just use the "set link" command itself?

    For your first example

    axis that ranges from 0 - 1, I would like to mark these as percentages (0.1 should be marked as 10%, 0.33 as 33% and so on)

      set link x2 via x/100. inverse x*100.
      set xrange [0.1:100.]
      set xtics nomirror format "%2g%%"
      plot sin(pi*x) axes x2y1
    
     
  • Matthew Halverson

    I never thought about doing it that way - plotting against one axes and using the secondary axes to map my marks.

    I still think that it would be nice to have a way to apply the function like I discussed. I don't want to change the axis (for instance in the percentage case, I still want it to range from 0-1), just do something regarding the marks.

    This method works (even though it requires 2 commands to accomplish it instead of just one), but it isn't going to work if I actually need that secondary axes for something (although I rarely do this, and I can always do it the long way and add my own tick marks in that case).

    Other than that problem, I love this! It accomplishes exactly what I wanted. I would like to see it implemented as I suggested, but as this works 99% of the time, it isn't anything critical anytime soon.

     
  • Ethan Merritt

    Ethan Merritt - 2015-10-17

    By the way, here is a completely different way to accomplish the same thing.

    gnuplot> set parametric
            dummy variable is t for curves, u/v for surfaces
    gnuplot> set xrange [0:100]
    gnuplot> set trange [0:2*pi]
    gnuplot> plot t*100,asin(t)
    gnuplot> set format x "%g%%"
    gnuplot> replot
    
     
    • Matthew Halverson

      That works as well. I thought that it would solve my issue with having to use the secondary axis for mapping, but it seems it doesn't. Is it not possible to define a different range of t for each pair of functions?

      What I mean is that for normal plotting, I can do something like this:
      plot sin(x), [0:pi] cos(x)
      or
      plot sample [0:pi] sin(x), [pi/2.0:pi] cos(x)
      to plot each function over different ranges. Trying this with t
      plot sample [t=0:pi] t,sin(t), [t=pi/2.0:pi] t,cos(t)
      doesn't seem to work. In all cases the default trange seems to be used. I can do a single specification like
      plot [t=0:pi] t,sin(t),t,cos(t)
      which works with both curves using that range, but I can't seem to do a different range for each function pair.

      Is this not possible? If it was, this would provide a way to do exactly what I want without having to abuse that secondary axis to do the mapping (which means I would have it available if I needed to plot against it too).

       
  • Ethan Merritt

    Ethan Merritt - 2015-10-18

    Yes, that works. But you don't need parametric mode for that.

       plot sample [t=0:pi] '+' using (t):(sin(t)), \
                 [t=pi/2:pi] '+' using (t):(cos(t))
    

    I don't quite see how that relates to your original question about labeling the x axis, but maybe it gives you another idea to play with.

     

    Last edit: Ethan Merritt 2015-10-18
  • Matthew Halverson

    Excellent! That will work.

    The way that it relates is that I may need to do this to plot two different functions with two different axes - so the first technique with set link won't work because I will then need both axes, so can't use one to fake the markings. I can use your suggestion of parametric mode to plot against x1y1 and a second function against x2y2, but they may need different ranges of the t variable. Your suggestion above will allow me to do that.

    Say I have functions f(x) which gives a percentage and x is measured in millions and g(x) which gives a percentage and x is a percentage itself. I can let y1 range from 0 to 100 and be formated with "%g%%" and x1 range from 0 to 100 formated with "%g million" and x2 be set up just like y1. Then I can do

    plot sample [t=0:100000000] "+" u (t/1000000.0):(100f(t)), [t=0:1] "+" u (100t):(100*g(t)) axes x2y1

    (I don't know why, but my multiplications keep disappearing when I save this - anywhere where it looks like an implied multiplication, there shoud be a multiplication sign).

    My original goal was to plot against axes with these specialized markings and allow gnuplot to figure out where to put the tic marks automatically. It is easy if I am willing to figure out where to put the tic marks myself, because I can label them whatever I want, but gnuplot can't place markings of the form I want on it's own because the values need to be transformed (multiplied or divided) before being formatted.

    This will allow me to do that exactly how I want. I just wish there was a more automatic way to mark those. Particularly in the percentage case, I can't imagine that I'm the only one that wants a 0-1 axis to be marked off as percentages from 0-100.

    Thanks for the last suggestion. That gets me exactly what I wanted although with a little extra work.

     

    Last edit: Matthew Halverson 2015-10-18
  • Ethan Merritt

    Ethan Merritt - 2015-10-18

    Too complicated for me to follow.

    Stepping back all the way to the beginning, did you know that you can get your "xx million" labels on the x axis using gnuplot-specific format %b ? E.g.:

    set xrange [0 : 3.0e7]
    set format x "%.0b million"
    plot x

    I didn't mention it at first because I didn't realize you really cared about "millions" in particular rather than just using that as an arbitrary example.

     
  • Matthew Halverson

    I did, but I was concerned about when it placed the marks before the first million. I don't think it is viable in my case if I rely on automatic placement of the tics.

    set xrange[0:3000000] # 0 - 3,000,000
    set format x "%0.0b million"
    plot sin(x)

    The first two marks read "0 million" and "488 million". The second mark is actually 488,000, but the formatting marks it like that. I actually would rather that it was labeled 0 million instead of 488 million - at least the 0 million is somewhat acurate. So here I would again have to place the labels myself instead of relying on the automatic placement. In my original 0-30,000,000 case, this isn't a problem because the marks aren't placed before the first million.

    I do have it working correctly now. Of course, for publication purposes, I will likely be placing the tic marks myself anyways. Gnuplot's defaults are usually pretty good, but for publication work, it is usually better to do that manually to get it exactly right - I know how it is going to be sized and placed on the final page, and gnuplot can't know that.

    That suggestion at least simplifies the manual placement:
    set xtics 5000000 format "%0.0b million"
    instead of
    set xtics format ""
    set for[i=0:6] xtics add (sprintf("%d million",5i) i5000000)
    that I was doing.

    In my particular use case, both the "millions" labels and the "%" labels were important, but I do care about the general approach as well - in the future I could easily want something that uses the same approach, but is distinctly different than this.

    I do have it figured out on how to do it in most cases now.

     

Log in to post a comment.