visualifyjs 2.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. package/.github/workflows/static.yml.bak +51 -0
  2. package/LICENSE +674 -0
  3. package/README.md +59 -0
  4. package/config-overrides.js +31 -0
  5. package/dist/visualify.js +188 -0
  6. package/docs/.nojekyll +0 -0
  7. package/docs/docs/CLI.md +34 -0
  8. package/docs/docs/README.md +65 -0
  9. package/docs/docs/Rechart/bar.md +190 -0
  10. package/docs/docs/Rechart/funnel.md +193 -0
  11. package/docs/docs/Rechart/geo.md +0 -0
  12. package/docs/docs/Rechart/line.md +355 -0
  13. package/docs/docs/Rechart/liquidfill.md +0 -0
  14. package/docs/docs/Rechart/pie.md +225 -0
  15. package/docs/docs/Rechart/polar.md +0 -0
  16. package/docs/docs/Rechart/radar.md +253 -0
  17. package/docs/docs/Rechart/sankey.md +0 -0
  18. package/docs/docs/Rechart/scatter.md +0 -0
  19. package/docs/docs/Rechart/sunburst.md +0 -0
  20. package/docs/docs/Rechart/tree.md +0 -0
  21. package/docs/docs/Rechart/wordcloud.md +0 -0
  22. package/docs/docs/_404.md +52 -0
  23. package/docs/docs/_coverpage.md +11 -0
  24. package/docs/docs/_sidebar.md +43 -0
  25. package/docs/docs/components/dotBio.md +34 -0
  26. package/docs/docs/components/echart.md +82 -0
  27. package/docs/docs/components/html.md +34 -0
  28. package/docs/docs/components/macaron.md +145 -0
  29. package/docs/docs/components/markdown.md +0 -0
  30. package/docs/docs/components/more.md +142 -0
  31. package/docs/docs/components/plotly.md +62 -0
  32. package/docs/docs/components/scatterL.md +70 -0
  33. package/docs/docs/components/visium.md +57 -0
  34. package/docs/docs/configuration.md +123 -0
  35. package/docs/docs/deploy.md +31 -0
  36. package/docs/docs/log.md +1 -0
  37. package/docs/docs/more-pages.md +23 -0
  38. package/docs/docs/quickstart.md +119 -0
  39. package/docs/docs/rechart-attributes.md +74 -0
  40. package/docs/docs/rechart-basic-usage.md +162 -0
  41. package/docs/docs/static/_images/deploy-github-pages.png +0 -0
  42. package/docs/docs/static/logo/favicon.ico +0 -0
  43. package/docs/docs/static/logo/logo_128x128.png +0 -0
  44. package/docs/docs/static/logo/logo_192x192.png +0 -0
  45. package/docs/docs/static/logo/logo_256x256.png +0 -0
  46. package/docs/docs/static/logo/logo_512x512.png +0 -0
  47. package/docs/docs/static/logo/logo_64x64.png +0 -0
  48. package/docs/docs/theme.md +5 -0
  49. package/docs/index.html +71 -0
  50. package/docs/manifest.json +24 -0
  51. package/docs/static/css/fluff-stuff.css +170 -0
  52. package/docs/static/css/font-awesome.min.css +4 -0
  53. package/docs/static/css/visualify.css +25 -0
  54. package/docs/static/fonts/fontawesome-webfont.woff2 +0 -0
  55. package/docs/static/images/star.png +0 -0
  56. package/docs/static/js/configuration.js +448 -0
  57. package/docs/static/js/fluff.js +1 -0
  58. package/docs/static/js/visualify.js +188 -0
  59. package/docs/static/logo/favicon.ico +0 -0
  60. package/docs/static/logo/logo_128x128.png +0 -0
  61. package/docs/static/logo/logo_192x192.png +0 -0
  62. package/docs/static/logo/logo_256x256.png +0 -0
  63. package/docs/static/logo/logo_512x512.png +0 -0
  64. package/docs/static/logo/logo_64x64.png +0 -0
  65. package/package.json +84 -0
  66. package/rollup.config.mjs +76 -0
  67. package/src/_css/404.css +116 -0
  68. package/src/_css/App.css +38 -0
  69. package/src/_css/autoSuggestion.css +27 -0
  70. package/src/_css/circular-progress.css +33 -0
  71. package/src/_css/index.css +37 -0
  72. package/src/_css/modern.css +25 -0
  73. package/src/_media/404.png +0 -0
  74. package/src/_media/corner.svg +8 -0
  75. package/src/_media/download.svg +3 -0
  76. package/src/_media/icon.svg +1 -0
  77. package/src/_media/logo.svg +14 -0
  78. package/src/_test/App.test.js +15 -0
  79. package/src/_utils/reportWebVitals.js +13 -0
  80. package/src/core/appContext.js +27 -0
  81. package/src/core/components/Scatter.js +188 -0
  82. package/src/core/components/ScatterBio.js +572 -0
  83. package/src/core/components/VisiumPlot.js +165 -0
  84. package/src/core/components/browser.js +42 -0
  85. package/src/core/components/dotplot.js +413 -0
  86. package/src/core/components/html.js +29 -0
  87. package/src/core/components/list.js +178 -0
  88. package/src/core/components/macaron.js +201 -0
  89. package/src/core/components/markdown.js +56 -0
  90. package/src/core/components/parser.scatterBio.js +579 -0
  91. package/src/core/components/ratio.js +80 -0
  92. package/src/core/components/scatterL.js +173 -0
  93. package/src/core/components/searchbar.js +131 -0
  94. package/src/core/components/selection.js +193 -0
  95. package/src/core/components/timeline.js +281 -0
  96. package/src/core/components/visium.js +97 -0
  97. package/src/core/fetch/condfetch.js +82 -0
  98. package/src/core/fetch/fetch.js +92 -0
  99. package/src/core/fetch/json.js +29 -0
  100. package/src/core/fetch/vfetch.js +42 -0
  101. package/src/core/liveEditor.js +44 -0
  102. package/src/core/modules/codeEditorWithPreview.js +104 -0
  103. package/src/core/modules/echarts/common.js +20 -0
  104. package/src/core/modules/echarts/presetHandler.js +41 -0
  105. package/src/core/modules/echarts/presets/esodev.chromium.js +172 -0
  106. package/src/core/modules/echarts/presets/esodev.codex.js +130 -0
  107. package/src/core/modules/echarts/presets/esodev.visium.js +123 -0
  108. package/src/core/modules/echarts/presets/mmtrbc.js +186 -0
  109. package/src/core/modules/echarts.js +71 -0
  110. package/src/core/modules/echartsUtils.js +43 -0
  111. package/src/core/modules/echartswitcher.js +152 -0
  112. package/src/core/modules/replotly/presetHandler.js +24 -0
  113. package/src/core/modules/replotly/presets/minimum.js +18 -0
  114. package/src/core/modules/replotly/presets/mmtrbc.dot.js +114 -0
  115. package/src/core/modules/replotly/presets/mmtrbc.violin.js +100 -0
  116. package/src/core/modules/replotly.js +71 -0
  117. package/src/core/pages/404.js +50 -0
  118. package/src/core/pages/error.js +27 -0
  119. package/src/core/pages/jsonPage.js +62 -0
  120. package/src/core/pages/loading.js +44 -0
  121. package/src/core/parser/echart.data.js +183 -0
  122. package/src/core/parser/echart.features.js +125 -0
  123. package/src/core/parser/echart.general.js +143 -0
  124. package/src/core/parser/echart.hilbert.js +57 -0
  125. package/src/core/parser/echart.parser.js +210 -0
  126. package/src/core/parser/echart.series.js +67 -0
  127. package/src/core/parser/echart.types.js +76 -0
  128. package/src/core/parser/plotly.config.js +10 -0
  129. package/src/core/parser/plotly.data.js +132 -0
  130. package/src/core/parser/plotly.layout.js +10 -0
  131. package/src/core/parser/plotly.violin.js +18 -0
  132. package/src/core/recharts.js +62 -0
  133. package/src/core/router/alias.js +49 -0
  134. package/src/core/router/jsonRouter.js +31 -0
  135. package/src/core/themes/modern.js +32 -0
  136. package/src/core/themes/themeSelector.js +33 -0
  137. package/src/core/visualify.js +47 -0
  138. package/src/core/widgets/circularProgress.js +24 -0
  139. package/src/core/widgets/controller.js +83 -0
  140. package/src/core/widgets/errorBoundary.js +36 -0
  141. package/src/core/widgets/footer.js +177 -0
  142. package/src/core/widgets/header.js +234 -0
  143. package/src/core/widgets/layout/Grid.js +31 -0
  144. package/src/core/widgets/layout.js +36 -0
  145. package/src/core/widgets/mapping.js +42 -0
  146. package/src/index.js +62 -0
  147. package/src/setupTests.js +5 -0
