Skip to content

Add the ability to not call into collapse-ticks#41

Closed
evdubs wants to merge 1 commit intoracket:masterfrom
evdubs:collapse-ticks-1
Closed

Add the ability to not call into collapse-ticks#41
evdubs wants to merge 1 commit intoracket:masterfrom
evdubs:collapse-ticks-1

Conversation

@evdubs
Copy link
Contributor

@evdubs evdubs commented Mar 1, 2018

This is most helpful when trying to just have tick labels on the far y axis while keeping the ticks on the near y axis and allowing the grid to still be drawn. Here is the code that can be used for testing

#lang racket

(require plot)

(collapse-ticks? #t)

(parameterize ([plot-width    150]
                 [plot-height   150]
                 [plot-x-label  #f]
                 [plot-y-label  #f]
                 [plot-y-ticks (ticks (linear-ticks-layout) no-ticks-format)]
                 [plot-y-far-ticks (linear-ticks)])
    (plot (function sin (- pi) pi)))

By changing collapse-ticks? to #f, we can see all of the ticks on the near y axis and the tick-grid will also be displayed.

… when trying to just have tick labels on the far y axis while keeping the ticks on the near y axis and allowing the grid to still be drawn
@evdubs
Copy link
Contributor Author

evdubs commented Mar 1, 2018

Here is the current result where collapse-ticks is forced
ticks-not-on-near-axis

Here is the result with this code when collapse-ticks? is set to #f
ticks-on-near-axis

@evdubs
Copy link
Contributor Author

evdubs commented Mar 1, 2018

I'll need to add some documentation for this feature.

@evdubs
Copy link
Contributor Author

evdubs commented Mar 1, 2018

I would like to know if there's either a way to display the near y axis ticks that I haven't figured out or if there's a more appropriate fix.

@alex-hhh
Copy link
Collaborator

alex-hhh commented Mar 3, 2018

I have only spend a small amount of time on this, and I didn't have time to figure out what collapse-ticks actually does (i.e. why are the ticks removed). I played with some variations of your example and I was surprised by the results...

My preference would be to find out if there is actually a bug in collapse-ticks and fix that, instead of bypassing the call altogether. Alternatively, if you believe that collapse-ticks actually works correctly, it might be worth explaining that in this pull request.

BTW, I'm not a maintainer, just a user of this package, the maintainers might have different opinions on this.

@bennn
Copy link
Contributor

bennn commented Mar 5, 2018

I don't see a way to get unlabeled near-axis ticks and labeled far-axis ticks with the current plot.

If there was a way to tell plot "use the right side as the near axis, not the left side", would that solve your problem? (I'm not sure how to implement that, but it seems like a clearer fix.)

@evdubs
Copy link
Contributor Author

evdubs commented Mar 5, 2018

@bennn that would be a preferable solution. I only took this approach because it seemed to work and was relatively straight forward.

@alex-hhh
Copy link
Collaborator

alex-hhh commented Mar 8, 2018

I think the problem is that collapse-ticks is too aggressive when there are no labels on the ticks. In such a case, it will always collapse all ticks into a single one, regardless of anything else (number of ticks, whether they are major or not, or distance between ticks).

If same-label? is changed to not consider two empty strings to be the same, the ticks will not be collapsed into one. Other collapsing rules will continue to be in effect, for example ticks might be collapsed if they are too close to each other.

You will find that the plot is rendered as intended if same-label? is changed to the definition below, without any need for a collapse-ticks? parameter:

(define (same-label? t1 t2)
  (and (string=? (tick-label t1) (tick-label t2))
       (not (string=? (tick-label t1) ""))))

@evdubs
Copy link
Contributor Author

evdubs commented Mar 11, 2018

@bennn do you think a change to same-label? like @alex-hhh proposed is a better solution?

@bennn
Copy link
Contributor

bennn commented Mar 21, 2018

Yes, if we have a parameter to make the new behavior opt-in (to avoid changing existing plots). Something like this:

(define (same-label? t1 t2)
  (if (or (collapse-empty-ticks?)
          (non-empty-string? (tick-label t1)))
    (string=? (tick-label t1) (tick-label t2))
    #false))

This is better to me because it's a smaller change.

But I'd still prefer to have a parameter that makes the left side be the far axis.

@evdubs
Copy link
Contributor Author

evdubs commented Mar 21, 2018

@bennn the parameter should already be opt-in, it just has a larger scope if you opt in rather than just taking effect within the same-label? check. Or am I misunderstanding something?

@evdubs
Copy link
Contributor Author

evdubs commented Mar 21, 2018

@bennn I will take a look to see what the code change looks like to switch axes for being near/far.

@bennn
Copy link
Contributor

bennn commented Mar 21, 2018

I think we understand each other

  • collapse-ticks? is opt-in
  • just changing same-label? would not be opt-in
  • changing same-label? but adding a parameter would be opt-in

And to be clear I don't feel very strongly that collapse-ticks? is worse than changing same-label?. The most important thing is that the docs (for whatever this PR ends up doing) help other people find this solution.

@alex-hhh
Copy link
Collaborator

alex-hhh commented Mar 21, 2018

Just to add my two cents to this conversation...

I think the current behavior of collapse-ticks? contains a bug. If I read the code correctly, it should collapse ticks that are close to each other compared to the plot area, or whose printed representation is the same (e.g when using 1 digit precision for the numbers). With the current implementation, however, it will consider two ticks to be the same if they have no label, regardless of whether they are actually close or not.

With the current behavior, no-ticks-format is useless, as all the ticks will be collapsed into one -- might as well just generate one tick in the middle of the interval.

To further elaborate on this: disabling collapse-ticks altogether might produce undesired results. For example, collapse-ticks make sure that if you have 3 ticks at 0.11, 0.12, 0.13, but you just label them with (~r x #:precision 1) you will not get 3 ticks all labeled "0.1" on the plot. It also makes sure that ticks are not placed too close to each other given the available resolution on the plot.

@bennn
Copy link
Contributor

bennn commented Mar 21, 2018

I think the current behavior of collapse-ticks? contains a bug. ....
With the current behavior, no-ticks-format is useless, ....

Whether or not it's a bug, I think we should keep the current behavior as the default --- so if a plot user upgrades to the next version of Racket, their old plots still look the same.

@bennn
Copy link
Contributor

bennn commented Apr 18, 2018

ah! I just ran into a problem with collapse-ticks. Here's code for my plot:

#lang racket
(require plot/no-gui plot/utils)

(define data
  '((#(#\A 1.0) #(#\B 1.0) #(#\C 1.0) #(#\D 1.0) #(#\E 1.0) #(#\F 1.0) #(#\G 1.0) #(#\H 1.0) #(#\I 1.0) #(#\J 1.0) #(#\K 1.0) #(#\L 1.0) #(#\M 1.0) #(#\N 1.0) #(#\O 1.0) #(#\P 1.0) #(#\Q 1.01) #(#\R 1.0) #(#\S 1.0))
    (#(#\A 1.02) #(#\B 1.0) #(#\C 1.15) #(#\D 272.7) #(#\E 1.07) #(#\F 1.01) #(#\G 1.12) #(#\H 1.02) #(#\I 1.02) #(#\J 1.06) #(#\K 1.13) #(#\L 1.01) #(#\M 1.09) #(#\N 1.06) #(#\O 1.09) #(#\P 0.98) #(#\Q 1.14) #(#\R 34.98) #(#\S 0.96))))

(define my-ticks
    (ticks (λ (ax-min ax-max)
             (define major-ticks
               (for/list ((i (in-range 0 (log ax-max 10))))
                 (pre-tick (expt 10 i) #true)))
             (define minor-ticks
               (for*/list ((i (in-range 0 (exact-ceiling (log ax-max 10))))
                           (j (in-range 2 10 2)))
                   (pre-tick (* (expt 10 i) j) #false)))
             (append minor-ticks major-ticks))
           (lambda (ax-min ax-max pre-ticks)
             (for/list ([pt (in-list pre-ticks)])
               (format "10~a" (integer->superscript (exact-floor (log (pre-tick-value pt) 10))))))))

(parameterize ([plot-x-ticks no-ticks]
               [plot-y-ticks my-ticks]
               [plot-y-transform log-transform])
  (plot-file
    (append
      (for*/list ((i (in-range 0 4))
                  (j (in-range 2 10 2)))
        (hrule (* (expt 10 i) j) #:color 0 #:style 'solid #:alpha 0.2))
      (for/list ([color (in-list '(3 4))]
                 [style (in-list '(solid fdiagonal-hatch))]
                 [x-min (in-naturals 0)])
        (discrete-histogram
          (list-ref data x-min)
          #:x-min x-min
          #:skip 3
          #:label #f
          #:style style
          #:color (->brush-color color)
          #:line-color (->pen-color color)
          #:add-ticks? #true)))
    "sample.png"
    'png
    #:y-min 0.5
    #:width 400
    #:height 200))

Here's what the plot looks like on the current master branch. This is bad because there are no y minor ticks:
ticks-before

Here's what the plot looks like if I remove all calls to collapse-ticks. This is bad because the x ticks are not collapsed:
ticks-after

And here's what the plot looks like if I call collapse-ticks and change same-label? to Alex's definition above --- it looks the same as the first picture:
ticks-same-label


@evdubs what do you think about changing this PR from 1 parameter to 6 parameters (plot-collapse-x-near-ticks? ... plot-collapse-z-far-ticks?)?

@evdubs
Copy link
Contributor Author

evdubs commented Apr 18, 2018

I can certainly do that. Do you think it's still worth investigating the whole "treat the far-x-axis as the near-x-axis" thing?

@bennn
Copy link
Contributor

bennn commented Apr 18, 2018

That still seems useful, but this barchart experience made me realize that control over collapse-ticks is good to have for itself. ("please don't collapse my hand-crafted ticks")

Leave it for a separate PR?

@alex-hhh
Copy link
Collaborator

Hi @Benn, your minor ticks are missing because they have the same label as the major ticks, and this is exactly what collapse-ticks will remove. Since the minor ticks don't display a label anyway, you can define them as:

(define my-ticks
    (ticks (λ (ax-min ax-max)
             (define major-ticks
               (for/list ((i (in-range 0 (log ax-max 10))))
                 (pre-tick (expt 10 i) #true)))
             (define minor-ticks
               (for*/list ((i (in-range 0 (exact-ceiling (log ax-max 10))))
                           (j (in-range 2 10 2)))
                   (pre-tick (* (expt 10 i) j) #false)))
             (append minor-ticks major-ticks))
           (lambda (ax-min ax-max pre-ticks)
             (for/list ([pt (in-list pre-ticks)])
               (if (pre-tick-major? pt)
                   (format "10~a" (integer->superscript (exact-floor (log (pre-tick-value pt) 10))))
                   (format "~a" (pre-tick-value pt)))))))

And they will show up as you intended. This is with the code on the master branch.

The changes I proposed to same-label? would only handle the case of empty labels and would have no effect on the rest of the collapse-ticks behavior, so it is unsurprising that it didn't fix the problem. With the same-label? change, you could have left the minor pre-ticks with an empty label, but without it, you have to generate a unique label, which is than discarded.

@bennn
Copy link
Contributor

bennn commented Apr 19, 2018

@alex-hhh thanks for this! I didn't realize the ticks-format function got called for every tick.

I'm still thinking parameters to disable collapse-ticks will be useful. Do you have an opinion on that?

@alex-hhh
Copy link
Collaborator

Hi @bennn,

I don't think that a collapse-ticks? parameter would be useful. The examples provided in this pull request don't justify it -- it is just that disabling the collapse-ticks function appeared to solve the immediate problem in each case. collapse-ticks is also an internal function of the plot package, and the purpose of a collapse-ticks? parameter would be difficult to explain to someone who is not familiar with these internals.

For the first example, I think, some labels-on-far-axis?, labels-on-near-axis? parameters would be best. The purpose of these parameters would be easy to explain to someone who only cared about the visual layout of a plot, without having to understand the internals of the plot package.

For the second example, I think the documentation for ticks could be improved to mention that all ticks generated by the function need to have a distinct label, including the minor ticks, otherwise they will be collapsed.

I also think the same-label? function should be fixed. In such a case, the minor ticks could have an empty string as a label and they would not be collapsed. In the current situation, the minor ticks have to have a label generated which is than discarded.

@bennn
Copy link
Contributor

bennn commented Apr 20, 2018

I'll make a pull request for the documentation for ticks.

I also think the same-label? function should be fixed.

That's ok with me as long as the fix doesn't change how existing plots render. (There should be a parameter or something to say "please don't collapse ticks with an empty label".)

I still have the feeling we'll want to give control over collapse-ticks someday, but I can't argue with you that the examples we have now aren't super-motivating.

@evdubs
Copy link
Contributor Author

evdubs commented Apr 21, 2018

I created PR #43 and I think that code change will be much more agreeable.

@evdubs evdubs closed this Jun 2, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants