tensorflow / tensorboard

TensorFlow's Visualization Toolkit
Apache License 2.0
6.67k stars 1.65k forks source link

Allow ad-hoc color changing #893

Open martinpopel opened 6 years ago

martinpopel commented 6 years ago

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.

nfelt commented 6 years ago

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

martinpopel commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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

jart commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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

martinpopel commented 6 years ago

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):

netheril96 commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

@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:

  1. 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.
  2. 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).
  3. 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 commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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 commented 4 years ago

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

jrenrut commented 4 years ago

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 commented 4 years ago

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

nicofirst1 commented 4 years ago

Any update on this?

ham952 commented 4 years ago

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)

-iteration02 (blue)

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

martinpopel commented 4 years ago

@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 commented 4 years ago

@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 !

dgrahn commented 4 years ago

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.

Trezorro commented 4 years ago

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.

jkyl commented 4 years ago

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

fanyuzeng commented 4 years ago

how to change the curve color of tensorboard?

dgrahn commented 4 years ago

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.

dgrahn commented 4 years ago

All, 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.

  1. Add a drop-down to the settings menu to allow the palette to be changed. Ideally, this would persist between refreshes.
  2. Add several color palettes with additional colors. Matplotlib has one with 20 distinct colors.
  3. Parse run names. If there are runs that have /training and /validation, then assign a color to the validation run and use a slightly desaturated version for the training run.

Thoughts?

manivaradarajan commented 4 years ago

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.

hfiller commented 4 years ago

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!

dgrahn commented 4 years ago

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.

  1. None of the settings are currently persisting after a refresh for me. Is anyone else experiencing this issue?
  2. There appears to be another settings screen in tf-tensorboard.html:45-61. I can't figure out how this settings dialog is toggled. Is this out of date?
  3. Does anyone know how to generate a PR demo?
manivaradarajan commented 4 years ago

@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:

dgrahn commented 4 years ago

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 .

manivaradarajan commented 4 years ago

Will you ping here when the Polymer 3 merge is done?

Yes, will do.

dgrahn commented 4 years ago

@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?

martinpopel commented 4 years ago

@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 commented 4 years ago

@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 commented 4 years ago

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

wchargin commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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=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.

— 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 .

stephanwlee commented 4 years ago

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]",
        ....
    }
}
dgrahn commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

@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?