Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow ad-hoc color changing #893

Open
martinpopel opened this issue Jan 19, 2018 · 64 comments
Open

Allow ad-hoc color changing #893

martinpopel opened this issue Jan 19, 2018 · 64 comments

Comments

@martinpopel
Copy link

As discussed in #288 and #449, it is difficult to choose one color palette that suits everyone in all situations.
If there are many runs and I select just some of them (with a regex or toggling individual runs), I quite often end up with e.g., red, red, orange, red and I cannot distinguish the runs especially if the curves are crossing each other.
I suggest to add a drop-down color picker (e.g. using http://jscolor.com/) to choose a color for each run.
I plan to use this especially before posting TensorBoard screenshots to my colleagues.

@martinpopel martinpopel changed the title Allow ad-hoc colors changing Allow ad-hoc color changing Jan 19, 2018
@nfelt
Copy link
Contributor

nfelt commented Jan 27, 2018

This could be useful. Note that jscolor itself though we couldn't use since it's GPL.

@martinpopel
Copy link
Author

OK, jscolor is not needed (it was just an example). Choosing e.g. from 16 pre-defined colors would be enough for my needs.

@jart
Copy link
Contributor

jart commented Jan 27, 2018

Our team probably can't do something like this at the moment. I suspect configuring color might be more appropriate if done in code/config rather than UI.

@martinpopel
Copy link
Author

I understand there may be higher priority features to implement. Just note that configuring colors in code/config would not solve this issue.
The point is that I don't know in advance which runs I will want to compare. I want to change the colors ad hoc from the GUI.
Also in case of multiple users connecting to the same TensorBoard server, I think the colors should be per-user configurable, i.e. client-side.

It is a question whether to solve the run<-->color mapping (semi)permanently in the browser. If possible this may be useful.
Another issue with TensorBoard is that when I delete a run (e.g. to save disk space), all colors change, so I have to redo all screenshots again to have consistent colors.

@netheril96
Copy link

A way to change color in config/code/command line is better than nothing, although I'd favor a Web UI too.

@jart
Copy link
Contributor

jart commented Mar 28, 2018

Is the root problem that colors are not predictable and might change as you add additional runs? I'm not sure how color selection works at the moment. Although one possible thing to consider is using hash(run_name) % #colors to make color selection somewhat more deterministic.

Could that solve your problem?

@martinpopel
Copy link
Author

martinpopel commented Mar 28, 2018

The color of a given run changes only if I delete any older runs. This is bothersome, but it is not the main issue I originally reported.

My issue is:
I have hundreds of runs in TensorBoard and I select various subsets using regex filters or checkboxes.
Each subset has at most eight runs, so it would be possible to use distinct color for each run, but quite often this is not the case.

Maybe there could be a button "change colors" which would automatically select colors so the currently selected runs have distinct colors - this would solve my issue.
However, I think my original proposal is more useful: by manual ad-hoc coloring, the users can choose the colors exactly as they want (e.g. using red for a "failed" run and gray for baseline).
Of course, we could have both a button for automatic re-coloring and an ad-hoc color picker.

BTW: My current workaround is to create symlinks for a given run until one of the symlinks gets assigned a suitable color. Then I keep visible just that symlink and hide all previous symlinks plus the original.

@jart
Copy link
Contributor

jart commented Mar 28, 2018

We're currently building SQL support so Runs can be grouped into Experiments, Experiments can be grouped into Projects, which are owned by Users. The next logical step is to add a UI feature that lets you compare an intersection of experiments.

In other words, we're working towards better solutions to organizing data. Do you suspect that might solve the root problem here?

@martinpopel
Copy link
Author

All that is great, but I don't see how it could help with this problem without adding the color picker.
I keep my runs organized in a directory structure already, e.g. training-dataset/number-of-gpus/batch-size/learning-rate/warmup-steps/etc.
In one minute I want to see all runs on a given training data, then I want to compare runs with all hyperparmeters fixed except for batch size, then I want to see the effect of number of GPUs, etc..
So there is no single way how to organize the runs in Projects/Experiments/Groups such that I would always compare only runs within one group.
Specifically for this issue, there is no fixed mapping of runs to colors which would suit all my needs.

@jart
Copy link
Contributor

jart commented Mar 29, 2018

One thing you might be able to do is render a matplotlib image and log it as an image summary.

@martinpopel
Copy link
Author

One thing you might be able to do is render a matplotlib image and log it as an image summary.

This is not even a workaround (and it would require hack all the TF frameworks again): I don't know in advance which colors should each run have - I decide this only when using TensorBoard and selecting the subset of runs.

My current workaround is to export the plots to csv files and plot these with gnuplot-lua-tikz (which is more suitable for academic papers than screenshots anyway). But this is not suitable for interactive analysis in TensorBoard (zooming, exact numbers it tooltips, etc.), similarly as what you suggested.

I think this discussion starts getting too long and not focused on the main problem and its solution (color picker), but rather on workarounds.
If you feel this issue has low-priority and there is no one to implement it, let's close it and go on.
A summary of workarounds (for other users):

  • clicking the show/hide checkbox for each run there and back to see "which of the four red curves (crossing each other) is which one"
  • changing the color of a given run using the symlink hack
  • create a new directory with symlinks to the runs you are interested in and start a new TensorBoard instance with --logdir pointing to this directory
  • exporting the runs to csv and re-plotting in your favorite visualization tool

@netheril96
Copy link

netheril96 commented Mar 29, 2018

I have the same needs as the author of this issue. The emphasis is on ad-hoc, that is, the fact that our selection is constantly changing on the spot. None of the workarounds proposed here work that dynamically. They are all fixed beforehand.

@djl11
Copy link

djl11 commented May 24, 2018

I agree with both netheril96 and martinpopel. Making sense of data which are marked with similar colors is difficult, particularly when 20+ scalars are being plotted on a single graph, and colors are re-used. This feature request would be a great addition to tensorboard.

@jart
Copy link
Contributor

jart commented May 24, 2018

What do we think about the following solutions?

  1. Have a checkbox next to regex search so it chooses new colors each time it's applied.
  2. Make (1) the default behavior and don't bother with the checkbox.
  3. Make (2) cleverer, by only choosing new colors if the filtered colors needlessly overlap.

@martinpopel
Copy link
Author

@jart: These three solutions may help and as someone here wrote, anything is better than nothing, but...

The problem of 2 and 3 is that some colors will change when users don't expect this - I guess this could be very controversial (although for me it is better than the current state). Sometimes I get used to some color-run mappings. Sometimes I make the regex more specific just temporarily then want to go back and see the same colors as before.
The problem of all three solutions is that users don't have full control over the colors, so it will solve just some use cases. Sometimes I need to display 20+ runs and even if you automatically choose a different color for each, there will be some difficult to distinguish pairs and no automatic algorithm can guess which runs are important for me to distinguish.
Another real-life example: I have 5 settings evaluated on two test sets, resulting in 10 runs (curves) in one graph. One test set is easier, so none of its accuracy curves cross the other test set curves. As a visual aid I would like to mark the same setting in both test sets with the same color, thus using only 5 colors for the 10 runs.

So my suggestion is:
4. Add a drop-down color picker for each run. It should be easy to implement and solves all the problems very elegantly. There could be a icon for the color picker next to the check-box and radio-button, or it could be activated by left-click or right-click on the run name, so it does not take any extra space.
5. In addition to 4, there could be a button which assigns different colors for all the runs in the current regex filter randomly. So you can click on it again and again until you are satisfied. This could be helpful if someone is lazy to choose a color for each run manually (e.g. because changing the regex filter frequently, but I guess this is not so common use case).
6. In addition to 4 and 5, when a run is deleted from disk, no colors should be changed.

Note that solution 4 is what I am suggesting all the time from my first post and I still don't see what's the problem with this approach. I am afraid explaining why it is better than all the suggested alternatives took me more effort than actually implementing it and sending a PR.

@djl11
Copy link

djl11 commented May 25, 2018

I agree that custom color selection would be by far the best solution. As Martin popel said, it would even be useful to colour certain plots the same color sometimes.

For example: 3 datasets, each with 3 hyperparameter selections, and 3 different architectures, making 27 scalars plotted in total. Maybe I could use just red blue green to distinguish the dataset for 1 screenshot, then the hyperparameters for another, and finally the architectures.

This is a simple example, but custom color selection would really add a great deal of visualisation power I feel, which is of course what tensorboard is all about, and otherwise does so well at.

But anything is better than nothing of course, I’m not sure how difficult this is to implement. I very much appreciate your attention on this.

@djl11
Copy link

djl11 commented May 25, 2018

Also, as a side note. Most people in my lab use tensorboard regularly, and by far the most common use case is comparing many runs in a single plot, with various parameters selected for cross comparison, with directory structure for the log files used to distinguish meaning. Having briefly spoken to each of them today after writing this comment, this is a feature request which all of them were very keen for. Of course this is not a very formal poll! But I genuinely think it is a feature which would be very much welcomed by the research community who use tensorboard.

@kocmitom
Copy link

kocmitom commented Aug 9, 2018

I would also greatly appreciated the possibility to change the colors ad-hoc. Or just one button "reassign colors", which would take into account the runs I selected first (I usually select much less than 16 runs).

@OverLordGoldDragon
Copy link

Any updates? TF2's out, TB remains unicolored - the issue's still relevant

@jrenrut
Copy link

jrenrut commented Nov 13, 2019

Hi, are there any updates on this issue? I'm having the same problem but with the scatter plot colors with the tensorboard projector.

@diggerdu
Copy link

diggerdu commented Nov 13, 2019

What about developing a mode for colorblind users and a mode for normal people, that would meet the needs of everyone

@nicofirst1
Copy link

Any update on this?

@ham952
Copy link

ham952 commented Jun 9, 2020

i want to present the same problem with a different perspective.
I did a (single) training itteration with multiple "stops" , analysing the parameters and then re-continuing the same. Such that by the end of complete run , i had many sessions and ofcourse each session plot is showing a different color .. Below is the snapshot of same ..

delme

Now i have compare it with another iteration, completed in a simialr fashion .. for me the problem is two-fold .. With so many color combinations its really frustrating to even segregate the two main itterations ..
for me the solution can be a directory (NOT sub-directory) based color assignment .. i-e all the sub-directory in a main directory can have a single color

-iteration01 (red)

  • run01
  • run02
  • run03

-iteration02 (blue)

  • run01
  • run02
  • run03

I beleive many people facing a similar problem or even in a different setting, can find such a solution more helpful.

@martinpopel
Copy link
Author

@ham952: Why don't you move the event files from all sub-directories to the same directory? This can be done with a single mv command (or you can configure your tools to store the even files there in the first place). The event files should have unique filenames and TensorBoard should merge the datapoints from all the files automatically into a single run (there may be problems with overlapping curves, ie. two different y-values for the same x-value, but it seems to happen just rarely in your case).

Note also that while using automatically the same color for all sub-directories would make you happy, it would make almost everyone sad. What could work (in addition to my suggestions 4,5,6 above) is an extra color-picker which assigns the same color to all currently selected runs. This way you could regex-select all the runs which should be red, then all the runs which should be blue etc. This global color-picker could be near the button which assigns a random different colors to all selected runs (which was my suggestion 5).

@ham952
Copy link

ham952 commented Jun 10, 2020

@ham952: Why don't you move the event files from all sub-directories to the same directory? This can be done with a single mv command (or you can configure your tools to store the even files there in the first place). The event files should have unique filenames and TensorBoard should merge the datapoints from all the files automatically into a single run (there may be problems with overlapping curves, ie. two different y-values for the same x-value, but it seems to happen just rarely in your case).

Note also that while using automatically the same color for all sub-directories would make you happy, it would make almost everyone sad. What could work (in addition to my suggestions 4,5,6 above) is an extra color-picker which assigns the same color to all currently selected runs. This way you could regex-select all the runs which should be red, then all the runs which should be blue etc. This global color-picker could be near the button which assigns a random different colors to all selected runs (which was my suggestion 5).

Thanks @martinpopel .. it solved my particular problem .. didnt had the idea that tensorboard can merge the datapoints from multiple event files ..

Stay Blessed !

@martinpopel
Copy link
Author

@dgrahn Thank you for being the first one (after more than two years since the issue was created) who did any real work.

I just want to repeat (see my comments above in this discussion) that a different palette (no matter with how many colors) does not solve my problem (which is obviously a problem of many other users).
Having an option to choose between different palettes (or even possibly to design a new "user/ad-hoc" palette) from the UI can be useful in some cases, but it is not the main problem of this issue (and perhaps should be discussed in a different issue).

What I suggest is to have a color-picker (from a palette with 10-20 pre-defined colors) for each run (i.e. placed next to each run name), so that I can quickly change the color of each run. What I meant by ad-hoc is that "now I want this curve in blue, but next minute I will want it in red" (e.g. because I will choose a different subset of runs).
It would be quite cumbersome if I first had to remember which color is assigned to the run I want to change and then I had to find this color in the palette and change it according to my needs.

@dgrahn
Copy link
Contributor

dgrahn commented Jul 28, 2020

@martinpopel I'm sure that it'll end up there. This is just a first step. A lot of work needs to be done to allow the colors to be updated on demand. If I have time after that, I'll implement a color picker. If I don't have time, I'll make sure to leave some comments that indicate how to implement this.

@dgrahn
Copy link
Contributor

dgrahn commented Jul 28, 2020

@martinpopel Would a color picker like this work for you? https://www.webcomponents.org/element/@polymer/paper-swatch-picker

@wchargin
Copy link
Contributor

Hi @dgrahn and @martinpopel! It seems like there are a couple different
problems with different corresponding solutions. First is that there are
simply too few colors in the default accessible palette. We can solve
this by adding alternate palettes and a config option. Second is that
even with a wider palette, we want to be able to assign colors to
specific runs, either manually, or automatically based on a “train/test”
split, or automatically based on some kind of experiment/hyperparameter
config, or something else. This is less straightforward; one reason is
that the amount of state stored is significantly larger, so we’d need to
consider more carefully how to persist that (does the URL fragment still
make sense?) as in addition to the actual color-picking UI.

So I agree with @dgrahn that keeping the scope tight is a good place to
start. To that end, I’d suggest persisting only the palette name—the
base key in your struct above. If we just store a string key, we can
avoid stashing a base64-over-JSON blob (like the run selection state)
into the fragment.

Let me know if this sounds reasonable to you, and we’ll definitely let
you know when the migration is done. Thanks!

@martinpopel
Copy link
Author

Would a color picker like this work for you? https://www.webcomponents.org/element/@polymer/paper-swatch-picker

Yes. That looks great.

keeping the scope tight is a good place to start

Yes. It is better to start with something simple which works (and can be improved later).

simply too few colors in the default accessible palette.

This is not the main problem for me. I am not sure which palette is the default one, but I see both googleStandard and googleColorBlindAssist have 9 colors. I rarely need more than 9 runs at the same time in one plot.
But as I understand from the branch increasing this to 20 is quite simple.

we want to be able to assign colors to specific runs, either manually

Yes. This is essential for me.

automatically based on a “train/test” split, or automatically based on some kind of experiment/hyperparameter
config, or something else.

This is not essential for me. Moreover, I doubt there is a fully-automatic color assignment suitable for more users.
A config with regexes (sorted by priorities) mapping run names to colors may be nice, but we should think if it is simple and intuitive enough for the users.
Tensorboard has newly a support for hparams, so perhaps the color config should be compatible with this (but I am not sure how).

we’d need to consider more carefully how to persist that

It would be nice if the color assignment is persistent between browser refreshes and deleting some runs (that run will disappear, but other runs should not change their colors), but again it is not essential for me.

@dgrahn
Copy link
Contributor

dgrahn commented Jul 28, 2020

@wchargin It just seems like this feature set is going to be expanded soon. That's why I proposed using the object store. What's the downside to storing a bit more information, besides a little overhead?

@wchargin
Copy link
Contributor

wchargin commented Aug 3, 2020

The main downside about storing objects is that the data is encoded in
the URL as a large blob of base64-over-JSON. For example, if I open
TensorBoard on my local machine, it redirects to:

http://localhost:6006/#scalars

If I change the smoothing weight, this becomes:

http://localhost:6006/#scalars&_smoothingWeight=0.8

But if I press “toggle all runs”, it becomes a 9 KB opaque blob:

http://localhost:6006/#scalars&_smoothingWeight=0.8&runSelectionState=eyJjdXN0b21fc2NhbGFyX2RlbW8iOnRydWUsImdyYXBoX3RyYWNlYmFja19kZW1vL2ZpcnN0Ijp0cnVlLCJncmFwaF90cmFjZWJhY2tfZGVtby9zZWNvbmQiOnRydWUsImxlZ2FjeV9hdWRpb19kZW1vL3dhdmU6MDEsc2luZV93YXZlIjp0cnVlLCJsZWdhY3lfYXVkaW9fZGVtby93YXZlOjAyLHNxdWFyZV93YXZlIjp0cnVlLCJsZWdhY3lfYXVkaW9fZGVtby93YXZlOjAzLHRyaWFuZ2xlX3dhdmUiOnRydWUsImxlZ2FjeV9hdWRpb19kZW1vL3dhdmU6MDQsYmlzaW5lX3dhdmUiOnRydWUsImxlZ2FjeV9hdWRpb19kZW1vL3dhdmU6MDUsYmlzaW5lX3dhaHdhaF93YXZlIjp0cnVlLCJoaXN0b2dyYW1zX2RlbW8iOnRydWUsImltYWdlc19kZW1vL2JveF90b19nYXVzc2lhbiI6dHJ1ZSwiaW1hZ2VzX2RlbW8vc29iZWwiOnRydWUsInByX2N1cnZlX2RlbW8vY29sb3JzIjp0cnVlLCJwcl9jdXJ2ZV9kZW1vL21hc2tfZXZlcnlfb3RoZXJfcHJlZGljdGlvbiI6dHJ1ZSwidGV4dF9kZW1vIjp0cnVlLCJzY2FsYXJzX2RlbW8vdGVtcGVyYXR1cmU6dDA9MjcwLHRBPTI3MCxrSD0wLjAwMSI6dHJ1ZSwic2NhbGFyc19kZW1vL3RlbXBlcmF0dXJlOnQwPTI3MCx0QT0yNzAsa0g9MC4wMDUiOnRydWUsInNjYWxhcnNfZGVtby90ZW1wZXJhdHVyZTp0MD0yNzAsdEE9MzEwLGtIPTAuMDAxIjp0cnVlLCJzY2FsYXJzX2RlbW8vdGVtcGVyYXR1cmU6dDA9MjcwLHRBPTMxMCxrSD0wLjAwNSI6dHJ1ZSwic2NhbGFyc19kZW1vL3RlbXBlcmF0dXJlOnQwPTI3MCx0QT0zNTAsa0g9MC4wMDEiOnRydWUsInNjYWxhcnNfZGVtby90ZW1wZXJhdHVyZTp0MD0yNzAsdEE9MzUwLGtIPTAuMDA1Ijp0cnVlLCJzY2FsYXJzX2RlbW8vdGVtcGVyYXR1cmU6dDA9MzEwLHRBPTI3MCxrSD0wLjAwMSI6dHJ1ZSwic2NhbGFyc19kZW1vL3RlbXBlcmF0dXJlOnQwPTMxMCx0QT0yNzAsa0g9MC4wMDUiOnRydWUsInNjYWxhcnNfZGVtby90ZW1wZXJhdHVyZTp0MD0zMTAsdEE9MzEwLGtIPTAuMDAxIjp0cnVlLCJzY2FsYXJzX2RlbW8vdGVtcGVyYXR1cmU6dDA9MzEwLHRBPTMxMCxrSD0wLjAwNSI6dHJ1ZSwic2NhbGFyc19kZW1vL3RlbXBlcmF0dXJlOnQwPTMxMCx0QT0zNTAsa0g9MC4wMDEiOnRydWUsInNjYWxhcnNfZGVtby90ZW1wZXJhdHVyZTp0MD0zMTAsdEE9MzUwLGtIPTAuMDA1Ijp0cnVlLCJzY2FsYXJzX2RlbW8vdGVtcGVyYXR1cmU6dDA9MzUwLHRBPTI3MCxrSD0wLjAwMSI6dHJ1ZSwic2NhbGFyc19kZW1vL3RlbXBlcmF0dXJlOnQwPTM1MCx0QT0yNzAsa0g9MC4wMDUiOnRydWUsInNjYWxhcnNfZGVtby90ZW1wZXJhdHVyZTp0MD0zNTAsdEE9MzEwLGtIPTAuMDAxIjp0cnVlLCJzY2FsYXJzX2RlbW8vdGVtcGVyYXR1cmU6dDA9MzUwLHRBPTMxMCxrSD0wLjAwNSI6dHJ1ZSwic2NhbGFyc19kZW1vL3RlbXBlcmF0dXJlOnQwPTM1MCx0QT0zNTAsa0g9MC4wMDEiOnRydWUsInNjYWxhcnNfZGVtby90ZW1wZXJhdHVyZTp0MD0zNTAsdEE9MzUwLGtIPTAuMDA1Ijp0cnVlLCJtZXNoX2RlbW8iOnRydWUsImhwYXJhbXNfZGVtbyI6dHJ1ZSwiaHBhcmFtc19kZW1vLzAiOnRydWUsImhwYXJhbXNfZGVtby8wL3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vMC92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vMSI6dHJ1ZSwiaHBhcmFtc19kZW1vLzEvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby8xL3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby8yIjp0cnVlLCJocGFyYW1zX2RlbW8vMi90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzIvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzMiOnRydWUsImhwYXJhbXNfZGVtby8zL3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vMy92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vNCI6dHJ1ZSwiaHBhcmFtc19kZW1vLzQvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby80L3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby81Ijp0cnVlLCJocGFyYW1zX2RlbW8vNS90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzUvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzYiOnRydWUsImhwYXJhbXNfZGVtby82L3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vNi92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vNyI6dHJ1ZSwiaHBhcmFtc19kZW1vLzcvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby83L3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby84Ijp0cnVlLCJocGFyYW1zX2RlbW8vOC90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzgvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzkiOnRydWUsImhwYXJhbXNfZGVtby85L3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vMTAiOnRydWUsImhwYXJhbXNfZGVtby85L3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby8xMC90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzEwL3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby8xMSI6dHJ1ZSwiaHBhcmFtc19kZW1vLzExL3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vMTEvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzEyIjp0cnVlLCJocGFyYW1zX2RlbW8vMTIvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby8xMi92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vMTMiOnRydWUsImhwYXJhbXNfZGVtby8xMy90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzEzL3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby8xNCI6dHJ1ZSwiaHBhcmFtc19kZW1vLzE0L3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vMTQvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzE1Ijp0cnVlLCJocGFyYW1zX2RlbW8vMTUvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby8xNS92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vMTYiOnRydWUsImhwYXJhbXNfZGVtby8xNi90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzE2L3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby8xNyI6dHJ1ZSwiaHBhcmFtc19kZW1vLzE3L3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vMTcvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzE4Ijp0cnVlLCJocGFyYW1zX2RlbW8vMTgvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby8xOC92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vMTkiOnRydWUsImhwYXJhbXNfZGVtby8xOS90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzE5L3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby8yMCI6dHJ1ZSwiaHBhcmFtc19kZW1vLzIwL3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vMjAvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzIxIjp0cnVlLCJocGFyYW1zX2RlbW8vMjEvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby8yMS92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vMjIiOnRydWUsImhwYXJhbXNfZGVtby8yMi90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzIyL3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby8yMyI6dHJ1ZSwiaHBhcmFtc19kZW1vLzIzL3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vMjMvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzI0Ijp0cnVlLCJocGFyYW1zX2RlbW8vMjQvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby8yNC92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vMjUiOnRydWUsImhwYXJhbXNfZGVtby8yNS90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzI1L3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby8yNiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzI2L3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vMjYvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzI3Ijp0cnVlLCJocGFyYW1zX2RlbW8vMjcvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby8yNy92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vMjgiOnRydWUsImhwYXJhbXNfZGVtby8yOC90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzI4L3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby8yOSI6dHJ1ZSwiaHBhcmFtc19kZW1vLzI5L3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vMjkvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzMwIjp0cnVlLCJocGFyYW1zX2RlbW8vMzAvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby8zMC92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vMzEiOnRydWUsImhwYXJhbXNfZGVtby8zMS90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzMxL3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby8zMiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzMyL3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vMzIvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzMzIjp0cnVlLCJocGFyYW1zX2RlbW8vMzMvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby8zMy92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vMzQiOnRydWUsImhwYXJhbXNfZGVtby8zNC90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzM0L3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby8zNSI6dHJ1ZSwiaHBhcmFtc19kZW1vLzM1L3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vMzUvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzM2Ijp0cnVlLCJocGFyYW1zX2RlbW8vMzYvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby8zNi92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vMzciOnRydWUsImhwYXJhbXNfZGVtby8zNy90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzM3L3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby8zOCI6dHJ1ZSwiaHBhcmFtc19kZW1vLzM4L3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vMzgvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzM5Ijp0cnVlLCJocGFyYW1zX2RlbW8vMzkvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby8zOS92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vNDAiOnRydWUsImhwYXJhbXNfZGVtby80MC90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzQwL3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby80MSI6dHJ1ZSwiaHBhcmFtc19kZW1vLzQxL3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vNDEvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzQyIjp0cnVlLCJocGFyYW1zX2RlbW8vNDIvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby80Mi92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vNDMiOnRydWUsImhwYXJhbXNfZGVtby80My90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzQzL3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby80NCI6dHJ1ZSwiaHBhcmFtc19kZW1vLzQ0L3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vNDQvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzQ1Ijp0cnVlLCJocGFyYW1zX2RlbW8vNDUvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby80NS92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vNDYiOnRydWUsImhwYXJhbXNfZGVtby80Ni90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzQ2L3ZhbGlkYXRpb24iOnRydWUsImhwYXJhbXNfZGVtby80NyI6dHJ1ZSwiaHBhcmFtc19kZW1vLzQ3L3RyYWluIjp0cnVlLCJocGFyYW1zX2RlbW8vNDcvdmFsaWRhdGlvbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzQ4Ijp0cnVlLCJocGFyYW1zX2RlbW8vNDgvdHJhaW4iOnRydWUsImhwYXJhbXNfZGVtby80OC92YWxpZGF0aW9uIjp0cnVlLCJocGFyYW1zX2RlbW8vNDkiOnRydWUsImhwYXJhbXNfZGVtby80OS90cmFpbiI6dHJ1ZSwiaHBhcmFtc19kZW1vLzQ5L3ZhbGlkYXRpb24iOnRydWUsIm1uaXN0L2xyXzFFLTAzLGNvbnY9MSxmYz0yIjp0cnVlLCJtbmlzdC9scl8xRS0wMyxjb252PTIsZmM9MiI6dHJ1ZSwibW5pc3QvbHJfMUUtMDQsY29udj0xLGZjPTIiOnRydWUsIm1uaXN0L2xyXzFFLTA0LGNvbnY9MixmYz0yIjp0cnVlLCJvbGRfdGV4dCI6dHJ1ZSwid29yZHNfZGVtb19hcmNoaXZlL3VidW50dSI6dHJ1ZSwid29yZHNfZGVtb19hcmNoaXZlL3JlZGhhdCI6dHJ1ZSwid29yZHNfZGVtb19hcmNoaXZlIjp0cnVlLCJ3b3Jkc19kZW1vIjp0cnVlLCJ3b3Jkc19kZW1vL2Q9dWJ1bnR1LHNxcnRfc2FtcGxlcz0yIjp0cnVlLCJ3b3Jkc19kZW1vL2Q9dWJ1bnR1LHNxcnRfc2FtcGxlcz0zIjp0cnVlLCJ3b3Jkc19kZW1vL2Q9dWJ1bnR1LHNxcnRfc2FtcGxlcz00Ijp0cnVlLCJ3b3Jkc19kZW1vL2Q9dWJ1bnR1LHNxcnRfc2FtcGxlcz01Ijp0cnVlLCJ3b3Jkc19kZW1vL2Q9dWJ1bnR1LHNxcnRfc2FtcGxlcz02Ijp0cnVlLCJ3b3Jkc19kZW1vL2Q9dWJ1bnR1LHNxcnRfc2FtcGxlcz03Ijp0cnVlLCJ3b3Jkc19kZW1vL2Q9dWJ1bnR1LHNxcnRfc2FtcGxlcz04Ijp0cnVlLCJ3b3Jkc19kZW1vL2Q9cmVkaGF0LHNxcnRfc2FtcGxlcz0yIjp0cnVlLCJ3b3Jkc19kZW1vL2Q9cmVkaGF0LHNxcnRfc2FtcGxlcz0zIjp0cnVlLCJ3b3Jkc19kZW1vL2Q9cmVkaGF0LHNxcnRfc2FtcGxlcz00Ijp0cnVlLCJ3b3Jkc19kZW1vL2Q9cmVkaGF0LHNxcnRfc2FtcGxlcz01Ijp0cnVlLCJ3b3Jkc19kZW1vL2Q9cmVkaGF0LHNxcnRfc2FtcGxlcz02Ijp0cnVlLCJ3b3Jkc19kZW1vL2Q9cmVkaGF0LHNxcnRfc2FtcGxlcz03Ijp0cnVlLCJ3b3Jkc19kZW1vL2Q9cmVkaGF0LHNxcnRfc2FtcGxlcz04Ijp0cnVlLCJhdWRpb19kZW1vLzAxX3NpbmVfd2F2ZSI6dHJ1ZSwiYXVkaW9fZGVtby8wMl9zcXVhcmVfd2F2ZSI6dHJ1ZSwiYXVkaW9fZGVtby8wM190cmlhbmdsZV93YXZlIjp0cnVlLCJhdWRpb19kZW1vLzA0X2Jpc2luZV93YXZlIjp0cnVlLCJhdWRpb19kZW1vLzA1X2Jpc2luZV93YWh3YWhfd2F2ZSI6dHJ1ZSwicHJvZmlsZV9kZW1vIjp0cnVlLCJwcm9maWxlX29ubHlfZGVtbyI6dHJ1ZX0

These URLs are more awkward to use and share for users. They’re also
opaque, which means that users have less visibility into what parts of
their state they’re sharing and it’s hard for them to trim out parts of
the URL that aren’t necessary. Complaints about the run selection state
URL format go back a long time, so we’d like to prevent adding more
opaque blobs where possible.

With the object structure proposed above, even a minimal object, with an
empty custom dict, would look like one of these:

http://localhost:6006/#colorScheme=tensorboardColorBlindAssist
http://localhost:6006/#colorScheme=eyJiYXNlIjoidGVuc29yYm9hcmRDb2xvckJsaW5kQXNzaXN0IiwiY3VzdG9tIjp7fX0K

and with a few overrides you get one of these:

http://localhost:6006/#colorScheme=tensorboardColorBlindAssist&customColors=key1:abcdef,key2=123456
http://localhost:6006/#colorScheme=eyJiYXNlIjoidGVuc29yYm9hcmRDb2xvckJsaW5kQXNzaXN0IiwiY3VzdG9tIjp7ImtleTEiOiIjYWJjZGVmIiwia2V5MiI6IiMxMjM0NTYifX0K

which are both shorter and clearer. As you note, base64 will always
have a factor-4/3 overhead, and JSON adds a bit, too.

We’ve discussed this a bit internally for related changes (though not
for this one specifically that I can recall) and opted to try to create
new pieces of URL states as simple string-to-string keys for this
reason.

@dgrahn
Copy link
Contributor

dgrahn commented Aug 3, 2020 via email

@stephanwlee
Copy link
Contributor

With common understanding that local storage based solution can scale to ~5MB (total data size for a given host, I believe) and that TensorBoard shared by colleagues will look different than the sharer, I have questions about the data structure.

{
    "base": "[palette-name]",
    "linkTrainVal": false,
    "custom": {
        "key": "[custom color]",
        ....
    }
}
  • what is the linkTrainVal?
  • with this solution, I presume you can switch back and forth between color palette (accessible 8 colors <-> expanded 20 colors) and keep the custom color tied to the palette. Is this behavior preferable as opposed to just having a runColor override so you do not have color override per palette and overriden color stay the same across palette changes? I would argue that latter is simpler to implement and provide simpler mental model to the users.

@dgrahn
Copy link
Contributor

dgrahn commented Aug 4, 2020

linkTrainVal will ensure that training and validation nested runs have the same color with different saturations. I don't have to implement that feature, but when I switched my default palette to matplotlib's tab20, the linked colors was extremely useful.

For custom colors, I was planning on having them reset after each palette change. But maybe that should be an option as well?

@stephanwlee
Copy link
Contributor

stephanwlee commented Aug 4, 2020

Too many options are generally not a good idea because (1) it is more flow/code to maintain and (2) more complex user's mental model. In this case, I will not make that judgement.

RE matplotlib's tab20: we have to make sure there is no copyright infringement there. I have not dug deeper into this but it seems to be BSD. I am not sure if we do BSDs.

1: https://github.com/matplotlib/matplotlib/blob/ede8e566e5c7e7a12fdd66231ba02f363aab8913/lib/matplotlib/_cm.py#L1269-L1272
2: https://github.com/vega/vega/blob/master/LICENSE

@dgrahn
Copy link
Contributor

dgrahn commented Aug 4, 2020

@stephanwlee In that case, we'll just have them reset after palette change. So here's the new plan.

  1. Palette change option in settings menu
  2. Custom color option somewhere in the run selector
  3. Settings stored in local storage.

How would we feel about a "dynamic" palette which would simply choose the n most divergent colors where n is the number of runs?

@wchargin
Copy link
Contributor

wchargin commented Aug 4, 2020

Is the consensus that we need to use the URL?

I was imagining that we wanted this to be in the URL because people will
share links and expect the colors to be shared as well, to avoid
confusion when discussing the charts. But I could be convinced
otherwise, and I could also be convinced to start with it in local
storage and see if that works for people. It’s true that that gives more
flexibility about the representation.

it seems to be BSD

BSD 3-Clause is okay:
https://opensource.google/docs/thirdparty/licenses/#notice

So here's the new plan. […]

This sounds fine to me.

How would we feel about a "dynamic" palette which would simply choose
the n most divergent colors where n is the number of runs?

One problem with this is that the number of runs grows over time, so
this would mean that as new data loads the colors for existing runs
change. We currently go to some lengths to avoid this: e.g., we sort
runs in order of start time, rather than alphabetically, so that the
ordering is time-stable. Any ideas on how to address this?

@dgrahn
Copy link
Contributor

dgrahn commented Aug 5, 2020

The dynamic palette would change colors as runs change. We don't have to include that, but it could be a useful feature.

Sounds like we have a path forward. Has the migration been completed?

@manivaradarajan
Copy link
Member

No, the migration hasn't completed yet, though we've made very good, substantial progress. We'll keep you posted.

@martinpopel
Copy link
Author

I think that by default the color of any run should not change when the number of runs has changed (when new runs were added, or when some runs were deleted) or when the number of selected runs has changed (by editing the regex or clicking on checkboxes). Thus I don't like the "dynamic palette" as the default option and personally I don't need it at all.

Usually, I have hundreds of runs, so coloring them with n>200 most divergent colors does not make sense (there will be many pairs of colors indistinguishable for me). Usually, I select (via regex or checkboxes) up to about 10 runs to be shown, but I change the selected subset often and I don't want any color to be changed automatically when changing the selection (I want to change the colors manually ad hoc, which is what this issue is about).

Usually, I have several browser tabs open with different subsets of runs selected in TensorBoard. Sometimes, there is an overlap between the subsets, ie. the same run is shown in multiple browser tabs. Sometimes, I share the TensorBoard server with my colleagues. Originally, I thought the simplest implementation will be client-side only, ie. changing the run color in one browser tab won't affect the color in other tabs (and other browsers of my colleagues). However, the other option (the color is stored on the server side and changed everywhere) is also acceptable for me. Both options have some pros and cons depending on the various use cases.

@stephanwlee
Copy link
Contributor

@dgrahn The Polymer migration is done and we can now take in all the changes. Thanks for waiting.

@sharvil
Copy link

sharvil commented Nov 11, 2020

@wchargin @stephanwlee until this issue is fixed, what you do you recommend users do when two or more runs that need to be compared end up with the same color?

@martinpopel
Copy link
Author

@sharvil: see my list of workarounds above - #893 (comment)

@stephanwlee
Copy link
Contributor

We have some update to this bug.

background: We were not too happy with the state of things with current platform and we have been eager to upgrade our framework to Angular. As you might have noticed, there was a whole infra upgrade to Angular recently and, on the side, we have been working on a new plugin called Time Series which tries to combine all time series metric based plugins into one view (it is currently arbitrary divided). The new plugin was available in tb-nightly for some time so you may have noticed that

image

Now, in the new plugin, we added an ability to click on the fob and override the color there and it is available in yesterday's release https://github.com/tensorflow/tensorboard/releases/tag/2.4.0. I know it does not solve everyone's problem and it is still a bit painful to use. Namely:

  • color override information gets lost when refreshed
  • color palette is still limited to handful of colors.

However, do know that we will be adding features to the new plugin and we hope to be a lot more robust with it.

@liusida
Copy link

liusida commented Jan 24, 2021

We have some update to this bug.

background: We were not too happy with the state of things with current platform and we have been eager to upgrade our framework to Angular. As you might have noticed, there was a whole infra upgrade to Angular recently and, on the side, we have been working on a new plugin called Time Series which tries to combine all time series metric based plugins into one view (it is currently arbitrary divided). The new plugin was available in tb-nightly for some time so you may have noticed that

image

Now, in the new plugin, we added an ability to click on the fob and override the color there and it is available in yesterday's release https://github.com/tensorflow/tensorboard/releases/tag/2.4.0. I know it does not solve everyone's problem and it is still a bit painful to use. Namely:

  • color override information gets lost when refreshed
  • color palette is still limited to handful of colors.

However, do know that we will be adding features to the new plugin and we hope to be a lot more robust with it.

The new "Time Series" option is great! Thanks!
image

I can manually pick colors for each run.

I wonder, why not decouple the Website and the backend, so people might be able to create Websites with different styles! I guess it is quite hard for a web designer to use Bazel to compile source code.

Thanks.

@psybuzz
Copy link
Contributor

psybuzz commented Jan 25, 2021

@liusida, glad to hear that the Time Series dashboard is usable for you.

it is quite hard for a web designer to use Bazel to compile source code.

For anyone interested in extending the web frontend of TensorBoard for their own purpose, one option that the team maintains is a path to building custom frontend plugins. In case you have not seen before, here is an example [1] with code that shows how to reuse the scalars backend data and write your own dashboard with custom styles in HTML, CSS, JS. Custom plugins that users create can be published and shared on PyPI as well. More details can be found at [2]. If this interests you, please feel free to request features and ask more questions!

[1] https://github.com/tensorflow/tensorboard/tree/javascript/tensorboard/examples/plugins/example_raw_scalars
[2] https://github.com/tensorflow/tensorboard/blob/javascript/ADDING_A_PLUGIN.md

@jettero
Copy link

jettero commented Oct 30, 2021

Too many options are generally not a good idea because (1) it is more flow/code to maintain and (2) more complex user's mental model. In this case, I will not make that judgement.

I'm reading this as, "I don't have this problem, so if we provide these options and people use them to fix readability problems they're having; it's a giant waste of time because I'm not having this problem."

I can't think of another way to interpret it.

@TevenLeScao
Copy link

Is there currently any way to keep a set color scheme after refreshing/reloading the page?

@pierre-nedelec
Copy link

We have some update to this bug.

background: We were not too happy with the state of things with current platform and we have been eager to upgrade our framework to Angular. As you might have noticed, there was a whole infra upgrade to Angular recently and, on the side, we have been working on a new plugin called Time Series which tries to combine all time series metric based plugins into one view (it is currently arbitrary divided). The new plugin was available in tb-nightly for some time so you may have noticed that

image

Now, in the new plugin, we added an ability to click on the fob and override the color there and it is available in yesterday's release https://github.com/tensorflow/tensorboard/releases/tag/2.4.0. I know it does not solve everyone's problem and it is still a bit painful to use. Namely:

  • color override information gets lost when refreshed
  • color palette is still limited to handful of colors.

However, do know that we will be adding features to the new plugin and we hope to be a lot more robust with it.

This is great work, thank you! especially the new option to color runs by regex, this is awesome.

One next step could be to be able to choose the color assigned to each group on this page, wouldn't it? Currently colors are automatically assigned to each group and we can't change them. Like this if we have many groups we could create something that has more visual meaning. It sounds similar to what was described above, being able to click on the fob to pick the color.

image

@drmeerkat
Copy link

What is the current status of this request? I would really love to see colors being persistent after refresh.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests