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.
This could be useful. Note that jscolor itself though we couldn't use since it's GPL.
OK, jscolor is not needed (it was just an example). Choosing e.g. from 16 pre-defined colors would be enough for my needs.
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.
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.
A way to change color in config/code/command line is better than nothing, although I'd favor a Web UI too.
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?
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.
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?
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.
One thing you might be able to do is render a matplotlib image and log it as an image summary.
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):
--logdir pointing to this directoryI 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.
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.
What do we think about the following solutions?
@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:
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.
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.
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.
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).
Any updates? TF2's out, TB remains unicolored - the issue's still relevant
Hi, are there any updates on this issue? I'm having the same problem but with the scatter plot colors with the tensorboard projector.
What about developing a mode for colorblind users and a mode for normal people, that would meet the needs of everyone
Any update on this?
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 ..

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)
-iteration02 (blue)
I beleive many people facing a similar problem or even in a different setting, can find such a solution more helpful.
@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: Why don't you move the event files from all sub-directories to the same directory? This can be done with a single
mvcommand (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 !
As an alternative to a full-blown UI solution, could we have the option to load a new palette of colors? It would be nice to have... 20 different colors rather than the few there are now.
Any update on this? Some of the UI based suggestions really seem like low hanging fruit for improving Tensorboard significantly.
It may be a good option to implement it as a color parameter for tf.summary.create_file_writer(). This would already open up a world of possibilities, and may be easier than UI changes.
Just to reiterate, UI options would always be better in dealing with the ad-hoc needs of a user during analysis.
As an alternative to a full-blown UI solution, could we have the option to load a new palette of colors? It would be nice to have... 20 different colors rather than the few there are now.
or at least not gray... can i get an amen
how to change the curve color of tensorboard?
Alrighty. I got tired of this lingering, so I decided to take it on. I can't change the assignee, but if someone could assign me, that would be great.
I don't have a full solution yet, but I can get you 20 colors. Working on making this a toggleable option now.
tensorboard/components/tf_color_scale/palettes.ts with the code from this Gist: https://gist.github.com/dgrahn/ac4a567ee023cd7d326602d4f15ee71dAll,
The current color mapping system is rather rudimentary. It maps the list of runs (or experiments) to a list of colors. The colorscale itself has no knowledge of what is shown on the screen.
Here is my proposed solution, I would love anyone following this to chime in.
Thoughts?
Dan, thanks for taking this on and thinking about this issue.
TensorBoard's color palette was chosen for accessibility reasons, and we want to make sure we don't want to regress on that (see https://github.com/tensorflow/tensorboard/pull/288 for context).
A run selector UI control to switch color palettes amongst a pre-defined set of palettes is definitely a good idea. Yes, ideally it should be persistent. It may take some back and forth to design this correctly.
Just wanted to forward some resources that can be helpful for this kind of stuff. For accessibility, the standards we use are the WCAG 2 AA contrast ratio thresholds (description and tool here just in case these colors become used with text).
After reading the recommendations, it looks like you're taking these concerns very seriously and I wanted to thank you for this!
Work on this issue will be stored on this branch. Feel free to checkout and review the work, or even contribute. The following changes have been made so far.
Work that needs to be done.
I've used the work of @stephanwlee as a guide. A few questions for whoever is listening.
@dgrahn A few notes to make this go more smoothly.
First of all, thank you again for taking on this longstanding user request. We discussed this feature request very recently on our team and it is a complicated one, so I want to forewarn you that there will be some architectural complications. To help you through this, @wchargin from the TensorBoard core team will work with you and advise you.
Second, TensorBoard team currently is in process of migrating to Polymer 3 and the build rules. To prevent thrashing, please pause your work until we are done with the migration. (See https://github.com/tensorflow/tensorboard/issues/3887).
Finally, some general pointers:
No problem. I have the updating logic all working on a listener off of the
color scale, but didn't realize storage already had listeners. I'll take
care of that.
Will you ping here when the Polymer 3 merge is done?
On Mon, Jul 27, 2020, 5:22 PM Mani Varadarajan notifications@github.com
wrote:
@dgrahn https://github.com/dgrahn A few notes to make this go more
smoothly.First of all, thank you again for taking on this longstanding user
request. We discussed this feature request very recently on our team and it
is a complicated one, so I want to forewarn you that there will be some
architectural complications. To help you through this, @wchargin
https://github.com/wchargin from the TensorBoard core team will work with
you and advise you.Second, TensorBoard team currently is in process of migrating to Polymer 3
and the build rules. To prevent thrashing, please pause your work until we
are done with the migration. (See #3887
https://github.com/tensorflow/tensorboard/issues/3887).Finally, some general pointers:
-
tf-tensorboard is deprecated. Please refer to tensorboard/webapp for
the new entry point. Angular is the new future for TensorBoard.
-In order to make the color scale changes reflect on components:
- create a colorPalette setting with on tf-storage (enum of strings)
- create a new method on colorScale.ts, getColorScaleForPalette
- make whatever component that uses colorScale listen to the
colorPalette change and use the computed property to get a colorScale.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/tensorflow/tensorboard/issues/893#issuecomment-664645254,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AADALVOZCZUS3FZO2L6SLKTR5XVZRANCNFSM4EMUCTXA
.
Will you ping here when the Polymer 3 merge is done?
Yes, will do.
@manivaradarajan I want to circle back to the architecture proposed above. Right now, I'm only planning on letting the palette be changed between preset options. But many people above have asked for a color picker.
Based on this, I'm thinking the more future-proof way of implementing is to store the palette as an object in tf_storage. Something like the following.
{
"base": "[palette-name]",
"linkTrainVal": false,
"custom": {
"key": "[custom color]",
....
}
}
Thoughts?
@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.
@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.
@martinpopel Would a color picker like this work for you? https://www.webcomponents.org/element/@polymer/paper-swatch-picker
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!
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.
@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?
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.
That's for URL parameters. I was planning on using the local storage option.
Is the consensus that we need to use the URL? Even with strong to string
keys, that would get long for custom colors.
On Mon, Aug 3, 2020, 6:43 PM William Chargin notifications@github.com
wrote:
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=eyJiYXNlIjoidGVuc29yYm9hcmRDb2xvckJsaW5kQXNzaXN0IiwiY3VzdG9tIjp7fX0Kand with a few overrides you get one of these:
http://localhost:6006/#colorScheme=tensorboardColorBlindAssist&customColors=key1:abcdef,key2=123456
http://localhost:6006/#colorScheme=eyJiYXNlIjoidGVuc29yYm9hcmRDb2xvckJsaW5kQXNzaXN0IiwiY3VzdG9tIjp7ImtleTEiOiIjYWJjZGVmIiwia2V5MiI6IiMxMjM0NTYifX0Kwhich 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.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/tensorflow/tensorboard/issues/893#issuecomment-668276673,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AADALVKQAMNHQJ2N7MWNHETR644S7ANCNFSM4EMUCTXA
.
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]",
....
}
}
linkTrainVal?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?
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
@stephanwlee In that case, we'll just have them reset after palette change. So here's the new plan.
How would we feel about a "dynamic" palette which would simply choose the n most divergent colors where n is the number of runs?
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?
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?
No, the migration hasn't completed yet, though we've made very good, substantial progress. We'll keep you posted.
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.
@dgrahn The Polymer migration is done and we can now take in all the changes. Thanks for waiting.
@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?
@sharvil: see my list of workarounds above - https://github.com/tensorflow/tensorboard/issues/893#issuecomment-377132932
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

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:
However, do know that we will be adding features to the new plugin and we hope to be a lot more robust with it.
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
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!

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.
@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
Most helpful comment
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.