Giter Club home page Giter Club logo

Comments (13)

teunbrand avatar teunbrand commented on July 24, 2024

Hello there,

Thank you for your feedback, I can see that it can be somewhat confusion. Indeed, as you mention, we've parametrised vjust to be in line with geom_text(), such that it would be easy to combine the two if needed.

library(ggplot2)
#> Warning: package 'ggplot2' was built under R version 4.1.1
library(geomtextpath)
library(patchwork)

df <- data.frame(
  x = seq(-0.5, 1.5, length.out = 10),
  y = 1,
  label = "geom_textpath"
)

plot_vjust <- function(vjust) {
  ggplot(df, aes(x, y)) +
    geom_textpath(aes(label = label), vjust = vjust) +
    annotate(x = 2, y = 1, label = "geom_text", geom = "text", vjust = vjust) +
    ggtitle(paste0("vjust = ", vjust)) +
    scale_x_continuous(limits = c(-1, 3))
}

plot_vjust(-1) + plot_vjust(0) + 
  plot_vjust(1) + plot_vjust(2)

Created on 2021-11-20 by the reprex package (v2.0.1)

I see your concern that this is parametrised confusingly, but I'm not convinced that we should break away from the conventions of typical grid text justification (which was my own intuition). Instead, I think it might make more sense to specify an offset parameter that does pretty much the opposite of vjust and could be used to more conveniently achieve the results you're looking after. Internally that would just be an adjustment to the vjust parameter, but at least it is more intuitive to users.

To address some of your points;

  1. The vjust parameter doesn't specify justification of the text along the y-axis, it specifies the justification orthogonal to the direction of the text. This just happens to coincide with y-axis justification when the angle of the text is 0. We are using vjust as justification orthogonal to the tangent on the curve, which is conceptually similar (as the direction of the text is on the tangent of the curve).
  2. The line does break at integer positions 1 and 0, it's just that we're using a closed interval that includes 1 and 0 itself.
  3. I apologise, I'm confused because I don't understand what you mean with 'sides' and 'scales'.

The correct underline position for text is specific for a font, so a fixed parameter that works for all fonts in probably out of the question. It is possible though to retrieve the position for a specific font with e.g. systemfonts::font_info("Arial")$underline_pos.

from geomtextpath.

AllanCameron avatar AllanCameron commented on July 24, 2024

Thanks for taking the time to write, and for getting the ball rolling with your SO question! We're having a lot of fun creating something new that might also be useful to other folk.

I share your intuition about the direction of vjust, but it's important to realise that this isn't copied from geom_text, nor is it a design decision we have made. Rather, vjust is one of the graphical parameters of any text that is created using the grid package (on which ggplot2 is built). It indicates which part of the text should be aligned to the specified point / path / line, from 0 (bottom of the text) to 1 (top of the text). It is passed directly from geom_textpath to grid::textGrob in our code without modification, as it is throughout the whole ggplot / grid ecosystem. Of course we could change vjust so that instead of just being passed to grid::textGrob, it is modified in some way, but then its behaviour would be out of step with every other package that uses grid or ggplot, and this is not something we want to do. Perhaps it would be better to have a completely different parameter called offset or nudge that does things a bit more intuitively, but this would be a simple arithmetic wrapper around vjust, and we are keen to avoid parameter bloat. My inclination is to leave the vjust as-is, but if we get a lot of similar feedback from other users we would add in an offset parameter.

In contrast, we have had (by necessity) to alter how hjustworks, because each letter's position and angle along the path has to be calculated in advance, and passing hjust directly to grid after this calculation would ruin the alignment, creating a total mess. Also, there is no single reference point along a path that is an anchor for hjust That means we have had to use the hjust parameter as an analogy to allow users to align the whole string somewhere between 0 (the start of the string is at the start of the path) and 1 (the end of the string is at the end of the path), through 0.5 (the midpoint of the string is at the midpoint of the path). I think this leads to natural and expected behaviour, and it's difficult to see how else you would do it.

Where the line breaking occurs is a design decision. It actually does occur at whole numbers - anything greater than 1 or.less than zero currently breaks the line. I think from what you are saying, you would expect anything greater than or equal to 1 or less than or equal to 0 to break the line. This would be a trivial change to make in the code, and I don't have strong feelings about it either way. I'm not sure if I would have a clear expectation about this as an end user, so it's great to have your perspective.

I'll leave this open for now to get an opinion from Teun.

from geomtextpath.

teunbrand avatar teunbrand commented on July 24, 2024

Haha, I wasn't expecting this degree of agreement, Allan (up to the point that we both suggest an offset parameter that would internally work as an adjustment to vjust)!

from geomtextpath.

AllanCameron avatar AllanCameron commented on July 24, 2024

