gramene-search 2.40.0 → 2.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8362,18 +8362,6 @@ const $9e29a4f60318db7a$var$Detail = (props)=>{
8362
8362
  studies,
8363
8363
  geneStudyIds
8364
8364
  ]);
8365
- // Without a baseline study the EBI Studies heatmap has nothing to draw (its
8366
- // request fails rather than coming back empty), so the tab says so and
8367
- // points at the differential EBI studies the gene does appear in -- e.g.
8368
- // Medicago truncatula, whose studies are all differential.
8369
- const ebiDifferential = (0, $gXNCa$react.useMemo)(()=>{
8370
- if (!geneStudyIds || !studies) return [];
8371
- const mine = new Set(geneStudyIds);
8372
- return studies.filter((e)=>mine.has(e._id) && $9e29a4f60318db7a$var$isDifferential(e) && !$9e29a4f60318db7a$var$isJgiStudy(e)).sort((a, b)=>$9e29a4f60318db7a$var$studyLabel(a) < $9e29a4f60318db7a$var$studyLabel(b) ? -1 : 1);
8373
- }, [
8374
- studies,
8375
- geneStudyIds
8376
- ]);
8377
8365
  const allJgiKey = JSON.stringify(allJgiStudies.map((e)=>[
8378
8366
  e._id,
8379
8367
  e.name
@@ -8478,32 +8466,21 @@ const $9e29a4f60318db7a$var$Detail = (props)=>{
8478
8466
  children: [
8479
8467
  gene.name || gene._id,
8480
8468
  " is not in any baseline expression study, so there is no heatmap here.",
8481
- ebiDifferential.length > 0 && /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsxs)((0, $gXNCa$reactjsxruntime.Fragment), {
8469
+ paralogQuery && atlasExperiment && /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsxs)((0, $gXNCa$reactjsxruntime.Fragment), {
8482
8470
  children: [
8483
8471
  ' ',
8484
- "It has results in ",
8485
- ebiDifferential.length === 1 ? 'a differential study' : `${ebiDifferential.length} differential studies`,
8486
- " at Expression Atlas:",
8487
- /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsx)("ul", {
8488
- className: "mt-1 mb-0",
8489
- children: ebiDifferential.map((e)=>/*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsxs)("li", {
8490
- children: [
8491
- /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsx)("a", {
8492
- href: `${$9e29a4f60318db7a$var$EBI_GXA}experiments/${encodeURIComponent(e._id)}/Results?geneQuery=${encodeURIComponent(JSON.stringify([
8493
- {
8494
- value: geneQuery
8495
- }
8496
- ]))}`,
8497
- target: "_blank",
8498
- rel: "noopener noreferrer",
8499
- children: e.description || e._id
8500
- }),
8501
- " (",
8502
- e._id,
8503
- ")"
8504
- ]
8505
- }, e._id))
8506
- })
8472
+ "To explore the differential expression of this gene and its paralogs, use the",
8473
+ ' ',
8474
+ /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsx)((0, $gXNCa$reactbootstrap.Button), {
8475
+ variant: "link",
8476
+ size: "sm",
8477
+ className: "p-0 align-baseline",
8478
+ onClick: ()=>setExpression({
8479
+ activeTab: 'paralogs'
8480
+ }),
8481
+ children: "Paralogs tab"
8482
+ }),
8483
+ "."
8507
8484
  ]
8508
8485
  })
8509
8486
  ]
@@ -8818,6 +8795,32 @@ function $cd8bc494277e92a4$export$965a6b1d7408d496(docs, tree) {
8818
8795
  }
8819
8796
  const $cd8bc494277e92a4$var$gridBorder = '1px solid var(--tbrowse-grid-line, rgba(0,0,0,0.06))';
8820
8797
  const $cd8bc494277e92a4$var$stressWidth = (width, organCount)=>Math.max($cd8bc494277e92a4$var$STRESS_MIN, width - organCount * $cd8bc494277e92a4$var$ORGAN_CELL_W - $cd8bc494277e92a4$var$MAXTPM_W);
8798
+ // "Expressed only" toggle. Homology applies it: while on (and the zone is
8799
+ // visible) it prunes every branch with no gene that has expression
8800
+ // attributes, and turning it on expands the branches that remain.
8801
+ const $cd8bc494277e92a4$var$ExpressedOnlyToggle = ({ on: on, onChange: onChange })=>/*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsxs)("label", {
8802
+ title: "Prune branches without expression data and expand the rest",
8803
+ style: {
8804
+ display: 'inline-flex',
8805
+ alignItems: 'center',
8806
+ gap: 3,
8807
+ fontSize: 10,
8808
+ cursor: 'pointer',
8809
+ whiteSpace: 'nowrap',
8810
+ margin: 0
8811
+ },
8812
+ children: [
8813
+ /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsx)("input", {
8814
+ type: "checkbox",
8815
+ checked: on,
8816
+ onChange: (e)=>onChange(e.target.checked),
8817
+ style: {
8818
+ margin: 0
8819
+ }
8820
+ }),
8821
+ "expressed only"
8822
+ ]
8823
+ });
8821
8824
  const $cd8bc494277e92a4$var$ExprHeader = ({ zoneState: zoneState, setZoneState: setZoneState, width: width, data: data, hoveredNodeId: hoveredNodeId })=>{
8822
8825
  const ea = data.hostData && data.hostData.exprAttrs || {};
8823
8826
  const organs = ea.organs || [];
@@ -8850,6 +8853,13 @@ const $cd8bc494277e92a4$var$ExprHeader = ({ zoneState: zoneState, setZoneState:
8850
8853
  name: next
8851
8854
  }))
8852
8855
  }),
8856
+ /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsx)($cd8bc494277e92a4$var$ExpressedOnlyToggle, {
8857
+ on: !!zoneState?.expressedOnly,
8858
+ onChange: (on)=>setZoneState((s)=>({
8859
+ ...s ?? {},
8860
+ expressedOnly: on
8861
+ }))
8862
+ }),
8853
8863
  /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsx)("span", {
8854
8864
  style: {
8855
8865
  display: 'flex',
@@ -9312,6 +9322,30 @@ class $64fad37f770d2bfe$var$Homology extends (0, ($parcel$interopDefault($gXNCa$
9312
9322
  const keepGeneId = this.gene && this.gene._id;
9313
9323
  return (0, $gXNCa$tbrowsecore.maximalExcludedClades)(snap.tree, (leaf)=>leaf.taxonomyId != null && activeSet.has(String(leaf.taxonomyId)) || leaf.geneId === keepGeneId);
9314
9324
  }
9325
+ // The Expression zone's "expressed only" toggle (zoneStates.expression
9326
+ // .expressedOnly): while it is on and the zone is visible, prune the largest
9327
+ // branches with no leaf carrying expression attributes. The gene of interest
9328
+ // stays, as with the genome prunes, so the root is never pruned.
9329
+ getExpressionPrunedIds(vs, hostProps) {
9330
+ const zs = vs && vs.zoneStates && vs.zoneStates.expression;
9331
+ if (!zs || !zs.expressedOnly) return [];
9332
+ if (!(vs.zones || []).some((z)=>z.id === 'expression' && z.visible)) return [];
9333
+ const ea = hostProps && hostProps.hostData && hostProps.hostData.exprAttrs;
9334
+ if (!ea || !ea.byNode || !hostProps.tree) return [];
9335
+ const keepGeneId = this.gene && this.gene._id;
9336
+ return (0, $gXNCa$tbrowsecore.maximalExcludedClades)(hostProps.tree, (leaf)=>ea.byNode.hasOwnProperty(leaf.id) || leaf.geneId === keepGeneId);
9337
+ }
9338
+ // Turning "expressed only" on also expands every branch, so the expressed
9339
+ // genes left after pruning are all in view. Done here, in the same update
9340
+ // as the toggle, rather than by a second viewer action that would race it.
9341
+ expandOnExpressedOnly(prev, next) {
9342
+ const was = !!(prev && prev.zoneStates && prev.zoneStates.expression && prev.zoneStates.expression.expressedOnly);
9343
+ const is = !!(next && next.zoneStates && next.zoneStates.expression && next.zoneStates.expression.expressedOnly);
9344
+ return !was && is ? {
9345
+ ...next,
9346
+ collapsedNodeIds: []
9347
+ } : next;
9348
+ }
9315
9349
  // Seed the bundle with a pivot-computed initial tbrowse view state once the
9316
9350
  // loader has the tree and the user is actually looking at the tbrowse
9317
9351
  // viewer, from lifecycle (not render) to avoid dispatching mid-render. The
@@ -9454,12 +9488,17 @@ class $64fad37f770d2bfe$var$Homology extends (0, ($parcel$interopDefault($gXNCa$
9454
9488
  },
9455
9489
  children: /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsx)((0, $gXNCa$reactbootstrap.Spinner), {})
9456
9490
  });
9457
- // Layer the genome-limit prune set on top of the user's own prunes for the
9458
- // controlled view state, but persist only the user's prunes (the layer
9459
- // strips the genome-derived ones in onViewStateChange) so the bundle stays
9460
- // free of filter-derived state and re-applies cleanly when the filter
9461
- // changes.
9462
- const pruneLayer = (0, $gXNCa$tbrowsecore.createDerivedPruneLayer)(this.getGenomePrunedIds());
9491
+ // Layer the genome-limit and "expressed only" prune sets on top of the
9492
+ // user's own prunes for the controlled view state, but persist only the
9493
+ // user's prunes (the layer strips the derived ones in onViewStateChange) so
9494
+ // the bundle stays free of derived state and re-applies cleanly when the
9495
+ // filter or toggle changes.
9496
+ const pruneLayer = (0, $gXNCa$tbrowsecore.createDerivedPruneLayer)([
9497
+ ...new Set([
9498
+ ...this.getGenomePrunedIds(),
9499
+ ...this.getExpressionPrunedIds(tbrowseVS, hostProps)
9500
+ ])
9501
+ ]);
9463
9502
  return /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsxs)((0, $gXNCa$reactjsxruntime.Fragment), {
9464
9503
  children: [
9465
9504
  /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsx)("div", {
@@ -9473,7 +9512,7 @@ class $64fad37f770d2bfe$var$Homology extends (0, ($parcel$interopDefault($gXNCa$
9473
9512
  zones: this.getTbrowseZones(),
9474
9513
  nodeOfInterest: this.gene._id,
9475
9514
  viewState: pruneLayer.effective(tbrowseVS),
9476
- onViewStateChange: (next)=>this.setTbrowseViewState(pruneLayer.onChange(next)),
9515
+ onViewStateChange: (next)=>this.setTbrowseViewState(this.expandOnExpressedOnly(tbrowseVS, pruneLayer.onChange(next))),
9477
9516
  densityControls: true,
9478
9517
  defaultOpenSections: {
9479
9518
  zones: true,