Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Improve draw #400

Merged
merged 89 commits into from
Nov 5, 2020
Merged

Improve draw #400

merged 89 commits into from
Nov 5, 2020

Conversation

kwcantrell
Copy link
Collaborator

@antgonza if you have some spare time, can you test this pr on one of your large trees? thanks

kwcantrell and others added 30 commits August 7, 2020 16:57
Ports the three test cases we had for the rectangular layout
(wasn't getting used anywhere. why was i keeping track of this lol)
Progress on biocore#184. Since it looks like the unrooted layout handles
these properly, all that's left for this issue should be just not
drawing arcs for internal nodes with 1 child. Should be doable by
modifying the js circular layout to give 1-child nodes -1 for their
arc / angle values or something to signal to empress.js to not bother
with arcs.
related to biocore#271, but needs extending to other layouts
I was having precision issues with the circular layout scaling
(tldr: Math.cos(Math.PI / 2) is very close to but not quite 0, so
it was messing up the max / min X computation), but this makes it
so we shouldn't have to even worry about things for this case.
Closes biocore#184! I forget if i already did that so i'm doing it again.
@ElDeveloper ElDeveloper added this to the Second Beta Release milestone Oct 13, 2020
@emperor-helper
Copy link

The following artifacts were built for this PR: empire-biplot.qzv, empire.qzv, empress-tree.qzv, just-fm.qzv, plain.qzv

@kwcantrell kwcantrell changed the title [WIP] Improve draw Improve draw Oct 14, 2020
Copy link
Collaborator

@fedarko fedarko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks cool, thanks for getting this ready!

Read over things, and I have a few suggestions. I think the most important are:

  • The structure of the getTreeCoords / getTreeColor functions in empress.js -- would it be possible to merge these back into a single function, maybe by adding a parameter that controls whether it returns colors or coordinates? I think duplicating this logic will cause some problems (although I understand that it's already kinda duplicated between getCoords and thickenColoredNodes now, though).

  • Use of 256 as the "base" for the compressed colors -- since hex colors range from [0, 255], I think we should use 255 instead.

Also, I am not sure what is causing it, but it looks like there is a strange bug when turning off collapsed clades where the colors become broken and some nodes remain hidden. My guess is that this might be a problem with getTreeCoords and getTreeColor getting out of sync, but I'm not confident about that.

buug

empress/support_files/js/colorer.js Show resolved Hide resolved
empress/support_files/js/colorer.js Show resolved Hide resolved
empress/support_files/js/drawer.js Outdated Show resolved Hide resolved
empress/support_files/js/empress.js Outdated Show resolved Hide resolved
empress/support_files/js/empress.js Outdated Show resolved Hide resolved
tests/test-circular-layout-computation.js Outdated Show resolved Hide resolved
tests/test-circular-layout-computation.js Show resolved Hide resolved
empress/support_files/js/drawer.js Outdated Show resolved Hide resolved
empress/support_files/js/drawer.js Outdated Show resolved Hide resolved
empress/support_files/js/drawer.js Outdated Show resolved Hide resolved
@kwcantrell
Copy link
Collaborator Author

Thanks @fedarko for the feedback. I believe all of your comments have been addressed.

A couple of things:

  1. I fixed the collapse clades issue you pointed out (good catch)
  2. I also fixed the export svg function

The structure of the getTreeCoords / getTreeColor functions in empress.js -- would it be possible to merge these back into a single function, maybe by adding a parameter that controls whether it returns colors or coordinates? I think duplicating this logic will cause some problems (although I understand that it's already kinda duplicated between getCoords and thickenColoredNodes now, though).

I think this should get moved to a different PR. We already have multiple functions that use the same pattern so, creating a single function will require a bit of restructuring that I is a bit outside of the scope of this PR.

@fedarko
Copy link
Collaborator

fedarko commented Oct 28, 2020

Going through now, changes look great. It looks like the clade collapsing is mostly fixed, but I think there's still some issues with collapsing and the rectangular / circular layouts. It looks like turning off collapsing doesn't re-draw the arcs in the circular layout or the vertical lines in the rectangular layout, and causes some coloring problems:

Circular layout:
hm

Rectangular layout:
hm2

It also looks like turning off coloring in general doesn't fix this, either (the arcs/lines only seem to come back when I uncheck "collapse clades"):
hm3

I think the issue may have to do with resetTree(), and that getTreeCoords() is called before this._collapsedClades is reset (which causes the vertical lines / arcs to not be drawn since they're still included in the now-removed collapsed clades). But I'm not 100% sure -- something similar also might be what's messing with the colors not being correct.

@kwcantrell
Copy link
Collaborator Author

kwcantrell commented Oct 28, 2020

good catch @fedarko! It should be fixed now.

Copy link
Collaborator

@fedarko fedarko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't gone through all of the export util / empress stuff yet, but have gone through about everything else. Have a few mostly small comments. This is looking great, thanks so much!!!

empress/support_files/js/colorer.js Outdated Show resolved Hide resolved
empress/support_files/js/colorer.js Outdated Show resolved Hide resolved
empress/support_files/js/colorer.js Outdated Show resolved Hide resolved
empress/support_files/js/drawer.js Outdated Show resolved Hide resolved
empress/support_files/js/drawer.js Outdated Show resolved Hide resolved
empress/support_files/js/empress.js Outdated Show resolved Hide resolved
tests/test-legend.js Show resolved Hide resolved
@@ -119,7 +123,7 @@ define(["underscore", "chroma"], function (_, chroma) {

// create a circle for each node
if (drawer.showTreeNodes) {
radius = drawer.NODE_CIRCLE_DIAMETER / 2;
var radius = drawer.NODE_CIRCLE_DIAMETER;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the var is needed :), but I think we should still divide this by 2 right?

... I guess it doesn't matter too much since the "units" are kind of arbitrary, but idk.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The circles were not really visible when we divide by 2 (at least on my monitor with the moving pictures data set)

Linked are two svg. One that divides the diameter by 2 and one that does not. Let me know which one looks better - it could just be my monitor :).

examples.zip

Copy link
Collaborator

@fedarko fedarko Nov 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the examples! It's subjective, but I think keeping the division by 2 looks slightly better, so I think we should stick with that for right now. It does make it harder to see node circles when zoomed out, but things look less cluttered when the SVGs are zoomed in (... at least on my computer :) --

with division by 2:
image

with no division by 2:
image

Neither solution is great, honestly, since the size of node circles isn't proportional to the tree size or anything. We should ideally try to scale node circles based on the tree dimensions, similarly to the stuff for edge thicknesses described in #276.

empress/support_files/js/select-node-menu.js Show resolved Hide resolved
tests/test-circular-layout-computation.js Outdated Show resolved Hide resolved
Copy link
Collaborator

@fedarko fedarko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this looks good! (And sorry for taking a few days to get back to you on this.) The bulk of this is basically ready as is, but there are some documentation / internal code things I think we should sort out first.

Besides the comments I made here, there are a few places with old documentation saying "RGB arrays" instead of RGB floats, including:

Part of Empress.colorSampleGroups():

// convert hex string to rgb array
var rgb = Colorer.hex2RGB(group);

Collapsed clade data:

* color: <[r,g,b]>

Part of Empress._colorTree():

* @param{Object} cm Maps categories to the colors to color their nodes
* with. Colors should be represented as RGB arrays, for
* example as is done in the color values of the output
* of Colorer.getMapRGB().
*/
Empress.prototype._colorTree = function (obs, cm) {

Part of BarplotLayer.initFMDiv():

// To my knowledge, there isn't a straightforward way of
// getting an RGB array out of the "TinyColor" values passed in
// by Spectrum: see
// https://bgrins.github.io/spectrum#details-acceptedColorInputs
scope.defaultColor = Colorer.hex2RGB(newColor.toHexString());

The border color stuff in the barplot panel handler:

// Borders (when enabled) default to white. (This is an RGB array.)
this.borderColor = [1, 1, 1];

// this.borderColor is always a RGB array, for the sake of everyone's
// sanity. However, spectrum requires that the specified color is a hex
// string: so we have to convert it to hex first here (only to later
// convert it back to RGB on change events). Eesh!
// A SILLY NOTE: Apparently chroma.gl() modifies the input RGB array if
// you pass it in directly, converting it into a weird thing that
// is represented in the browser console as "(4) [255, 255, 255,
// undefined, _clipped: false, _unclipped: Array(3)]". Unpacking the
// input array using ... (as done here with this.borderColor) seems to
// avoid this problem.
var startingColor = chroma.gl(...this.borderColor).hex();
$(this.borderColorPicker).spectrum({
color: startingColor,
change: function (newColor) {
scope.borderColor = Colorer.hex2RGB(newColor.toHexString());
},
});

var borderColor = this._barplotPanel.borderColor;
var borderLength = this._barplotPanel.borderLength;
var maxD = prevLayerMaxD + borderLength;
// TODO: Should be changed when the ability to change the background
// color is added. Basically, we get a "freebie" if the border color
// matches the background color, and we don't need to draw anything --
// we can just increase the displacement and leave it at that.
// (This works out very well if this is the "outermost" border -- then
// we really don't need to do anything.)
if (
borderColor[0] === 1 &&
borderColor[1] === 1 &&
borderColor[2] === 1
) {
return maxD;
}

I haven't gone extremely thoroughly through things yet, so there may be additional places throughout the code/docs which exhibit this problem.

None of these are really urgent issues, since only one of them impacts the user directly, but I would like to try to fix as many of them as we can in advance (to avoid the master codebase having confusing docs).

For what it's worth the barplot panel handler stuff does very slightly impact the program behavior -- the "freebie" checking stuff should be changed to check if the border color is equal to exactly white (as a float), rather than the current behavior which still assumes that the color is stored as an RGB array. The consequence of this right now is that "freebies" are detected whenever the border color is unchanged (since it defaults to [1,1,1]), but even if the user changes the color and then changes it back to exactly white (16777215), no "freebie" is given since the checks still assume this is an array. This makes drawing barplot borders slower... albeit in this one, extremely tiny corner case :P

Anyway, hope this clarifies things. Happy to zoom sometime this week and go through these, or to just defer some of this work to a new issue if you'd prefer (since we have a lot of open PRs to get through). Thanks so much!

Comment on lines 88 to 90
// So, if coords[node+2] == DEFAULT_COLOR then coords[node+2+5] will
// also be equal to DEFAULT_COLOR. Thus, we can save checking three
// array elements here.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// So, if coords[node+2] == DEFAULT_COLOR then coords[node+2+5] will
// also be equal to DEFAULT_COLOR. Thus, we can save checking three
// array elements here.

I think we'd need to update this comment about the colors array -- honestly I'd be ok just removing this comment since I'm not sure if it's really applicable here.

@@ -313,6 +313,36 @@ define(["chroma", "underscore", "util"], function (chroma, _, util) {
return _.mapObject(this.__valueToColor, Colorer.hex2RGB);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't comment on it directly (??? github is weird), but the docs comment for getMapRGB should be updated to mention that the colors are RGB floats not arrays

@fedarko fedarko merged commit fd159e1 into biocore:master Nov 5, 2020
fedarko added a commit to fedarko/empress that referenced this pull request Nov 5, 2020
kwcantrell pushed a commit that referenced this pull request Nov 5, 2020
…ength legends; export collapsed clade shapes and barplots (#392)

* ENH: support collecting+exporting barplot legends

* BUG: Fix legend SVG title centering; <g> => <svg>

Also added a newline after </style>

* BUG: Improve legend SVG for SVG importers

-Use "long form" font specification for the style SVG (fixes problems
 with GIMP and Inkscape)
-Put the style code higher up in the output legend SVG -- has the
 effect of applying the rect stroke to the topmost legend rect, which
 was a problem in Inkscape but not in chromium (:thonk:)
-Add note about GIMP choking on dominant-baseline (tldr not worth
 worrying abt now i think)

* STY: reorder/split up text and .title svg styles

(the text styles are now across multiple lines)

* MNT: hang on to continuous props in Legend for SVG

similar to what we do for categorical export

* ENH: add newlines to within gradient svgs

make life less painful (tm)

* MNT: abstract some code within legend export; grad svg work

* MNT: Refactor colorer/legend handling of gradients

Now, things are split up into a "Solo" and "HTML" SVG -- the gradient
shown on the page is a combo of these, and the one we export is just
the Solo one. This makes scaling it properly for the export SO MUCH
EASIER AHH

All we gotta do now is just add in value text and update rowsUsed /
maxLineWidth. think that should be good?

oh also this is gonna explode the tests ofc. that is a job for TOMORROW
MARCUS (tm)

* ENH: Finish? gradient legend SVG exporting!

IT WORKS SO WELL AOGIHDSOIGHJ

something worth noting: there seems to be some unaccounted-for
horizontal padding on the right side in the cat legend export.
i matched it in the continuous legend export b/c it looks nice but
worth looking into...?

* MNT: add explicit padding to right side of cat SVG

it looks like things are the opposite from how i thought -- looks like
the perceived extra space was just due to the boldfont used in
estimating the texts (when you make the text bold it's almost snug
with the border on the right side). may as well add the same padding
as for the continuous legends so things look consistent ish.

Still, this leaves it kinda unclear as to why continuous legends were
so comparatively snug with the border until i added padding ... maybe
boldface numbers are just not that bigger? idk

UPDATE: yeah i checked it and bold numbers are basically the same size
but bold letters are much larger. mystery solved :100:

* ENH: initial support for exporting length legends

looks not great (gotta align max and min headers like in table)
but good enough tm

* ENH: make exported length legend look purdy

* STY: pret

* ENH: export collapsed clade shapes! #303

Actually not that bad. wack.

* ENH: draw full rectangle for unrooted collapsing

removes line in the middle

* ENH/STY: use stroke on svg triangles; prettify

* MNT: also use stroke for unrooted clade export

* DOC: document todos for clade collapsing export

* ENH: support exporting barplots in SVG!

Need to use paths for circular barplot curves, and maybe better
stuff for rect barplots. but it works :D

* Update readme re: #303 fixes :D

* PERF: Only specify stroke width for thick lines

since default is 1

* MNT: apply shape-rendering to SVG

shoutouts to https://stackoverflow.com/a/53309814/10730311.

this is very easy to configure (just a line in the svg header),
so if users prefer different things we can document this.

* MNT: make polygon exporting util func

* MNT: attempt to fix bounding box stuff

export is broken (height is somehow nan?) but at least this works now

* STY: prettify

* negate y coords and declare maxy in bb

still broken but much less so

* Space out adjacent polygon pts

fixes things! hey this works now

* PERF/BUG: don't even draw 0-length barplots

previously they were showing up in the SVG, probs due to precision
pbms. should beo k now

* STY: prett

* DOC: remove svg export disclaimer :D #303

* BUG: Fix #421

still gotta test, tho, which will likely need to be deferred until
after fixing the other pbms with this pr and tests .______.

* TST: fix a gradient svg test

* specify combined svg

* TST: split up test ref svgs by solo/html

* TST: Fix most of the colorer tests

* MNT: redo public attr stuff with a func approach

is safer -- delegates checking that colorer is continuous to, well,
colorer.

* TST: unbreak colorer tests!

* Say missing and/or not numeric in warning

* TST: unbreak legend tests :D

* STY: prettify tests

* MNT: Drastically simplify legend exporting

At least for cat legends -- no longer do we have to worry about
rows and units and all that. each legend just returns its width and
height, and that's all we care about.

* STY: pret

* UNBREAK CONTINUOUS LEGENDS :D

* Fix length legends

* ENH: show missing/nonnumeric warn in grad legends

* DOC: fix some docs stuff

* fix stats format

* populateTreeStats fixes

* STY: whoops

* MNT: Move radius bb expansion to sep function

addresses a comment from @kwcantrell

* PERF: don't cache barplot buffer

addresses @kwcantrell comment. Required breaking up the barplot
drawing stuff into a separate function that returns the coords

* BUG: fix reversed continuous color map legends

tldr gotta reverse the stop colors. reason this worked _before_ was
that it was accessing the interpolator to build up the stop colors

* simplify grad svg code a bit

* TST: test reverse color gradient bug is fixed

* STY

* MNT: Simplify gradient ID / suffix stuff

Addresses @kwcantrell comment.

* DOC: fix documentation stuff wrt #400
fedarko added a commit to fedarko/empress that referenced this pull request Nov 10, 2020
ElDeveloper added a commit that referenced this pull request Nov 16, 2020
…menu; fix "Add" button (#432)

* ENH: add BiomTable.hasFeatureID

* Prevent errors+warn on tips not in table #314

* fix warn msg

* tidy styling/stuff

* Make int sample presence handle bad case&test #314

still gotta clean up tests, and actually integrate this into the
selection menu, and etc. but a start.

* tidy up #314 int test

* child -> descendant tips in int sample presence

* TST: beef up int sample presence tests

* STY: prettifififify

* Show warning for int nodes w/ all tips not in tbl

Closes #314.

However, the UI here could still be improved a lot! So gonna tidy
things up a bit before getting this PR in. May knock out #272 while
we're at it.

* polish selected node menu a bit

Still kinda broken, but I think i have an idea of how to fix it

* TST: Add selected node menu test skeleton :D

Because manually testing this is going to give me a stroke

* TST: test a sel node menu error case; chg init'ing

Didn't seem like there was much of a reason to keep initialize out
of the selected node menu constructor, so just went ahead and moved
it there.

* TST/MNT: add + tidy up ssn tests; tidy err cases

since the tip case is afaict literally impossible to test

* More s.node menu tests; revamp HTML ._.

not thrilled about doing this the brute force way but it works

* beef up showNodeMenu tip test

* rename SelectedNodeMenu.notes to .smNotes

for clarity's sake, since .notes seems way more general than
the actual purpose this element serves

* beef up tip menu test

* MNT: simplify showing/hiding HTML eles in S.N.Menu

was getting tired of writing stuff out

* TODOs for menu fixing #314

* STY

* BUG: hide add ui eles after all sm fields added

Closes #272.

* Reorganize and restyle selection menu

Not done yet (gotta move stuff around for SM), but this already
makes the organization here clearer i think. Having FM and SM be
separate clearly marked sections should make things easier to
understand, since it will be very easy to say "oh this node has no
feature metadata" or "oh this node isn't in the table" (#314).

* STY: pret

* MNT: take advantage of makeFMtable being nonstatic

This makes calling this, and doing state-modifying stuff from
within this function, so much less of a pain. not sure why i thought
this would be a good idea back in june lmao

* MNT; take advantage of sm table being nonstatic

* some #314 esque menu fixes

have things planned out, just gotta go through and refactor stuff

* Refactor feature metadata in s.node menu

* css todo

* Refactor SM stuff :D

Closes #314 for good, I think. Some bugs (#272 rears its head again)
and i wanna test this, but this is already a big improvement

* Fix #272 bug (...again.)

ok this seems good. just gotta add tests and then pr should be ready

* STY

* TST: unbreak s. node menu tests

* Simplify s. node menu js tests :D

* TST: add an int node s node menu test

* Apparently qunit is case sensitive wrt "teardown"

:thinking:

I can't believe I just spent like 15 minutes trying to debug this lmao

* TST: test #272 case

wound up being a surprisingly large pain. turns out the (main) reason
was that we actually shouldn't have been creating a new selected
node menu in the tests; we should've just used the test data's
copy. Stuff was being initialized twice, so there were 6 (not 3)
s.m. fields in the <select>, and i was tearing my hair out lmao

* TST: test ambiguous internal node menu case

* MNT/TST: simplify js test code

* MNT/TST: abstract out fm table checking in snm tst

* test sm table population

* tidy up selected node menu code formatting

* STY: appease jshint by declaring a var in scope

WHOOPS

* TST: test sm notes txt in one of the cases

* checktips fix

* Update now-outdated-due-to-#400 comment

Thanks @ElDeveloper for pointing this out!

* Update empress/support_files/js/select-node-menu.js

Co-authored-by: Yoshiki Vázquez Baeza <[email protected]>

* HACK: Fix adjacent sm/fm section border CSS thing

YEEESH

* ENH: Actually, nvm, ditch menu section borders

But make things look a lot nicer -- e.g. show note in sm section when
no columns selected, remove extraneous <br />, etc.

* cats can have a little <hr />, as a treat

* TST: unbreak select node menu tests ._.

* STY: prettify test

Co-authored-by: Yoshiki Vázquez Baeza <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants