teunbrand / ggchromatic

Colour and fill scales for 'ggplot2' using colour spaces.
https://teunbrand.github.io/ggchromatic/
Other
11 stars 1 forks source link

add support for differenc rescalers for the channels #13

Open Raoul-Kima opened 2 years ago

Raoul-Kima commented 2 years ago

Since the different channels might serve to visualize very different things, they sometimes need different rescalers. As far as I can see this currently is not possible, since:

  1. the rescaler is called on the individual channels data rather then the color_spec vector.
  2. nor is it not possible to specify different rescalers for the different channels.
  3. nor is the rescaler given any info about which channel it is currently being invoked on.

I currently have a project where I want to make use of this feature, because 1 channel contains outliers and must thus be scaled based on quantiles rather then minimum and maximum to give a useful visualisation, whereas the other channel must be guaranteed to include all extreme values and is therefore scaled based on min/max. As a sidenote: ggplot does not naturally support scaling based on quantiles, as the only info about the data which is passed to the rescaler is the min and max (e.g. when the rescaler is invoked in the legend construction, where no actual data is passed). I'm circumventing this by scoping the full dataset into the rescaler in a separate channel.

teunbrand commented 2 years ago

I can see some merit to this, but I can't currently think of an example where there wouldn't exist a simpler solution than passing a custom rescaler. If you have a column with outliers, why wouldn't you be able to deal with by call e.g. rgb_spec(r = rank(outlier_var), g = normal_var, b = other_var). Can you think of a situation that would absolutely require custom rescalers for each channel?

Raoul-Kima commented 2 years ago

If I understand your workaround correctly one would have to do something like rgb_spec(x_rescaled,y,z) and then specify manual limits for x to prevent it from being again rescaled internally (the rescaled values might not be supposed to span the entire range of possible r values, or might be supposed to span more than it, in the case of outliers), and then specify a label-function for x that backtransforms the x_rescaled values to x values to get correct legend labels.

Another workaround might be (worked in my case at least) to do the rescaling in the palette function. That was quite straightforward. I basically just put the code into the palette instead of the rescaler, no other changes necessary.

I'm not sure if these workarounds are applicable in all situations. I'm not that deeply into ggplot internals. I guess there's a reason why these things are kept separate in the ggplot api. Although that reason might not be technical, but rather just to have a nice api. All workarounds involve doing the rescaling outside the rescaler, which seems to me as if it was against the design philisophy of the ggplot api.

As I wrote above, another solution would be to pass the color_spec vector to the rescaler instead of the individual channels. And another (probably less idiomatic) solution would be to tell the rescaler which channel it is being invoked on

edit: fixed a typo, added comment in bracket in first paragraph