Parte del codice seguente richiede probabilmente almeno JMP 15 per il supporto dell'importazione XML. Utilizza anche una profonda conoscenza dell'albero della casella di visualizzazione che avrà bisogno di aggiustamenti in futuro.
@datanauta chiesto Calcola aree all'interno di contorni . Ho seguito tre percorsi cercando di capirlo. Innanzitutto, il codice di installazione:
dt = Open( "$sample_data/big class.jmp", invisible );
magenta = RGB Color( 1, 0, 1 );// pure magenta
cp = dt << Contour Plot(
X( :weight, :height ),
Y( :age ),
Show Boundary( 0 ),
Show Data Points( 0 ),
Fill Areas( 1 ),
Label Contours( 0 ),
Transform( "Range Normalized" ),
Color Theme( "White to Black" ),
Show Boundary( 0 ),
Specify Contours( Min( 12.5 ), Max( 16.5 ), N( 9 ) ),
SendToReport( Dispatch( {}, "Contour Plot Graph", FrameBox, {Frame Size( 623, 512 ), Background Color( magenta )} ) )
);
ymin = (Report( cp )[axisbox( 1 )] << getscript)["Min"];
ymax = (Report( cp )[axisbox( 1 )] << getscript)["Max"];
xmin = (Report( cp )[axisbox( 2 )] << getscript)["Min"];
xmax = (Report( cp )[axisbox( 2 )] << getscript)["Max"];
Show( xmin, xmax, ymin, ymax );
cp << minimizewindow( 1 );
Gray contours on magenta background.Contorni grigi su sfondo magenta.
Il primo percorso è stato molto breve. Ho scoperto che la trama del contorno ha un messaggio per <
Il percorso due contava i pixel, probabilmente simile a @gzmorgan0 approccio. Funziona, ma presenta alcuni difetti che puoi vedere prefigurati nell'immagine sopra. Ho creato apposta per lo sfondo quella brutta sfumatura magenta in modo da poter facilmente cercare i pixel grigi. Ma se guardi da vicino, puoi vedere un po' di magenta che filtra tra le regioni. Peccato! Anti-aliasing al lavoro! Normalmente, su uno sfondo bianco, quasi non te ne accorgeresti, ma la transizione in scala di grigi tra i colori è ancora presente.
Zoomed in, the darker regions are still anti-aliased against white.Ingrandite, le regioni più scure sono ancora anti-aliasing rispetto al bianco.
Ad ogni modo, il codice seguente tenta di posizionare i pixel sfumati di magenta in un'area grigia vicina. Forse fa un lavoro equilibrato nel commettere errori su entrambi i lati. Senza il magenta, sarebbero tutte sfumature di grigio e il codice non sarebbe in grado di vedere se fosse necessaria una decisione. (Questo sembra funzionare su JMP 14 e 15.)
pixels = (Report( cp )[framebox( 1 )] << getimage) << getpixels;
// trim non magenta edges. not sure why there are extra pixels...
For( ileft = 1, ileft < N Cols( pixels ), iLeft += 1,
If( pixels[N Rows( pixels ) / 2, ileft] == magenta,
Break()
)
);
For( iright = N Cols( pixels ), iright > ileft, iright -= 1,
If( pixels[N Rows( pixels ) / 2, iright] == magenta,
Break()
)
);
For( itop = 1, itop < N Rows( pixels ), itop += 1,
If( pixels[itop, N Cols( pixels ) / 2] == magenta,
Break()
)
);
For( ibottom = N Rows( pixels ), ibottom > itop, ibottom -= 1,
If( pixels[ibottom, N Cols( pixels ) / 2] == magenta,
Break()
)
);
If( ileft > 10 | itop > 10 | iright < N Cols( pixels ) - 10 | ibottom < N Rows( pixels ) - 10,
Throw( "trimming error" )
);
pixels = pixels[itop :: ibottom, ileft :: iright];
colorCounts = [=> 0];
spiral = [-1 -1, -1 0, -1 1, 0 1, 1 1, 1 0, 1 -1, 0 -1, -2 -2, -2 -1, -2 0, -2 1, -2 2, -1 2, 0 2, 1 2, 2 2, 2 1, 2 0, 2 -1, 2 -2, 1 -2, 0 -2, -1 -2];
grays = [=> ];
For( i = 0, i <= 255, i += 1,
grays[RGB Color( i / 255, i / 255, i / 255 )] = i
);
temp = pixels;
For( i = 1, i <= N Items( pixels ), i += 1,
// pixels that are not magenta and not gray, but are antialiased values...
// force them to the gray of a near pixel
If( pixels[i] != magenta,
{r, g, b} = Color To RGB( pixels[i] );
If( (r != g & r == b),
rowidx = Floor( (i - 1) / N Cols( pixels ) ) + 1; // nc is the number of columns in the 2D pixmat
colidx = Mod( (i - 1), N Cols( pixels ) ) + 1; // rowlocs and collocs are 2D indexes (1-based)
For( j = 1, j <= N Rows( spiral ), j += 1,
// if this has an array out of bounds, make sure there is magenta pad all around
color = pixels[rowidx + spiral[j, 1], colidx + spiral[j, 2]];
If( grays << Contains( color ),
temp[i] = color;
Break();
);
);
);
);
colorCounts[temp[i]] += 1;
);
pixels = temp;
totalpixels = Sum( colorCounts << getvalues );
If( totalpixels != N Rows( pixels ) * N Cols( pixels ),
Throw( "error counting pixels" )
);
areaPerPixel = 1;//((ymax - ymin) * (xmax - xmin)) / totalpixels;
New Window( "Check polygons are inside the magenta area", New Image( pixels ) );
pixelcount = 0;
For( ii = 0, ii <= 255, ii += 1,
i = ii / 255;
If( colorcounts[RGB Color( i, i, i )] > 0,
thisarea = colorcounts[RGB Color( i, i, i )] * areaPerPixel;
Write( "\!ngray=", If( i == 0, "black", i == 1, "white", Char( i, 7, 3 ) ), " \!tarea=", Char( thisarea, 5 ) );
pixelcount += colorcounts[RGB Color( i, i, i )];
pixels[Loc( pixels == RGB Color( i, i, i ) )] = RGB Color( 0, 1, 0 );
);
);
thisarea = colorcounts[magenta] * areaPerPixel;
Write( "\!nmagenta \!tarea=", Char( thisarea, 7, 3 ) );
pixelcount += colorcounts[magenta];
pixels[Loc( pixels == magenta )] = RGB Color( 0, 1, 0 );
New Window( "Check polygons are inside the magenta area", New Image( pixels ) );
Write( "\!nidentified \!tarea=", Char( pixelcount * areaPerPixel, 7, 3 ) );
Write( "\!nall graph \!tarea=", Char( totalpixels * areaPerPixel, 7, 3 ) );
Write( "\!noverlooked \!tarea=", Char( (totalpixels - pixelcount) * areaPerPixel, 7, 3 ) );Ecco l'immagine ripulita
The interior magenta pixels are converted to a nearby gray.I pixel magenta interni vengono convertiti in un grigio vicino.
C'è ancora un po' di irregolarità, ma potrebbe essere bilanciata altrove:
Those pixels will be counted wrong.Quei pixel verranno conteggiati in modo errato.
Il risultato è una tabella nella finestra del registro.
grigio=zona nera=2598
grigio=0.098 area=2973
grigio=0.200 area=3781
grigio=0.302 area=5003
grigio=0.400 area=8528
grigio=0.502 area=12535
grigio=0.600 area=11081
grigio=0.702 area=8382
grigio=0.800 area=12718
grigio=0.902 area=13074
area magenta=238302
area identificata=318975
tutta l'area del grafico=318976
area trascurata=1.000
Il pixel trascurato è un pixel magenta quasi puro nell'angolo in alto a destra. Non ho cercato di rintracciarlo ulteriormente.
Il percorso tre è probabilmente il migliore se riesci a farlo funzionare; dipende da JMP che scrive un file SVG allo stesso modo e potrebbe dipendere anche da questo particolare esempio. Le risposte sono molto simili al secondo tentativo e dovrebbero essere più corrette. (Dipende dalle caratteristiche di JMP 15.) Chiave per comprendere il percorso SVG: la colonna 3 della matrice è negativa per la fine di un segmento; gli array inizio/fine individuano i segmenti nella matrice dei percorsi.
(Report( cp )[framebox( 1 )]) << savepicture( "$temp/deletemeGraph.svg" );
(Report( cp )[framebox( 2 )]) << savepicture( "$temp/deletemeLegend.svg" );
Rename File( "$temp/deletemeGraph.svg", "deletemeGraph.xml" );
Rename File( "$temp/deletemeLegend.svg", "deletemeLegend.xml" );
dtSVGGraph = Open(
"C:\Users\v1\AppData\Local\Temp\deletemeGraph.xml",
XML Settings( Stack( 1 ), Row( "/svg/g/g/g/g/g/path/@d" ), Row( "/svg/g/g/g/g/path/@d" ),
Col( "/svg/g/g/g/g/g/@fill", Column Name( "color" ), Fill( "Use Once" ), Type( "Character" ), Format( {"Best", 15} ), Modeling Type( "Continuous" ) ),
Col( "/svg/g/g/g/g/g/path/@d", Column Name( "path" ), Fill( "Use Once" ), Type( "Character" ), Format( {"Best", 15} ), Modeling Type( "Continuous" ) ),
Col( "/svg/@width", Column Name( "width" ), Fill( "Use Once" ), Type( "Table Variable" ), Format( {"Best", 15} ), Modeling Type( "Continuous" ) ),
Col( "/svg/@height", Column Name( "height" ), Fill( "Use Once" ), Type( "Table Variable" ), Format( {"Best", 15} ), Modeling Type( "Continuous" ) ),
Col( "/svg/g/@fill", Column Name( "colorAlternate" ), Fill( "-", "/svg/g" ), Type( "Character" ), Format( {"Best"} ), Modeling Type( "Continuous" ) ),
Col( "/svg/g/g/g/g/path/@d", Column Name( "path" ), Fill( "Use Once" ), Type( "Character" ), Format( {"Best"} ), Modeling Type( "Continuous" ) ) ),
XML Wizard( 0 )
);
For( i = 1, i <= N Rows( dtSVGGraph ), i += 1,
If( dtSVGGraph:color[i] == "",
dtSVGGraph:color[i] = dtSVGGraph:colorAlternate[i]
)
);
dtSVGGraph << deletecolumns( {colorAlternate} );
dtSVGLegend = Open(
"C:\Users\v1\AppData\Local\Temp\deletemeLegend.xml",
XML Settings(
Stack( 1 ),
Row( "/svg/g/g/g/g/g/text" ),
Row( "/svg/g/g/g/g/text" ),
Col( "/svg/g/g/g/g/g/@fill", Column Name( "color" ), Fill( "Use Once" ), Type( "Character" ), Format( {"Best", 15} ), Modeling Type( "Continuous" ) ),
Col( "/svg/g/g/g/g/g/text", Column Name( "text" ), Fill( "Use Once" ), Type( "Character" ), Format( {"Best", 15} ), Modeling Type( "Continuous" ) ),
Col( "/svg/g/g/g/g/text", Column Name( "textAlternate" ), Fill( "Use Once" ), Type( "Character" ), Format( {"Best", 15} ), Modeling Type( "Continuous" ) ),
Col( "/svg/g/g/g/g/g/rect/@y", Column Name( "y" ), Fill( "Use Once" ), Type( "Numeric" ), Format( {"Best", 15} ), Modeling Type( "Continuous" ) ),
Col( "/svg/g/g/g/g/rect/@y", Column Name( "y" ), Fill( "Use Once" ), Type( "Numeric" ), Format( {"Best", 15} ), Modeling Type( "Continuous" ) ),
Col( "/svg/g/@fill", Column Name( "colorAlternate" ), Fill( "-", "/svg/g" ), Type( "Character" ), Format( {"Best"} ), Modeling Type( "Continuous" ) ) ),
XML Wizard( 0 )
);
dtSVGLegend << selectwhere( Is Missing( y ) );
dtSVGLegend << deleterows;
For( i = 1, i <= N Rows( dtSVGLegend ), i += 1,
If( dtSVGLegend:color[i] == "",
dtSVGLegend:color[i] = dtSVGLegend:colorAlternate[i]
);
If( dtSVGLegend:text[i] == "",
dtSVGLegend:text[i] = dtSVGLegend:textAlternate[i]
);
);
dtSVGLegend << deletecolumns( {textAlternate, y, colorAlternate} );
//dtSVGGraph<<SORT></SORT>L'output del log è invertito rispetto all'ultima volta...
questi sono i conteggi dei pixel per ogni colore:
#E6E6E6 < 12,5 13026.06075
#CCCCCC < 13.0 12648.7232
#B3B3B3 < 13,5 8322,47330000002
#999999 < 14,0 10780,35015
#808080 < 14,5 12529,58585
#666666 < 15,0 8507.05305
#4D4D4D < 15,5 4961,26459999998
#333333 < 16,0 3712,89360000002
#191919 < 16,5 2922,03675000001
#000000 >= 16,5 2535,49285
------ totale dei pixel grigi --------
totale 79945.9341
Due modi per rappresentare la dimensione della cornice del grafico...
fotogramma 318976 pixel
Questo è il prodotto della lunghezza dell'asse x * della lunghezza dell'asse y:
frame 3150 dati^2
È possibile utilizzare il rapporto tra pixel e dati^2 del fotogramma per convertire il conteggio dei pixel per ciascun colore.
I conteggi dei pixel includono i decimali perché vengono calcolati come aree di un gruppo di piccoli poligoni che il file SVG utilizza per creare il grafico. Poiché SVG è una variazione di XML, ho utilizzato la procedura guidata XML per generare le impostazioni XML per leggere i due file SVG. Uno dei file SVG è stato salvato dal frame(1), il grafico, e l'altro è stato salvato dal frame(2), la legenda. L'output del registro è etichettato con il testo della legenda, estratto dal file SVG. In JMP 15, la legenda si trova in un secondo fotogramma. Ciò sembra cambiare per JMP 16; se rimuovi con cura i bit relativi alla legenda, funziona ancora, senza le etichette.