33 type PlotDefinition ,
44} from "@common/db/schema/plot" ;
55
6- import { scaleLinear , scaleLog , scaleOrdinal } from "@visx/scale" ;
6+ import { scaleLinear , scaleLog } from "@visx/scale" ;
77import { extent } from "@visx/vendor/d3-array" ;
88import {
99 GlyphCircle ,
@@ -75,9 +75,12 @@ export interface DataPoint extends Record<string, unknown> {
7575export interface DataTransformationOptions {
7676 xColumn : string ;
7777 yColumn ?: string ;
78- colorColumn ?: string ;
79- symbolColumn ?: string ;
80- lineColumn ?: string ;
78+ colorColumns ?: string [ ] ; // Changed to array to support multiple columns
79+ symbolColumns ?: string [ ] ; // Changed to array to support multiple columns
80+ lineColumns ?: string [ ] ; // Changed to array to support multiple columns
81+ colorSeparator ?: string ; // Separator for combining multiple color values
82+ symbolSeparator ?: string ; // Separator for combining multiple symbol values
83+ lineSeparator ?: string ; // Separator for combining multiple line values
8184 xAxisType ?: "number" | "category" ;
8285}
8386
@@ -88,9 +91,12 @@ export function transformData(
8891 const {
8992 xColumn,
9093 yColumn,
91- colorColumn,
92- symbolColumn,
93- lineColumn,
94+ colorColumns,
95+ symbolColumns,
96+ lineColumns,
97+ colorSeparator = " | " ,
98+ symbolSeparator = " | " ,
99+ lineSeparator = " | " ,
94100 xAxisType = "number" ,
95101 } = options ;
96102
@@ -116,52 +122,74 @@ export function transformData(
116122 if ( xAxisType === "number" && isNaN ( xValue as number ) ) return null ;
117123 if ( yColumn && isNaN ( y as number ) ) return null ;
118124
119- // Handle abbreviation objects for color
120- let colorValue : string | undefined ;
121- let colorObject :
122- | { code : string ; description ?: string ; color ?: string }
123- | undefined ;
124- if ( colorColumn && row [ colorColumn ] ) {
125- if ( typeof row [ colorColumn ] === "object" && row [ colorColumn ] !== null ) {
126- colorObject = row [ colorColumn ] as {
125+ // Helper function to extract value from column (handles abbreviation objects)
126+ const extractColumnValue = ( columnName : string ) : string | undefined => {
127+ const value = row [ columnName ] ;
128+ if ( ! value ) return undefined ;
129+
130+ if ( typeof value === "object" && value !== null ) {
131+ const objectValue = value as {
127132 code : string ;
128133 description ?: string ;
129134 color ?: string ;
130135 } ;
131- if ( colorObject && colorObject . code ) {
132- colorValue = colorObject . code ;
136+ return objectValue . code ? objectValue . code : undefined ;
137+ }
138+ return String ( value ) ;
139+ } ;
140+
141+ // Handle multiple color columns
142+ let colorValue : string | undefined ;
143+ let colorObject :
144+ | { code : string ; description ?: string ; color ?: string }
145+ | undefined ;
146+ if ( colorColumns && colorColumns . length > 0 ) {
147+ const colorValues = colorColumns
148+ . map ( ( col ) => extractColumnValue ( col ) )
149+ . filter ( ( val ) => val !== undefined ) ;
150+
151+ if ( colorValues . length > 0 ) {
152+ colorValue = colorValues . join ( colorSeparator ) ;
153+
154+ // For color objects, use the first column that has color information
155+ for ( const col of colorColumns ) {
156+ const value = row [ col ] ;
157+ if ( typeof value === "object" && value !== null ) {
158+ const objValue = value as {
159+ code : string ;
160+ description ?: string ;
161+ color ?: string ;
162+ } ;
163+ if ( objValue . color ) {
164+ colorObject = objValue ;
165+ break ;
166+ }
167+ }
133168 }
134- } else {
135- colorValue = String ( row [ colorColumn ] ) ;
136169 }
137170 }
138171
139- // Handle abbreviation objects for symbol
172+ // Handle multiple symbol columns
140173 let symbolValue : string | undefined ;
141- if ( symbolColumn && row [ symbolColumn ] ) {
142- if (
143- typeof row [ symbolColumn ] === "object" &&
144- row [ symbolColumn ] !== null
145- ) {
146- const symbolObject = row [ symbolColumn ] as { code : string } ;
147- if ( symbolObject && symbolObject . code ) {
148- symbolValue = symbolObject . code ;
149- }
150- } else {
151- symbolValue = String ( row [ symbolColumn ] ) ;
174+ if ( symbolColumns && symbolColumns . length > 0 ) {
175+ const symbolValues = symbolColumns
176+ . map ( ( col ) => extractColumnValue ( col ) )
177+ . filter ( ( val ) => val !== undefined ) ;
178+
179+ if ( symbolValues . length > 0 ) {
180+ symbolValue = symbolValues . join ( symbolSeparator ) ;
152181 }
153182 }
154183
155- // Handle abbreviation objects for line
184+ // Handle multiple line columns
156185 let lineValue : string | undefined ;
157- if ( lineColumn && row [ lineColumn ] ) {
158- if ( typeof row [ lineColumn ] === "object" && row [ lineColumn ] !== null ) {
159- const lineObject = row [ lineColumn ] as { code : string } ;
160- if ( lineObject && lineObject . code ) {
161- lineValue = lineObject . code ;
162- }
163- } else {
164- lineValue = String ( row [ lineColumn ] ) ;
186+ if ( lineColumns && lineColumns . length > 0 ) {
187+ const lineValues = lineColumns
188+ . map ( ( col ) => extractColumnValue ( col ) )
189+ . filter ( ( val ) => val !== undefined ) ;
190+
191+ if ( lineValues . length > 0 ) {
192+ lineValue = lineValues . join ( lineSeparator ) ;
165193 }
166194 }
167195
@@ -238,11 +266,12 @@ export function useFilteredData<T extends DataPoint>(points: T[]) {
238266
239267export function assignAbbreviationColorsAndSymbols < T extends DataPoint > (
240268 points : T [ ] ,
241- colorColumn ?: string ,
242- symbolColumn ?: string ,
243- lineColumn ?: string ,
269+ colorColumns ?: string [ ] ,
270+ symbolColumns ?: string [ ] ,
271+ lineColumns ?: string [ ] ,
244272) : T [ ] {
245- if ( ! colorColumn && ! symbolColumn && ! lineColumn ) return points ;
273+ if ( ! colorColumns ?. length && ! symbolColumns ?. length && ! lineColumns ?. length )
274+ return points ;
246275
247276 // Create color mappings that prioritize abbreviation colors
248277 const colorMap = new Map < string , string > ( ) ;
@@ -251,12 +280,12 @@ export function assignAbbreviationColorsAndSymbols<T extends DataPoint>(
251280 let defaultColorIndex = 0 ;
252281
253282 // Get unique colors in sorted order for consistent assignment
254- const uniqueColors = colorColumn
283+ const uniqueColors = colorColumns ?. length
255284 ? Array . from ( new Set ( points . map ( ( p ) => p . color ) . filter ( Boolean ) ) ) . sort ( )
256285 : [ ] ;
257286
258287 uniqueColors . forEach ( ( color ) => {
259- if ( colorColumn && color && ! processedColors . has ( color ) ) {
288+ if ( colorColumns ?. length && color && ! processedColors . has ( color ) ) {
260289 processedColors . add ( color ) ;
261290
262291 // Find the point with this color to check for abbreviation color
@@ -277,10 +306,10 @@ export function assignAbbreviationColorsAndSymbols<T extends DataPoint>(
277306 } ) ;
278307
279308 // Get unique values for symbol and line columns (sorted for consistent ordering)
280- const uniqueSymbols = symbolColumn
309+ const uniqueSymbols = symbolColumns ?. length
281310 ? Array . from ( new Set ( points . map ( ( p ) => p . symbol ) . filter ( Boolean ) ) ) . sort ( )
282311 : [ ] ;
283- const uniqueLines = lineColumn
312+ const uniqueLines = lineColumns ?. length
284313 ? Array . from ( new Set ( points . map ( ( p ) => p . line ) . filter ( Boolean ) ) ) . sort ( )
285314 : [ ] ;
286315
@@ -289,7 +318,7 @@ export function assignAbbreviationColorsAndSymbols<T extends DataPoint>(
289318 let defaultSymbolIndex = 0 ;
290319
291320 uniqueSymbols . forEach ( ( symbol ) => {
292- if ( symbolColumn && symbol ) {
321+ if ( symbolColumns ?. length && symbol ) {
293322 symbolMap . set (
294323 symbol ,
295324 AVAILABLE_SYMBOLS [ defaultSymbolIndex % AVAILABLE_SYMBOLS . length ] ,
@@ -303,17 +332,17 @@ export function assignAbbreviationColorsAndSymbols<T extends DataPoint>(
303332 // Assign colors and symbols to points while preserving original values
304333 return points . map ( ( point ) => ( {
305334 ...point ,
306- ...( colorColumn &&
335+ ...( colorColumns ?. length &&
307336 point . color && {
308337 originalColor : point . color ,
309338 color : colorMap . get ( point . color ) || OBSERVABLE_COLORS [ 0 ] ,
310339 } ) ,
311- ...( symbolColumn &&
340+ ...( symbolColumns ?. length &&
312341 point . symbol && {
313342 originalSymbol : point . symbol ,
314343 symbol : symbolMap . get ( point . symbol ) ,
315344 } ) ,
316- ...( lineColumn &&
345+ ...( lineColumns ?. length &&
317346 point . line && {
318347 originalLine : point . line ,
319348 line : lineMap . get ( point . line ) ,
0 commit comments