Yes! Within seconds and with close accord. Do you have an intuition about whether the (0, 1) should be an open rather than closed interval?

from geomtextpath.

byteit101 avatar byteit101 commented on July 24, 2024

I am just about to go to bed, and I'll respond more fully tomorrow, but real quick

Instead, I think it might make more sense to specify an offset parameter

Yes, I think a different parameter might make more sense. I'm not necessarily asking about changing vjust, just rather some way that may make more sense for a textpath, given the necessary conceptual differences between the two.

from geomtextpath.

teunbrand avatar teunbrand commented on July 24, 2024

Do you have an intuition about whether the (0, 1) should be an open rather than closed interval?

I have no strong preference, but I would see merit in a cut_path = TRUE/FALSE parameter so that you have the option to use the line as a strikethrough even when vjust = 0.5. I imagine this being NA by default, which would mean current behaviour, whereas TRUE always cuts the path, even if text isn't likely to intersect the line.

from geomtextpath.

AllanCameron avatar AllanCameron commented on July 24, 2024

OK. I'll do that. And I'll change to interval to open, so that we incorporate some user feedback since neither of us have a preference.

from geomtextpath.

AllanCameron avatar AllanCameron commented on July 24, 2024

Based on the above comments, the latest commit will have the following behaviour:

Default

 ggplot(iris, aes(x = Sepal.Length, colour = Species)) +
   geom_textpath(aes(label = Species), stat = "density",
                 size = 6, fontface = 2, hjust = 0.2, vjust = 0.3)

Line now doesn't break at exactly vjust = 1 and vjust = 0

  ggplot(iris, aes(x = Sepal.Length, colour = Species)) +
   geom_textpath(aes(label = Species), stat = "density",
                 size = 6, fontface = 2, hjust = 0.2, vjust = 1)

  ggplot(iris, aes(x = Sepal.Length, colour = Species)) +
   geom_textpath(aes(label = Species), stat = "density",
                 size = 6, fontface = 2, hjust = 0.2, vjust = 0)

  ggplot(iris, aes(x = Sepal.Length, colour = Species)) +
   geom_textpath(aes(label = Species), stat = "density",
                 size = 6, fontface = 2, hjust = 0.2, vjust = 0.99)

  ggplot(iris, aes(x = Sepal.Length, colour = Species)) +
   geom_textpath(aes(label = Species), stat = "density",
                 size = 6, fontface = 2, hjust = 0.2, vjust = 0.01)

cut_path parameter now over-rides vjust

  ggplot(iris, aes(x = Sepal.Length, colour = Species)) +
   geom_textpath(aes(label = Species), stat = "density",
                 size = 6, fontface = 2, hjust = 0.2, vjust = 0.3,
                 cut_path = FALSE)

  
  ggplot(iris, aes(x = Sepal.Length, colour = Species)) +
   geom_textpath(aes(label = Species), stat = "density",
                 size = 6, fontface = 2, hjust = 0.2, vjust = -1,
                 cut_path = TRUE)

Created on 2021-11-20 by the reprex package (v2.0.0)

from geomtextpath.

teunbrand avatar teunbrand commented on July 24, 2024

Wow that was quick! Looks very nice, thanks Allan!

from geomtextpath.

AllanCameron avatar AllanCameron commented on July 24, 2024

Closed with this commit

from geomtextpath.

byteit101 avatar byteit101 commented on July 24, 2024

I've been pondering this all day. First some clarifications:

The vjust parameter doesn't specify justification of the text along the y-axis, it specifies the justification orthogonal to the direction of the text.

Yes, I was using a straight line as an example, I though I made that clear, but perhaps not.

We are using vjust as justification orthogonal to the tangent on the curve, which is conceptually similar (as the direction of the text is on the tangent of the curve)

Yes, that is what I had expected

I apologise, I'm confused because I don't understand what you mean with 'sides' and 'scales'.

Right, so by sides I'm referring to what side of the line the text is on, and by scale I'm referring to the values of vjust to achieve said positioning.
There are 3 "trivial" use cases, centered on the line, above the line at some reasonably readable distance, and below the line at some reasonably readable distance.

Ignoring the "readable distance" part, right now the centered use case is vjust = 0.5, above is 0, and below is -1. Thus the scale or magnitude of the vjust parameter has 2 integers in it. If, for example, we scaled vjust by 100, the scale of the magnitude of vjust becomes 50, 0, -100. The "scale" is basically just the y=mx+b of what values map to which outcomes. We could change the scale to be 18,16,20 for center, above, below respectively, though I think that's a dumb scale :-)

Does that clarify that point a bit more?

The correct underline position for text is specific for a font, so a fixed parameter that works for all fonts in probably out of the question. It is possible though to retrieve the position for a specific font with e.g. systemfonts::font_info("Arial")$underline_pos.

