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,57 @@
1
+ import hilbert from 'hilbert';
2
+
3
+ const selectPointsForDownsampling = (
4
+ points,
5
+ hilbertValues,
6
+ threshold = 1000,
7
+ ) => {
8
+ // Pair each point with its Hilbert value
9
+ const pointsWithHilbert = points.map((point, index) => ({
10
+ point,
11
+ hilbert: hilbertValues[index],
12
+ }));
13
+
14
+ // Sort by Hilbert value
15
+ pointsWithHilbert.sort((a, b) => a.hilbert - b.hilbert);
16
+
17
+ // Calculate the step size to achieve the target number of points
18
+ const step = Math.ceil(points.length / threshold);
19
+
20
+ // Select a subset of points
21
+ const downsampled = [];
22
+ for (let i = 0; i < points.length; i += step) {
23
+ downsampled.push(pointsWithHilbert[i].point);
24
+ }
25
+
26
+ return downsampled;
27
+ };
28
+
29
+ const calculateHilbertValue = (point, order = 16) => {
30
+ // Create a Hilbert curve instance
31
+ const hilbertInstance = new hilbert.Hilbert2d(); // Replace with the actual class name if different
32
+ return hilbertInstance.xy2d(point.x, point.y, order);
33
+ };
34
+
35
+ const downsampleSeries = (series, hilbertSettings) => {
36
+ const { order = 16, threshold } = hilbertSettings;
37
+
38
+ const downsampledSeries = series.map((data) => {
39
+ const hilbertValues = data.data.map((point) =>
40
+ calculateHilbertValue(point, order),
41
+ );
42
+ const downsampledData = selectPointsForDownsampling(
43
+ data.data,
44
+ hilbertValues,
45
+ threshold,
46
+ );
47
+
48
+ return {
49
+ ...data,
50
+ data: downsampledData,
51
+ };
52
+ });
53
+
54
+ return downsampledSeries;
55
+ };
56
+
57
+ export default downsampleSeries;
@@ -0,0 +1,210 @@
1
+ /*
2
+ * @Author : Lihao leolihao@arizona.edu
3
+ * @Date : 2023-12-23 23:27:45
4
+ * @FilePath : /visualifyjs/src/core/parser/echart.parser.js
5
+ * @Description :
6
+ * Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
+ */
8
+ import conditionalFetch from '../fetch/condfetch';
9
+ import { isEmpty } from 'lodash';
10
+
11
+ const enableVisualMap = (series) => {
12
+ if (!series || series.length === 0) return false;
13
+ const seriesData = series[0].data;
14
+ if (!seriesData) return false;
15
+ // Check if the series data has z values (indicating 3D data)
16
+ return seriesData.some((dataPoint) => dataPoint.value.length === 3);
17
+ };
18
+
19
+ const _fetch_data = async (parser = {}, Options = {}, sharedData) => {
20
+ const { sources } = parser;
21
+
22
+ let fetched_data = {}; // response from api
23
+
24
+ const processSource = async (source) => {
25
+ let resp = await conditionalFetch(
26
+ source,
27
+ sharedData,
28
+ Options.title,
29
+ Options.visualify,
30
+ );
31
+ if (resp) fetched_data[source.name] = resp;
32
+ };
33
+
34
+ if (Array.isArray(sources)) {
35
+ await Promise.all(sources.map(processSource));
36
+ } else if (typeof sources === 'object') {
37
+ await processSource(sources);
38
+ }
39
+
40
+ if (isEmpty(fetched_data))
41
+ throw new Error(parser?.startup_msg ?? 'No data fetched from api');
42
+
43
+ return fetched_data;
44
+ };
45
+
46
+ export const _process_fetched_data = (
47
+ fetched_data,
48
+ parser = {},
49
+ Options = {},
50
+ ) => {
51
+ Options.series = __process_fetched_data(
52
+ fetched_data,
53
+ parser,
54
+ Options.visualify,
55
+ );
56
+ Options.legend.data = Options.series.map((item) => item.name);
57
+
58
+ if (!enableVisualMap(Options.series)) {
59
+ //console.log('disable visual map');
60
+ Options.visualMap = [];
61
+ }
62
+ return Options;
63
+ };
64
+
65
+ const __process_fetched_data = (
66
+ fetched_data,
67
+ parser_config,
68
+ visualify = {},
69
+ ) => {
70
+ //console.log('visualify', visualify);
71
+ const {
72
+ seriesBy = visualify?.seriesBy ?? null,
73
+ mapping = visualify?.mapping ?? {},
74
+ exclude = visualify?.exclude ?? [],
75
+ symbol = visualify?.symbol ?? null,
76
+ symbolSize = visualify?.symbolSize ?? null,
77
+ merger = visualify?.merger ?? null,
78
+ filter = visualify?.filter ?? null,
79
+ } = parser_config;
80
+ const { x = 'x', y = 'y', z = 'z', extra = [] } = mapping;
81
+ const aggregatedData = {};
82
+
83
+ for (const [key, data] of Object.entries(fetched_data)) {
84
+ //console.log('processing data from api', key, data);
85
+ if (!data) {
86
+ return Object.values(aggregatedData);
87
+ } else if (data && merger && merger[key]) {
88
+ /*
89
+ console.log(
90
+ `processing data from merger:`,
91
+ key,
92
+ `merger`,
93
+ merger[key],
94
+ `data`,
95
+ data,
96
+ `with`,
97
+ aggregatedData,
98
+ );
99
+ */
100
+ // add extra properties to aggregatedData.data
101
+ Object.values(aggregatedData).forEach((item) => {
102
+ item.data.forEach((value) => {
103
+ if (merger[key].item in value) {
104
+ let tag = value[merger[key].item];
105
+ let val = data[tag];
106
+ if (merger[key].label) value[merger[key].label] = val;
107
+ if (merger[key].visualMap) value.value.push(val);
108
+ }
109
+ });
110
+ });
111
+ } else {
112
+ // if seriesBy is not defined, get the first key of data as the series
113
+ const seriesKey = seriesBy ?? Object.keys(data)[0];
114
+
115
+ if (data[seriesKey] === undefined || data === undefined) continue;
116
+ data[seriesKey].forEach((item, index) => {
117
+ if (exclude && exclude.includes(item)) return;
118
+
119
+ const extraProperties = {};
120
+ for (const property in mapping.extra) {
121
+ if (data[extra[property]]) {
122
+ extraProperties[property] =
123
+ data[extra[property]][index];
124
+ }
125
+ }
126
+
127
+ if (!data[x] || !data[y] || !parser_config.type) return;
128
+
129
+ const point = data[z]
130
+ ? [data[x][index], data[y][index], data[z][index]]
131
+ : [data[x][index], data[y][index]];
132
+
133
+ if (!aggregatedData[item]) {
134
+ aggregatedData[item] = {
135
+ name: item,
136
+ type: parser_config.type,
137
+ data: [],
138
+ };
139
+ if (symbol) aggregatedData[item].symbol = symbol;
140
+ if (symbolSize)
141
+ aggregatedData[item].symbolSize = symbolSize;
142
+ }
143
+
144
+ aggregatedData[item].data.push({
145
+ value: point,
146
+ ...extraProperties,
147
+ });
148
+ });
149
+ }
150
+ }
151
+
152
+ let processed_data = Object.values(aggregatedData);
153
+
154
+ if (filter) {
155
+ for (let filter_key of Object.keys(filter)) {
156
+ const filter_expression = filter[filter_key];
157
+ //console.log('filter', filter_key, filter_expression);
158
+ processed_data = processed_data.map((item) => {
159
+ const filteredData = item.data.filter((dataPoint) => {
160
+ try {
161
+ const value = dataPoint[filter_key];
162
+ if (value === undefined || value === null) return true;
163
+
164
+ const match =
165
+ filter_expression.match(/([><]=?)\s*(-?\d+)/);
166
+ if (!match)
167
+ throw new Error(
168
+ 'Invalid filter expression for filter',
169
+ );
170
+
171
+ // Extract the operator and threshold value
172
+ const operator = match[1];
173
+ const threshold = parseInt(match[2]);
174
+ // Evaluate the filter expression using the function
175
+ return eval_filter(value, operator, threshold);
176
+ } catch (err) {
177
+ console.warn('error in filter', err);
178
+ return false;
179
+ }
180
+ });
181
+ return {
182
+ ...item,
183
+ data: filteredData,
184
+ };
185
+ });
186
+ }
187
+ }
188
+
189
+ return processed_data;
190
+ };
191
+
192
+ // Define a function to evaluate filter expressions
193
+ function eval_filter(value, operator, threshold) {
194
+ switch (operator) {
195
+ case '<':
196
+ return value < threshold;
197
+ case '<=':
198
+ return value <= threshold;
199
+ case '>':
200
+ return value > threshold;
201
+ case '>=':
202
+ return value >= threshold;
203
+ case '=':
204
+ return value === threshold;
205
+ default:
206
+ throw new Error('Invalid operator in filter expression');
207
+ }
208
+ }
209
+
210
+ export default _fetch_data;
@@ -0,0 +1,67 @@
1
+ /*
2
+ * @Author : Lihao leolihao@arizona.edu
3
+ * @Date : 2023-12-02 22:53:11
4
+ * @FilePath : /visualifyjs/src/core/parser/echart.series.js
5
+ * @Description :
6
+ * Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
+ */
8
+ export function _handleSeries(options, seriesObject, index) {
9
+ setArrayEl(seriesObject, options, 'label', index);
10
+ setArrayEl(seriesObject, options, 'labelLine', index);
11
+ setArrayEl(seriesObject, options, 'itemStyle', index);
12
+ setArrayEl(seriesObject, options, 'emphasis', index);
13
+ // Handle Line Chart options
14
+ if (seriesObject.type === 'line') {
15
+ setArrayEl(seriesObject, options, 'smooth', index);
16
+ setArrayEl(seriesObject, options, 'step', index);
17
+ setArrayEl(seriesObject, options, 'areaStyle', index);
18
+ } else if (seriesObject.type === 'pie') {
19
+ setArrayEl(seriesObject, options, 'selectedMode', index);
20
+ setArrayEl(seriesObject, options, 'roseType', index);
21
+ if ('center' in options)
22
+ seriesObject.center = getArray(options.center, index);
23
+ if ('radius' in options)
24
+ seriesObject.radius = getArray(options.radius, index);
25
+ } else if (seriesObject.type === 'radar') {
26
+ if ('radar' in options && Array.isArray(options.radar))
27
+ seriesObject.radarIndex = index;
28
+ } else if (seriesObject.type === 'funnel') {
29
+ seriesObject.top = getArrayEl(options.top, index) ?? 60;
30
+ seriesObject.bottom = getArrayEl(options.bottom, index) ?? 60;
31
+ seriesObject.left = getArrayEl(options.left, index) ?? '10%';
32
+ setArrayEl(seriesObject, options, 'right', index);
33
+ seriesObject.width = getArrayEl(options.width, index) ?? '80%';
34
+ setArrayEl(seriesObject, options, 'height', index);
35
+ seriesObject.min = getArrayEl(options.min, index) ?? 0;
36
+ seriesObject.max = getArrayEl(options.max, index) ?? 100;
37
+ seriesObject.minSize = getArrayEl(options.minSize, index) ?? '0%';
38
+ seriesObject.maxSize = getArrayEl(options.maxSize, index) ?? '100%';
39
+ seriesObject.sort = getArrayEl(options.sort, index) ?? 'descending';
40
+ seriesObject.gap = getArrayEl(options.gap, index) ?? 0;
41
+ seriesObject.funnelAlign =
42
+ getArrayEl(options.funnelAlign, index) ?? 'center';
43
+ setArrayEl(seriesObject, options, 'z', index);
44
+ }
45
+ }
46
+
47
+ function setArrayEl(sereis, options, param, index) {
48
+ let val = getArrayEl(options[param], index);
49
+ if (param in options && val) sereis[param] = val;
50
+ }
51
+
52
+ // Helper function to get the type for each series
53
+ export function getArrayEl(value, index) {
54
+ return Array.isArray(value)
55
+ ? value[Math.min(index, value.length - 1)]
56
+ : value;
57
+ }
58
+
59
+ function getArray(value, index) {
60
+ let _inedx = Math.min(index, value.length - 1);
61
+ if (Array.isArray(value) && Array.isArray(value[_inedx]))
62
+ return value[_inedx];
63
+ else if (Array.isArray(value)) return value;
64
+ else return getArrayEl(value, index);
65
+ }
66
+
67
+ export default _handleSeries;
@@ -0,0 +1,76 @@
1
+ /*
2
+ * @Author : Lihao leolihao@arizona.edu
3
+ * @Date : 2024-01-21 19:18:05
4
+ * @FilePath : /visualifyjs/src/core/parser/echart.types.js
5
+ * @Description :
6
+ * Copyright (c) 2024 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
+ */
8
+ export function handle_alltypes_chart(type, Options) {
9
+ if (type === 'pie') return handle_pie_chart(Options);
10
+ if (type === 'radar') return handle_radar_chart(Options);
11
+ if (type === 'funnel') return handle_funnel_chart(Options);
12
+ return Options;
13
+ }
14
+
15
+ function handle_pie_chart(Options) {
16
+ const newOptions = {
17
+ ...Options,
18
+ legend: {
19
+ ...Options?.legend,
20
+ orient: 'vertical',
21
+ left: 'left',
22
+ },
23
+ emphasis: {
24
+ ...Options?.emphasis,
25
+ itemStyle: {
26
+ shadowBlur: 10,
27
+ shadowOffsetX: 0,
28
+ shadowColor: 'rgba(0, 0, 0, 0.5)',
29
+ },
30
+ },
31
+ xAxis: {
32
+ show: false,
33
+ },
34
+ yAxis: {
35
+ show: false,
36
+ },
37
+ };
38
+ return newOptions;
39
+ }
40
+
41
+ function handle_radar_chart(Options) {
42
+ const newOptions = {
43
+ ...Options,
44
+ radar: {
45
+ ...Options?.radar,
46
+ },
47
+ xAxis: {
48
+ show: false,
49
+ },
50
+ yAxis: {
51
+ show: false,
52
+ },
53
+ legend: {
54
+ top: 0,
55
+ },
56
+ };
57
+ return newOptions;
58
+ }
59
+
60
+
61
+ function handle_funnel_chart(Options) {
62
+ const newOptions = {
63
+ ...Options,
64
+ xAxis: {
65
+ show: false,
66
+ },
67
+ yAxis: {
68
+ show: false,
69
+ },
70
+ legend: {
71
+ top: 0,
72
+ },
73
+ };
74
+ return newOptions;
75
+ }
76
+
@@ -0,0 +1,10 @@
1
+ /*
2
+ * @Author : Lihao leolihao@arizona.edu
3
+ * @Date : 2024-01-14 14:43:20
4
+ * @FilePath : /visualifyjs/src/core/parser/plotly.config.js
5
+ * @Description :
6
+ * Copyright (c) 2024 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
+ */
8
+ const handle_Config = async () => {};
9
+
10
+ export default handle_Config;
@@ -0,0 +1,132 @@
1
+ /*
2
+ * @Author : Lihao leolihao@arizona.edu
3
+ * @Date : 2024-01-14 14:43:45
4
+ * @FilePath : /visualifyjs/src/core/parser/plotly.data.js
5
+ * @Description :
6
+ * Copyright (c) 2024 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
+ */
8
+ import conditionalFetch from '../fetch/condfetch';
9
+ import { isEmpty } from 'lodash';
10
+
11
+ const handle_Data = async (parser = {}, Options = {}, sharedData) => {
12
+ const { sources } = parser;
13
+
14
+ let fetched_data = {}; // response from api
15
+
16
+ const processSource = async (source) => {
17
+ let resp = await conditionalFetch(
18
+ source,
19
+ sharedData,
20
+ Options.title,
21
+ Options.visualify,
22
+ );
23
+ if (resp) fetched_data[source.name] = resp;
24
+ };
25
+
26
+ if (Array.isArray(sources)) {
27
+ await Promise.all(sources.map(processSource));
28
+ } else if (typeof sources === 'object') {
29
+ await processSource(sources);
30
+ }
31
+
32
+ if (isEmpty(fetched_data))
33
+ throw new Error(parser?.startup_msg ?? 'No data fetched from api');
34
+
35
+ return fetched_data;
36
+ };
37
+
38
+ export default handle_Data;
39
+
40
+ export const __process_fetched_data = (
41
+ fetched_data,
42
+ parser_config,
43
+ visualify = {},
44
+ ) => {
45
+ //console.log('visualify', visualify);
46
+ const {
47
+ seriesBy = visualify?.seriesBy ?? null,
48
+ mapping = visualify?.mapping ?? {},
49
+ exclude = visualify?.exclude ?? [],
50
+ symbol = visualify?.symbol ?? null,
51
+ symbolSize = visualify?.symbolSize ?? null,
52
+ merger = visualify?.merger ?? null,
53
+ } = parser_config;
54
+ const { x = 'x', y = 'y', z = 'z', extra = [] } = mapping;
55
+ const aggregatedData = {};
56
+
57
+ for (const [key, data] of Object.entries(fetched_data)) {
58
+ //console.log('processing data from api', key, data);
59
+ if (!data) {
60
+ return Object.values(aggregatedData);
61
+ } else if (data && merger && merger[key]) {
62
+ /*
63
+ console.log(
64
+ `Plotly processing data from merger:`,
65
+ key,
66
+ `merger`,
67
+ merger[key],
68
+ `data`,
69
+ data,
70
+ `with`,
71
+ aggregatedData,
72
+ );*/
73
+ // add extra properties to aggregatedData.data
74
+ Object.values(aggregatedData).forEach((item) => {
75
+ item.data.forEach((value) => {
76
+ if (merger[key].item in value) {
77
+ let tag = value[merger[key].item];
78
+ let val = data[tag];
79
+ if (merger[key].label) value[merger[key].label] = val;
80
+ if (merger[key].visualMap) value.value.push(val);
81
+ }
82
+ });
83
+ });
84
+ } else {
85
+ // if seriesBy is not defined, get the first key of data as the series
86
+ const seriesKey = seriesBy ?? Object.keys(data)[0];
87
+ if (
88
+ data[seriesKey] === undefined ||
89
+ data === undefined ||
90
+ !Array.isArray(data[seriesKey])
91
+ )
92
+ continue;
93
+ data[seriesKey].forEach((item, index) => {
94
+ if (exclude && exclude.includes(item)) return;
95
+
96
+ const extraProperties = {};
97
+ for (const property in mapping.extra) {
98
+ if (data[extra[property]]) {
99
+ extraProperties[property] =
100
+ data[extra[property]][index];
101
+ }
102
+ }
103
+
104
+ if (!data[x] || !data[y] || !parser_config.type) return;
105
+
106
+ const point = data[z]
107
+ ? [data[x][index], data[y][index], data[z][index]]
108
+ : [data[x][index], data[y][index]];
109
+
110
+ if (!aggregatedData[item]) {
111
+ aggregatedData[item] = {
112
+ name: item,
113
+ type: parser_config.type,
114
+ data: [],
115
+ };
116
+ if (symbol) aggregatedData[item].symbol = symbol;
117
+ if (symbolSize)
118
+ aggregatedData[item].symbolSize = symbolSize;
119
+ }
120
+
121
+ aggregatedData[item].data.push({
122
+ value: point,
123
+ ...extraProperties,
124
+ });
125
+ });
126
+ }
127
+ }
128
+
129
+ let processed_data = Object.values(aggregatedData);
130
+
131
+ return processed_data;
132
+ };
@@ -0,0 +1,10 @@
1
+ /*
2
+ * @Author : Lihao leolihao@arizona.edu
3
+ * @Date : 2024-01-14 14:44:10
4
+ * @FilePath : /visualifyjs/src/core/parser/plotly.layout.js
5
+ * @Description :
6
+ * Copyright (c) 2024 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
+ */
8
+ const handle_Layour = async () => {};
9
+
10
+ export default handle_Layour;
@@ -0,0 +1,18 @@
1
+ /*
2
+ * @Author : Lihao leolihao@arizona.edu
3
+ * @Date : 2024-01-14 16:20:14
4
+ * @FilePath : /visualifyjs/src/core/parser/plotly.violin.js
5
+ * @Description :
6
+ * Copyright (c) 2024 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
+ */
8
+
9
+ export const handle_violin_plot = (processed_data) => {
10
+ const plotlyData = processed_data.map((item) => {
11
+ return {
12
+ type: item.type,
13
+ y: item.data.map((d) => d.value[2]),
14
+ name: item.name,
15
+ };
16
+ });
17
+ return plotlyData;
18
+ };
@@ -0,0 +1,62 @@
1
+ /*
2
+ * @Author : Lihao leolihao@arizona.edu
3
+ * @Date : 2023-11-29 16:02:42
4
+ * @FilePath : /visualifyjs/src/core/recharts.js
5
+ * @Description :
6
+ * Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
+ */
8
+ import React from 'react';
9
+ import { createRoot } from 'react-dom/client';
10
+ import EChartSwitcher from './modules/echartswitcher';
11
+ import { VisualifyProvider } from './appContext';
12
+
13
+ class Recharts {
14
+ constructor(config = {}) {
15
+ //console.log('config', config);
16
+ const { el = null } = config;
17
+ // Default to empty object if nothing is passed
18
+ if (typeof el === 'string') {
19
+ this.selector = document.querySelector(el);
20
+ if (!this.selector) {
21
+ throw new Error(`Element not found with selector: ${el}`);
22
+ }
23
+ } else {
24
+ this.selector = el;
25
+ }
26
+ const { parser = null, advanced = null, ...rest } = config;
27
+ this.config = rest;
28
+ this.parser = parser;
29
+ this.advanced = advanced;
30
+ }
31
+
32
+ mount(selector = this.selector) {
33
+ const el =
34
+ typeof selector === 'string'
35
+ ? document.querySelector(selector)
36
+ : selector;
37
+
38
+ if (!el)
39
+ throw new Error(`Element not found with selector: ${selector}`);
40
+
41
+ try {
42
+ // Assuming createRoot is imported from 'react-dom/client'
43
+ const charts = createRoot(el);
44
+ charts.render(
45
+ <VisualifyProvider>
46
+ <EChartSwitcher
47
+ props={{
48
+ config: this.config,
49
+ parser: this.parser,
50
+ advanced: this.advanced,
51
+ }}
52
+ />
53
+ </VisualifyProvider>,
54
+ );
55
+ //console.log('mounted ' + selector, el);
56
+ } catch (e) {
57
+ console.error('Error mounting chart:', e);
58
+ }
59
+ }
60
+ }
61
+
62
+ export default Recharts;
@@ -0,0 +1,49 @@
1
+ /*
2
+ * @Author : Lihao leolihao@arizona.edu
3
+ * @Date : 2023-12-04 12:47:02
4
+ * @FilePath : /visualifyjs/src/core/router/alias.js
5
+ * @Description :
6
+ * Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
+ */
8
+ import { Navigate, useLocation } from 'react-router-dom';
9
+
10
+ const AliasRoute = ({ alias, children }) => {
11
+ const location = useLocation();
12
+
13
+ for (const pattern in alias) {
14
+ const regex = new RegExp(pattern);
15
+ if (regex.test(location.pathname)) {
16
+ const target = alias[pattern];
17
+
18
+ // Check if the target is defined and is a string
19
+ if (typeof target === 'string') {
20
+ // Check if target is a URL or a path
21
+ if (
22
+ target.startsWith('http://') ||
23
+ target.startsWith('https://')
24
+ ) {
25
+ window.location.href = target;
26
+ return null;
27
+ }
28
+
29
+ // Redirect to the matched route
30
+ const newPath = location.pathname.replace(regex, target);
31
+ return (
32
+ <Navigate
33
+ to={newPath}
34
+ replace
35
+ />
36
+ );
37
+ } else {
38
+ console.error(
39
+ `Alias target for pattern '${pattern}' is not defined or not a string.`,
40
+ );
41
+ continue; // Skip to the next pattern
42
+ }
43
+ }
44
+ }
45
+
46
+ return children;
47
+ };
48
+
49
+ export default AliasRoute;