@@ -0,0 +1,572 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import Scatter from './Scatter';
3
+ import CircularProgress from '../widgets/circularProgress';
4
+ import { useAppContext } from '../appContext';
5
+ import simplefetch from '../fetch/fetch';
6
+
7
+ function rcolor(seed = 0) {
8
+ const maxHexValue = 16777215;
9
+ const randomSeed = seed || Math.random();
10
+ const randomColor = Math.floor(randomSeed * maxHexValue).toString(16);
11
+ const color = '#' + randomColor.padStart(6, '0');
12
+
13
+ return color;
14
+ }
15
+
16
+ function isEmpty(obj) {
17
+ return Object.keys(obj).length === 0 && obj.constructor === Object;
18
+ }
19
+
20
+ function ScatterBio({ props, style, reset }) {
21
+ // Declare states at the beginning
22
+ const { sharedData } = useAppContext();
23
+ const { debug } = props;
24
+
25
+ const [updatedProps, setUpdatedProps] = useState(props);
26
+ const [loading, setLoading] = useState(true);
27
+ const [error, setError] = useState(null);
28
+
29
+ useEffect(() => {
30
+ // ------------------------------ Fetch Data ------------------------------
31
+ const {
32
+ meta,
33
+ simpleload = true,
34
+ gene,
35
+ geneval,
36
+ metaval,
37
+ colour = 'Cell_Type', // 'Cell_Type' or 'Stage'
38
+ colourval = undefined,
39
+ axis_mapping,
40
+ config = {},
41
+ exclude_celltype = [],
42
+ entry_mapping = undefined,
43
+ exp_condition = 0,
44
+ startup_msg = '',
45
+ } = props;
46
+
47
+ // error handling for missing config --------------------------------------
48
+
49
+ // if meta is missing
50
+ if (!meta) {
51
+ setError({ message: 'meta is missing', data: { meta: meta } });
52
+ setLoading(false);
53
+ return;
54
+ } else if (!gene) {
55
+ setError({ message: 'gene is missing', data: { gene: gene } });
56
+ setLoading(false);
57
+ return;
58
+ }
59
+ // missing axis_mapping
60
+ // that are required for this widget to work
61
+ // represented as x, y while processing the data
62
+ else if (!axis_mapping || !axis_mapping.x || !axis_mapping.y) {
63
+ setError({
64
+ message: 'axis_mapping is missing/incorrect',
65
+ data: { axis_mapping: axis_mapping },
66
+ });
67
+ setLoading(false);
68
+ return;
69
+ }
70
+ // if not simpleload, then metaval is required
71
+ else if (!simpleload && !metaval) {
72
+ setError({
73
+ message: 'metaval is missing',
74
+ data: { metaval: metaval },
75
+ });
76
+ setLoading(false);
77
+ return;
78
+ }
79
+
80
+ /*
81
+ // missing config
82
+ else if (!config) {
83
+ setError({message: "config is missing", data: {config: config}});
84
+ setLoading(false);
85
+ return;
86
+ }
87
+
88
+ // config.xAxis & config.yAxis are required for this widget to work
89
+ else if (!config.xAxis || !config.yAxis) {
90
+ setError({message: "config.xAxis or config.yAxis is missing", data: {config: config}});
91
+ setLoading(false);
92
+ return;
93
+ }
94
+ */
95
+
96
+ // ------------------------------------------------------------------------
97
+
98
+ const _query_gene = geneval ? sharedData[geneval] : sharedData.gene;
99
+ const _query_meta = metaval ? sharedData[metaval] : sharedData.meta;
100
+
101
+ const updatePlot = async () => {
102
+ try {
103
+ setLoading(true);
104
+
105
+ let metadata = {};
106
+ let genedata = {};
107
+
108
+ // if not simpleload, then we wait user to provide the data
109
+ if (!simpleload && (!_query_meta || _query_meta.length === 0)) {
110
+ setLoading({
111
+ message: `Please select ${startup_msg} to load data`,
112
+ });
113
+ return;
114
+ } else if (simpleload) {
115
+ metadata = await simplefetch(meta, {
116
+ id: _query_meta,
117
+ type: 'metadata',
118
+ debug: debug,
119
+ });
120
+
121
+ genedata = await simplefetch(gene, {
122
+ id: _query_gene,
123
+ key: 'gene', //TODO: obtain key from config which can override the type
124
+ type: 'gene',
125
+ debug: debug,
126
+ });
127
+ } else {
128
+ //console.log("ScatterBio: _query_meta", _query_meta);
129
+ //console.log("ScatterBio: nodes_mapping", nodes_mapping);
130
+
131
+ // Mapping logic to filter and transform IDs
132
+ const mapped_nodes = entry_mapping
133
+ ? _query_meta.map((node) => entry_mapping[node])
134
+ : _query_meta;
135
+
136
+ //removed duplicated IDs
137
+ const _filted_query_meta = [...new Set(mapped_nodes)];
138
+
139
+ //console.log("ScatterBio: _filted_query_meta", _filted_query_meta);
140
+
141
+ const metadataPromises = _filted_query_meta.map(
142
+ async (metaId) => {
143
+ return await simplefetch(meta, {
144
+ id: metaId,
145
+ type: 'metadata',
146
+ debug: debug,
147
+ });
148
+ },
149
+ );
150
+
151
+ const metadataResponses = await Promise.all(
152
+ metadataPromises,
153
+ );
154
+
155
+ // Combine the metadata from different IDs
156
+ metadata = metadataResponses.reduce(
157
+ (combined, metadata) => {
158
+ return {
159
+ ...combined,
160
+ ...metadata,
161
+ };
162
+ },
163
+ {},
164
+ );
165
+
166
+ if (
167
+ _query_gene &&
168
+ _query_gene.length > 0 &&
169
+ !_query_gene.includes('None')
170
+ ) {
171
+ if (debug)
172
+ console.log('ScatterBio: _query_gene', _query_gene);
173
+
174
+ const genedataPromises = _query_meta.map(
175
+ async (metaId) => {
176
+ const _mapped_metaId = entry_mapping
177
+ ? entry_mapping[metaId]
178
+ : metaId;
179
+ const _merged_query_gene =
180
+ _mapped_metaId + '/' + _query_gene;
181
+ //console.log(_merged_query_gene);
182
+ return await simplefetch(gene, {
183
+ id: _merged_query_gene,
184
+ key: 'gene', //TODO: obtain key from config which can override the type
185
+ type: 'gene',
186
+ debug: debug,
187
+ });
188
+ },
189
+ );
190
+
191
+ genedata = await Promise.any(genedataPromises);
192
+ //console.log("ScatterBio: genedata", genedata);
193
+ }
194
+ }
195
+
196
+ const _nogene = isEmpty(genedata);
197
+ if (debug) console.log('ScatterBio: _nogene', _nogene);
198
+ if (debug)
199
+ console.log(
200
+ 'ScatterBio: genedata',
201
+ genedata,
202
+ 'metadata',
203
+ metadata,
204
+ );
205
+
206
+ // ------------------------------ Proccess Data ------------------------------
207
+ const { colors: __colors = [] } = config;
208
+
209
+ const filted_colour = sharedData[colourval]
210
+ ? sharedData[colourval].replace(' ', '_')
211
+ : colour;
212
+
213
+ if (debug)
214
+ console.log('ScatterBio - Colour by:', filted_colour);
215
+
216
+ const __celltypes = [
217
+ ...new Set(metadata[filted_colour]),
218
+ ].filter((celltype) => !exclude_celltype.includes(celltype));
219
+
220
+ let { zcolor: visualcolor = [] } = config;
221
+ let seriescolor = {};
222
+
223
+ if (Array.isArray(__colors) && __colors.length > 0) {
224
+ __colors.forEach((item) => {
225
+ if (item.color) visualcolor.push(item.color);
226
+ else visualcolor.push(rcolor());
227
+ });
228
+ __celltypes.forEach((celltype, index) => {
229
+ const cell = __colors.find(
230
+ (item) => item.name === celltype,
231
+ );
232
+ const _color = cell?.color ?? visualcolor[index];
233
+ const _symbol =
234
+ __colors.find((item) => item.name === celltype)
235
+ ?.symbol ?? 'circle';
236
+ seriescolor[celltype] = {
237
+ color: _color,
238
+ symbol: _symbol,
239
+ };
240
+ });
241
+ } else {
242
+ let no_zcolor = false;
243
+ if (visualcolor.length === 0) {
244
+ no_zcolor = true;
245
+ }
246
+ __celltypes.forEach((celltype, index) => {
247
+ if (no_zcolor) {
248
+ visualcolor.push(rcolor());
249
+ }
250
+ seriescolor[celltype] = {
251
+ color: rcolor(),
252
+ symbol: 'circle',
253
+ };
254
+ });
255
+ }
256
+
257
+ // console.log("ScatterBio: axis_mapping", axis_mapping);
258
+ // console.log("metadata: ", metadata);
259
+ const { extra } = axis_mapping;
260
+
261
+ let processedData;
262
+
263
+ try {
264
+ processedData = metadata['Cell_ID'].map((cellId, index) => {
265
+ const _expression =
266
+ genedata[cellId] >= exp_condition
267
+ ? genedata[cellId]
268
+ : _nogene
269
+ ? 999
270
+ : -1;
271
+ const _Cell_Type = metadata[filted_colour] ?? 'Unknown';
272
+ if (
273
+ !__celltypes.includes('Unknown') &&
274
+ __celltypes.length === 0
275
+ ) {
276
+ __celltypes.push('Unknown');
277
+ seriescolor['Unknown'] = {
278
+ color: '#000000',
279
+ symbol: 'circle',
280
+ };
281
+ }
282
+ // const _UMI = metadata.N_UMI ? Math.round(metadata.N_UMI[index] * 100) / 100 : 0;
283
+ // round to 2 decimal places
284
+ const extraProperties = {};
285
+ for (const property in extra) {
286
+ if (metadata[extra[property]]) {
287
+ extraProperties[property] =
288
+ metadata[extra[property]][index];
289
+ }
290
+ }
291
+
292
+ const z_index =
293
+ _expression === -1 || _expression === 999
294
+ ? config.visium_cell_fraction
295
+ ? extraProperties[
296
+ config.visium_cell_fraction
297
+ ] ?? _expression
298
+ : _expression
299
+ : _expression;
300
+
301
+ return {
302
+ name: cellId,
303
+ value: [
304
+ metadata[axis_mapping.x][index],
305
+ metadata[axis_mapping.y][index],
306
+ z_index,
307
+ ],
308
+ Type:
309
+ _Cell_Type === 'Unknown'
310
+ ? 'Unknown'
311
+ : _Cell_Type[index],
312
+ Expression: _expression,
313
+ ...extraProperties,
314
+ };
315
+ });
316
+
317
+ //console.log("ScatterBio: processedData", processedData[0], processedData[1]);
318
+ } catch (err) {
319
+ // if TypeError, then set error message to remind user to check the api
320
+ setError({
321
+ message:
322
+ 'Please check the API, \n' +
323
+ 'Your API may not return the correct data format. \n' +
324
+ meta +
325
+ '\n' +
326
+ err,
327
+ });
328
+ setLoading(false);
329
+ return;
330
+ }
331
+
332
+ if (debug) console.log(processedData[2], processedData[3]);
333
+
334
+ const {
335
+ dotsize,
336
+ dotFactor = 2000,
337
+ minSymbolSize = 2,
338
+ maxSymbolSize = 10,
339
+ } = config;
340
+ const pointCount = processedData.length;
341
+
342
+ // Calculate the symbol size based on the number of points
343
+ let symbolSize;
344
+ if (dotsize === 'auto') {
345
+ const sizeFactor = Math.max(
346
+ 1 - (pointCount - 1000) / dotFactor,
347
+ 0.2,
348
+ );
349
+ symbolSize =
350
+ (maxSymbolSize - minSymbolSize) * sizeFactor +
351
+ minSymbolSize;
352
+ //console.log(pointCount, symbolSize);
353
+ } else {
354
+ symbolSize = typeof dotsize === 'number' ? dotsize : 5;
355
+ }
356
+
357
+ // Create a series for each unique cell type
358
+ const series = __celltypes.map((cellType) => {
359
+ return {
360
+ name: cellType,
361
+ type: 'scatter',
362
+ data: processedData.filter(
363
+ (data) =>
364
+ data.Type === cellType && data.Expression > -1,
365
+ ),
366
+ itemStyle: {
367
+ color: seriescolor[cellType].color,
368
+ },
369
+ symbol: seriescolor[cellType].symbol,
370
+ symbolSize: symbolSize,
371
+ };
372
+ });
373
+
374
+ //console.log("series: ", series);
375
+
376
+ const zshift =
377
+ -config.zshift || -Math.max(config.chartWidth * 0.02, 10);
378
+
379
+ const auto_zmax = Math.max(
380
+ ...processedData.map((item) => item.value[2]),
381
+ );
382
+ const auto_zmin = Math.min(
383
+ ...processedData.map((item) => item.value[2]),
384
+ );
385
+
386
+ //console.log("ScatterBio: auto_zmax", auto_zmax, "auto_zmin", auto_zmin, config.visium_cell_fraction);
387
+
388
+ let visualMap =
389
+ _nogene && !config.visium_cell_fraction
390
+ ? []
391
+ : {
392
+ min: config.zmin ?? auto_zmin,
393
+ max: config.zmax ?? auto_zmax,
394
+ dimension: 2,
395
+ orient: 'vertical',
396
+ top: 'center',
397
+ right: zshift,
398
+ text: config.labels
399
+ ? config.labels.z ?? ''
400
+ : '',
401
+ textGap: 10,
402
+ calculable: true,
403
+ inRange: {
404
+ color: visualcolor,
405
+ },
406
+ textStyle: {
407
+ writingMode: 'vertical-lr',
408
+ },
409
+ ...config.visualMap,
410
+ };
411
+
412
+ const { legend: _config_legend = {} } = config;
413
+ const legendItemCount = __celltypes.length;
414
+ const { type: _legendType, ...__config_legend } =
415
+ _config_legend;
416
+ let legendType = 'scroll';
417
+ if (_legendType === 'auto') {
418
+ legendType = legendItemCount > 10 ? 'scroll' : 'plain';
419
+ }
420
+
421
+ // console.log("__celltypes:", __celltypes);
422
+ // Sort __celltypes by extracting and comparing the numerical part
423
+ const sortedCellTypes = __celltypes.slice().sort((a, b) => {
424
+ // Handle null, undefined, or other unexpected values
425
+ if (a === null || b === null) {
426
+ return 0; // Handle the case as per your requirement
427
+ }
428
+ const numA = parseInt(a.substring(1), 10);
429
+ const numB = parseInt(b.substring(1), 10);
430
+ return numA - numB;
431
+ });
432
+
433
+ // legend
434
+ const _legend =
435
+ _config_legend === false
436
+ ? false
437
+ : {
438
+ data: sortedCellTypes, //__celltypes,
439
+ orient: 'horizontal',
440
+ top: 5, // "top" | "bottom" | "center"
441
+ right: 'center', // "top" | "bottom" | "center",
442
+ ...__config_legend,
443
+ type: legendType,
444
+ };
445
+ //console.log("ScatterBio: legend", _legend);
446
+
447
+ const gridSettings = [
448
+ {
449
+ top: '5%',
450
+ bottom: '5%',
451
+ left: '5%',
452
+ right: '5%',
453
+ ...(config.grid || {}), // Merge with config.grid if available, otherwise an empty object
454
+ },
455
+ ];
456
+
457
+ const title = config.title ?? '';
458
+ // Update props for Scatter
459
+
460
+ let scatterBioProps = {
461
+ ...props,
462
+ config: {
463
+ chartWidth: 800,
464
+ chartHeight: 600,
465
+ ...config,
466
+ series: series,
467
+ legend: _legend,
468
+ visualMap: visualMap,
469
+ title: _nogene
470
+ ? title
471
+ : {
472
+ ...title,
473
+ text: _query_gene,
474
+ },
475
+ // Use formatter from config if provided, otherwise use the default formatter
476
+ formatter: config.formatter
477
+ ? (params) => config.formatter(params)
478
+ : (params) => {
479
+ return `
480
+ ${params.name}
481
+ <br/> Type: ${params.data.Type}
482
+ <br/> UMI: ${params.data.UMI ?? 0}
483
+ `;
484
+ },
485
+ grid: gridSettings,
486
+ },
487
+ };
488
+
489
+ /*
490
+ const imageDom = new Image();
491
+ imageDom.src = './resources/YY0-44_image.png';
492
+ scatterBioProps.config.backgroundColor = {
493
+ image: imageDom,
494
+ repeat: 'no-repeat' // or 'repeat', 'repeat-x', 'repeat-y' depending on your needs
495
+ };
496
+ */
497
+
498
+ //console.log("ScatterBio: scatterBioProps.config", scatterBioProps.config);
499
+ setUpdatedProps(scatterBioProps);
500
+
501
+ setLoading(false);
502
+ } catch (err) {
503
+ console.log(err);
504
+ if (err.name === 'TypeError' && simpleload)
505
+ setError({
506
+ message: `invalid URL for metadata/gene,\nplease check your URL or set simpleload to false`,
507
+ });
508
+ else setError(err);
509
+ setLoading(false);
510
+ }
511
+ };
512
+ updatePlot();
513
+ }, [props, sharedData, debug]);
514
+
515
+ if (reset) {
516
+ reset(props.id, (vals) => {
517
+ // logic to reset the data
518
+ const { gene: rec_gene = ' ' } = vals;
519
+ console.log('received data', sharedData[rec_gene]);
520
+ });
521
+ }
522
+
523
+ if (loading.message) {
524
+ return (
525
+ <div style={{ marginTop: '10px', ...style }}>{loading.message}</div>
526
+ );
527
+ } else if (loading) {
528
+ // Render a loading animation
529
+ return (
530
+ <div
531
+ style={{
532
+ display: 'flex',
533
+ flexDirection: 'column',
534
+ alignItems: 'center',
535
+ justifyContent: 'center',
536
+ height: '100%',
537
+ ...style,
538
+ }}>
539
+ <CircularProgress color='primary' />
540
+ </div>
541
+ );
542
+ }
543
+
544
+ if (error) {
545
+ const errorLines = error.message.split('\n');
546
+ const errorElements = errorLines.map((line, index) => (
547
+ <p
548
+ key={index}
549
+ style={{ color: 'red' }}>
550
+ {line}
551
+ </p>
552
+ ));
553
+ return (
554
+ <div style={style}>
555
+ An error has occurred: <br />
556
+ <br /> {errorElements}
557
+ </div>
558
+ );
559
+ }
560
+ // Only render Scatter when not loading
561
+ return (
562
+ <>
563
+ <Scatter
564
+ key={updatedProps.id + '.inherent'}
565
+ props={updatedProps}
566
+ style={style}
567
+ />
568
+ </>
569
+ );
570
+ }
571
+
572
+ export default ScatterBio;