Yes, and that is something that I've gone back and forth on, but ended up deciding that I'd rather report the confusion without a solution so to spark a discussion than try to solve it myself. That is one reason why, while this issue is filed against vjust as it exist, I'd be perfectly happy with a new parameter, be it numeric or, as I added at the end of my post, some parameter space in the font metrics.

but then its behaviour would be out of step with every other package that uses grid or ggplot, and this is not something we want to do

Yes, I actually went back and forth on whether to file this issue for that exact reason. I do like that it matches the rest of ggplot, but I do think there needs to be something that exposes the intent of use of texpaths more in a textpath way due to this confusion

typical grid text justification (which was my own intuition).

I share your intuition about the direction of vjust,

These two opinions illustrait my point exactly: It's potentially confusing

I think from what you are saying, you would expect anything greater than or equal to 1 or less than or equal to 0 to break the line.

Yes, that's what I was attempting to say with point 2

Ok, I think I responded to most points, If you are still confused, ask again.

I do want to make a proposal though:

I may have come around back to favoring font-metric things over a numeric scale. I'm going to propose keeping vjust as-is, instead adding font.offset (or some other name like that) with the following options: NA (default), above, above-bounding, above-ideographic*, hanging, middle, below, below-bounding. If both vjust and font.offset are specified, you get a warning/error, and vjust is used.

*I am not familiar with the intricacies of ideographic writing. This may or may not be necessary. I'm also going to ignore other line-based scripts beyond Devanagari as they are significantly less common, and I don't know how to deal with them :-)

Thus the go-to options for users who want nice text layout are font.offset="above", font.offset="below", and font.offset="middle" (effective default).

This avoids users having to re-align any text when they change fonts during the final polish stages of their report, as I am doing right now on the report that spawned the SO question. As an example, coping the offset of the text in this image required 3 different values for 3 different fonts: -0.29, -0.26, and -0.24.

Why do I now think string enum values, rather than a continuous scale is probably better? Because any continuous scale will be nonlinear, and change it's linearity per font.

And now back to this:

It is possible though to retrieve the position for a specific font with e.g. systemfonts::font_info("Arial")$underline_pos.

The reason I said "I don't mind doing some research to find the right metric for underline and overline distance" is that there doesn't seem to be one underline distance per font. As can be seen below, LibreOffice and Firefox have two different underline positions.

Now the photos:

"hanging" option: (As someone who doesn't know hindi, I don't care about this, but a whole subcontinent may. Simulated using vjust=0.83, and I assume that will chage per-font but I only have one Devanagari font installed)

Devanagari_text

"center"/"middle" (vjust=0.5):
latin_text_center

"above-bounding" (vjust~=-0.38, varies per font. Note the descenders are all above the line)
latin_above_bounding

"below" (vjust~=1.21, varies per font. Note the diacritics hit the line (when present, obviously). Thai would be even worse in this setting)
latin_below

"below-bounding" (vjust~=1.41, varies per font. Thai would require even lower)
latin_below_bound

"above" is one of the two below. Note the descenders can hit the line (vs above-bounding)

I don't know enough about ideographic to make a sane screenshot of "above-ideographic", but I believe it would be somewhere between "above" and "above-bounding"

Comparison between LibreOffice and FirefoX underline locations:
latin_lounder
latin_underline

Note that I'm going to make the assumption that if you have very cursive fonts (looking at you zapfino), the -bounding variants would be very funky, and you probably will just use vjust manually :-)

I'm not opposed to implementing this myself, but I would like to discuss it first with you all.

from geomtextpath.

AllanCameron avatar AllanCameron commented on July 24, 2024

Thanks for the response. We are still working on getting the vjust implemented properly (getting this right is vital to ensuring consistent curvature and spacing). Part of the problem is that none of your examples include multi-line text, and I think it's important that we support this. Remember, we're still at an early stage of development, and we have a few issues to get right with the underlying mechanism before we can decide on the UX decisions about which parts of the mechanism can or should be exposed to end-users and how these should be presented.

Ultimately, it might be a good idea to have some kind of parameter like the one you discussed, but this would almost certainly be a simple vjust wrapper. Personally, I'm happy to let people play with the vjust to achieve the look they want, at least until we're close to a CRAN submission and hopefully we'll have a bit more feedback by then.

You are very welcome to fork the repo and have a go at implementing something you think would be a useful addition that we could incorporate via a pull request.

In the meantime, it's great to see that what we have is working well enough for an end user to produce meaningful examples without too much trouble (I hope!)

from geomtextpath.

byteit101 avatar byteit101 commented on July 24, 2024

Was going to look at implementing this today, but I see it seems to have been at least partially implemented (overline/underline) with 9f59f2e That's great!

from geomtextpath.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.