@@ -15,7 +15,7 @@ import type {
1515//icons have size 16x16
1616export const shapes = shapesArray
1717
18- const numberOfSamplesCutoff = 20000 // if map is greater than cutoff, switch from svg to canvas rendering
18+ const maxSvgSamplesCutoff = 20000 // if map is greater than cutoff, switch from svg to canvas rendering
1919const noExpColor = '#F5F5F5' //light gray
2020const expColor = '#ff000d' //default color for gene expression
2121
@@ -85,16 +85,13 @@ export class ScatterModel {
8585 if ( 'error' in data ) throw data . error
8686
8787 this . charts = [ ]
88- //This is not preferable.
89- if ( reqOpts . colorTW ?. term . type == SINGLECELL_GENE_EXPRESSION ) {
90- this . processGEData ( data [ 'plots' ] )
91- } else {
92- this . range = data . range
93- for ( const [ key , chartData ] of Object . entries ( data . result ) ) {
94- if ( ! Array . isArray ( chartData . samples ) ) throw 'data.samples[] not array'
95- this . createChart ( key , chartData )
96- }
88+
89+ this . range = data . range
90+ for ( const [ key , chartData ] of Object . entries ( data . result ) ) {
91+ if ( ! Array . isArray ( chartData . samples ) ) throw 'data.samples[] not array'
92+ this . createChart ( key , chartData )
9793 }
94+
9895 this . is3D = this . scatter . config . term0 ?. q . mode == 'continuous'
9996 this . initRanges ( )
10097 } catch ( e : any ) {
@@ -106,57 +103,19 @@ export class ScatterModel {
106103
107104 createChart ( id : string , data : ScatterDataResult ) {
108105 const cohortSamples : any [ ] = data . samples . filter ( sample => 'sampleId' in sample )
109- if ( cohortSamples . length > numberOfSamplesCutoff ) this . is2DLarge = true
106+ if ( cohortSamples . length > maxSvgSamplesCutoff ) this . is2DLarge = true
110107 const colorLegend : Map < string , ColorLegendItem > = new Map ( data . colorLegend )
111108 const shapeLegend : Map < string , ShapeLegendItem > = new Map ( data . shapeLegend )
112109 this . charts . push ( { id, data, cohortSamples, colorLegend, shapeLegend } )
113110 }
114111
115- processGEData ( plots : any ) {
116- const plotsCopy = structuredClone ( plots )
117- let xMin = Infinity ,
118- xMax = - Infinity ,
119- yMin = Infinity ,
120- yMax = - Infinity
121- for ( const plot of plotsCopy ) {
122- plot . data = plot . data || { }
123- plot . id = plot . name
124- let plotMax = - Infinity ,
125- plotMin = Infinity ,
126- plotGEMin = Infinity ,
127- plotGEMax = - Infinity
128- for ( const cell of plot . expCells ) {
129- xMin = Math . min ( xMin , cell . x )
130- xMax = Math . max ( xMax , cell . x )
131- yMin = Math . min ( yMin , cell . y )
132- yMax = Math . max ( yMax , cell . y )
133- plotMin = Math . min ( plotMin , cell . x )
134- plotMax = Math . max ( plotMax , cell . y )
135- plotGEMin = Math . min ( plotGEMin , cell . geneExp )
136- plotGEMax = Math . max ( plotGEMax , cell . geneExp )
137- cell . shape = 'Ref'
138- }
139- plot . min = plotMin
140- plot . max = plotMax
141- plot . geMin = plotGEMin
142- plot . geMax = plotGEMax
143- plot . data . samples = plot . expCells . concat ( plot . noExpCells )
144- plot . cohortSamples = plot . expCells . concat ( plot . noExpCells )
145- plot . colorLegend = new Map ( )
146- plot . shapeLegend = new Map ( )
147- plot . shapeLegend . set ( 'Ref' , { shape : 0 , key : 'Ref' , sampleCount : plot . expCells . length } )
148- this . charts . push ( plot )
149- }
150- this . range = { xMin, xMax, yMin, yMax }
151- }
152-
153112 async initRanges ( ) {
154113 let samples : any [ ] = [ ]
155114 for ( const chart of this . charts ) samples = samples . concat ( chart . data . samples )
156- if ( samples . length > numberOfSamplesCutoff ) this . is2DLarge = true
115+ if ( samples . length > maxSvgSamplesCutoff ) this . is2DLarge = true
157116 if ( samples . length == 0 ) return
158117 const s0 = samples [ 0 ] //First sample to start reduce comparisons
159- const [ xMin , xMax , yMin , yMax , zMin , zMax , scaleMin , scaleMax ] = samples . reduce (
118+ const [ xMin , xMax , yMin , yMax , zMin , zMax , scaleMin , scaleMax , geMin , geMax ] = samples . reduce (
160119 ( s , d ) => [
161120 d . x < s [ 0 ] ? d . x : s [ 0 ] ,
162121 d . x > s [ 1 ] ? d . x : s [ 1 ] ,
@@ -165,9 +124,11 @@ export class ScatterModel {
165124 d . z < s [ 4 ] ? d . z : s [ 4 ] ,
166125 d . z > s [ 5 ] ? d . z : s [ 5 ] ,
167126 'scale' in d ? ( d . scale < s [ 6 ] ? d . scale : s [ 6 ] ) : Number . POSITIVE_INFINITY ,
168- 'scale' in d ? ( d . scale > s [ 7 ] ? d . scale : s [ 7 ] ) : Number . NEGATIVE_INFINITY
127+ 'scale' in d ? ( d . scale > s [ 7 ] ? d . scale : s [ 7 ] ) : Number . NEGATIVE_INFINITY ,
128+ 'geneExp' in d ? ( d . geneExp < s [ 8 ] ? d . geneExp : s [ 8 ] ) : Number . POSITIVE_INFINITY ,
129+ 'geneExp' in d ? ( d . geneExp > s [ 9 ] ? d . geneExp : s [ 9 ] ) : Number . NEGATIVE_INFINITY
169130 ] ,
170- [ s0 . x , s0 . x , s0 . y , s0 . y , s0 . z , s0 . z , s0 . scale , s0 . scale ]
131+ [ s0 . x , s0 . x , s0 . y , s0 . y , s0 . z , s0 . z , s0 . scale , s0 . scale , s0 . geneExp , s0 . geneExp ]
171132 )
172133 const settings = this . scatter . settings
173134 for ( const chart of this . charts ) {
@@ -179,7 +140,9 @@ export class ScatterModel {
179140 zMin,
180141 zMax,
181142 scaleMin,
182- scaleMax
143+ scaleMax,
144+ geMin,
145+ geMax
183146 }
184147 }
185148 }
@@ -258,7 +221,7 @@ export class ScatterModel {
258221 if ( this . scatter . config . colorTW ?. term . type == SINGLECELL_GENE_EXPRESSION ) {
259222 let color
260223 if ( ! c . geneExp ) color = noExpColor
261- else if ( c . geneExp > chart . geMax ) color = expColor
224+ else if ( c . geneExp > chart . ranges . geMax ) color = expColor
262225 else color = chart . colorGenerator ( c . geneExp )
263226 return color
264227 }
@@ -404,15 +367,14 @@ export class ScatterModel {
404367 ? expColor
405368 : config . colorTW ?. term . continuousColorScale ?. maxColor || gradientColor . darker ( ) . toString ( )
406369 }
407-
408370 // Handle continuous color scaling when color term wrapper is in continuous mode
409371 if ( config . colorTW ?. q . mode === 'continuous' ) {
410372 // Extract and sort all sample values for our calculations
411373 // We filter out any values that are explicitly defined in the term values
412374 // This gives us the raw numerical data we need for scaling
413375 let colorValues
414376 if ( config . colorTW . term . type == SINGLECELL_GENE_EXPRESSION ) {
415- colorValues = [ chart . geMin , chart . geMax ]
377+ colorValues = [ chart . ranges . geMin , chart . ranges . geMax ]
416378 } else {
417379 colorValues = chart . cohortSamples
418380 . filter (
@@ -452,7 +414,6 @@ export class ScatterModel {
452414 // order just get the first and last values
453415 break
454416 }
455-
456417 // Create the color generator using d3's linear scale
457418 // This maps our numerical range to a color gradient
458419
0 commit comments