#pragma rtGlobals=1 // Use modern global access method. #pragma ModuleName=WMPieChart #pragma version=8.04 // Released with Igor 8.04 #pragma IgorVersion=6.02 // for GetRTStackInfo(2), ColorWaveEditor client mode #pragma TextEncoding = "UTF-8" #include #include , version>=1.02 #include , version>=1.01 // PieChart.ipf // // Makes a pie chart using Igor Pro drawing tools and annotations The macro makes an empty graph // window and draws the pie chart in it. You supply a data wave, the function will create // FracWave, a temporary wave which contains a version of the data that has been normalized // to the sum, and then it will draw the wedges as polygons. // // The pie is drawn in window-relative coordinates. That is, a number between 0 and 1 // represents 0 to 100% of the window dimension. The graph window keeps the plot area // square so that the pie will be round. // // The pie is drawn in the ProgFront drawing layer. If you can't select the pie wedges, // make sure you are in drawing mode (type command-T to bring up the tool palette, and // click the lower button). If you are in drawing mode, but still can't select pie wedges, // you may be in the wrong drawing layer. While holding down the option key, click on // the tree button (second from bottom in the drawing tool palette) and select ProgFront // from the popup menu. // // You can modify the pie in various ways: // To move the pie, use the panel's Center X0 and Y0 controls. // To change the size of the pie, use the Pie Radius control. // To color a wedge choose Custom Colors and edit the associated color. // You can add more labels using Add Annotation in the Graph menu. // To make an exploded wedge, simply click and drag the wedge while in drawing mode. // // PROGRAMMERS: Version 6.32: May 17, 2013, Added PieChartForProgrammers() // for programmatic creation of 2D pie charts. 6.35: Also see ModifyPieChart(). // // REVISIONS // Version 4: Dec. 12, 1996, J. Weeks // Version 5.02: Jul. 2, 2004, JP - added PieChartWithLabels and auto-colorizing, // no longer uses permanent global waves. // Version 5.03b7: Oct. 14, 2004, JP - revised color method, replace Missing Parameter // Dialog with a panel similar to the Gizmo 3D Pie Chart panel. // Version 5.03: Oct. 20, 2004, JP - Rearranged the panel items, improved error messages, // rewrote PieChartWithLabels() as TwoDPieChart(), use resize hook to maintain aspect ratio // instead of width={Aspect,1}. // PieChartVersion is now 2. // Since the pie wedges are now drawn in ProgFront, not UserFront, older charts are // cleared and the panel is closed and recreated. // Version 5.04: April 22, 2005, JP - Fixed "Please Choose another Numeric Wave" bug. // Updating pie charts works if the window is renamed, PieChartVersion is now 3. // Version 5.05: December14, 2005, JP - Added Custom Colors, PieChartVersion is now 4. // Labels now are drawn using annotations. Double-click in pie chart opens Pie Chart panel, // Contextual click has shortened menu that includes Modify Pie Chart. Increased Saturation range. // Version 6.02: August 14, 2007, JP - Adjusted some control positions to make panel native GUI-friendly, panel not editable. // Version 6.03: October 5, 2007, JP - Fixed removal of labels when the Labels checkbox is unchecked. Uses WaveCRC for update check. // Version 6.04: October 10, 2007, JW - Modified to use new client color wave editor mode. // Version 6.05: September 25, 2008, JP - Allows 1 point waves (single wedge or full circle), // has Outline Wedges... option, variable stroke width. // Version 6.1: June 12, 2009, JP - Added PossiblyQuoteName code to work with liberally-named waves and data folders. // Now limits the list of waves to those that have 200 or fewer rows (previously limited to 1000 which is just an unreasonable number of wedges in a Pie Chart). // Version 6.32: May 17, 2013, JP - Added PieChartForProgrammers(), an extended version of Pie_Chart() for programmatic creation of 2D pie charts. // Added ModifyPieChart() for progammatic alteration of 2D pie charts. // The legacy Pie_Chart() and PieChart() routines now create panel-compatible pie charts, and use MaintainAspectUsingMargins() // instead of ModifyGraph width={Aspect,1}. // Version 6.33: July 22, 2013, JP - Minor control position adjustments. // Version 6.35: February 27, 2014, JP - Added missing RestoreDependency() calls where needed, mostly to PieChartForProgrammers(). // Version 6.38: October 12, 2015, JP - Added fill patterns, contextual menu to set color and patterns, one color for all. // Added WMPieAutomaticColor() and WMPieAutomaticPattern() which can be conveniently overridden to alter automatic colors and patterns. // Version 6.381: January 12, 2016, JP - Fixed "Structure field index out of bounds" errors when data wave is more than 100 points. // Version 6.382: January 13, 2016, JP - Changes to support liberal names for numeric data wave and label wave. // Version 6.383: May 24, 2016, JP - Labels group checkbox formatting // Version 7.01: July 5, 2016, JP - Text Wave Labels no longer have leading and trailing space added to them, which makes multi-line labels line up better. // Fixed repeated DoAlerts about Old version Pie Chart when user changes the name of the pie chart window. // Version 8: February 18, 2019, JP - Works with long wave and data folder names. If you use short names (31 or less), // earlier versions of the Pie Chart procedure will continue to work. // Version 8.04: October 8, 2019, JP - Added innerRadius, labelRotation, and explodeWedgesDistance. PieChartVersion is now 8. Static Constant kUseDrawText= 0 // Set kUseDrawText= 1 to use drawing tools text (the way PieChartVersions 1-3 did). // If you do that, you may need to manually remove annotation labels from updated pie charts. Menu "New" "Pie Chart", /Q, New2DPieChart() End Menu "2D Pie" "New 2D Pie Chart",/Q, New2DPieChart() "Show 2D Pie Chart Panel",/Q, ShowPieChartPanel() "2D Pie Chart Help",/Q,DisplayHelpTopic/K=1 "2D Pie Chart Procedure" WMPieChart#PossiblyShowPieChartMenu("Debug 2D Pie Chart..."),/Q, WMPieChart#fShowPieStructure() End Menu "Graph" WMPieChart#PossiblyShowPieChartMenu("Modify 2D Pie Chart..."),/Q, ShowPieChartPanel() End Static Function/S PossiblyShowPieChartMenu(menuItem) String menuItem String topPie= TopPieChart() String topWin= WinName(0,1) if( strlen(topWin) == 0 || CmpStr(topWin, topPie) != 0 ) menuItem="" // no menu item endif return menuItem End // Returns name of graph with the pie chart. // Use ModifyPieChart to modify an existing pie chart. Function/S PieChartForProgrammers(graphName, dataWave, labelsMethod, labelsTextWave, [pieRadius, labelRadius, centerX, centerY, startAngleDegrees, ccw, wedgeTotalPct, fontName, fontSize, quiet]) String graphName // "" for top graph, "_new_" to create a new graph (name returned), else must be name of existing graph Wave dataWave // data for wedges String labelsMethod // "_wave_", "_value_", "_percent_", "_percent_and_tenths_", "_none_" Wave/T/Z labelsTextWave // can be $"" if labelsMethod is not "_wave_", else the text wave holding the labels. // optional parameters (which need to be specified with name=value, such as labelRadius= 0.8) Variable pieRadius // 0 - 0.5 Variable labelRadius // 0 - 1, default is 0.7 * pieRadius Variable centerX // X coordinate of pie center (0 - 1), defaults to 0.5 Variable centerY // Y coordinate of pie center (0 - 1), defaults to 0.5 Variable startAngleDegrees // 0, 90, 180, or 270 corresponds to Right, Bottom, Left, or Top. Default is 0 (Right) Variable ccw // 0 for clockwise (the default), else counter-clockwise. Variable wedgeTotalPct // 0-100. Default is 100 (%) String fontName // font name for labels, "" means use the graph's default font (also the default). Variable fontSize // font size for labels, defaults to 10 points (if you want no labels, set labelsMethod="_none_" Variable quiet // 0 to allow DoAlert for errors, else quiet (no DoAlert dialogs) // set values for missing optional parameters if( ParamIsDefault(pieRadius) ) pieRadius= 0.5 endif if( ParamIsDefault(labelRadius) ) labelRadius= pieRadius * 0.7 endif if( ParamIsDefault(centerX) ) centerX= 0.5 endif if( ParamIsDefault(centerY) ) centerY= 0.5 endif if( ParamIsDefault(startAngleDegrees) ) startAngleDegrees= 0 endif if( ParamIsDefault(ccw) ) ccw= 0 // clockwise endif if( ParamIsDefault(wedgeTotalPct) ) wedgeTotalPct= 100 endif if( ParamIsDefault(fontName) ) fontName= "default" // default endif if( ParamIsDefault(fontSize) ) fontSize= 10 // points endif if( ParamIsDefault(quiet) ) quiet= 0 // allow DoAlerts endif // Use the parameters if( !WaveExists(dataWave) ) if( !quiet ) DoAlert 0, "Cannot find data wave: "+ GetWavesDataFolder(dataWave,2) endif return "" endif // "" for top graph, "_new_" to create a new graph (name returned), else must be name of existing graph graphName= InitPieChartGraph(win=graphName) STRUCT PieChartInfo pieInfo DefaultPieStruct(pieInfo) pieInfo.dataWaveFolder= GetWavesDataFolder(dataWave,1) pieInfo.dataWaveName= NameOfWave(dataWave) strswitch(labelsMethod) case "_none_": pieInfo.labelType= kPieLabelNone break case "_value_": pieInfo.labelType= kPieLabelValue break case "_percent_": pieInfo.labelType= kPieLabelPercent break case "_percent_and_tenths_": pieInfo.labelType= kPieLabelPercentTenths break case "_wave_": default: if( WaveExists(labelsTextWave) ) pieInfo.labelType= kPieLabelWave pieInfo.labelWaveFolder= GetWavesDataFolder(labelsTextWave,1) pieInfo.labelWaveName= NameOfWave(labelsTextWave) else if( !quiet ) DoAlert 0, "Cannot find labels wave: "+ GetWavesDataFolder(labelsTextWave,2) endif return "" endif break endswitch pieInfo.wedgesRadius= pieRadius pieInfo.labelRadius= labelRadius pieInfo.wedgesX0= CenterX pieInfo.wedgesY0= CenterY pieInfo.angle0Degrees= startAngleDegrees pieInfo.nextClockwise= ccw != 0 pieInfo.wedgesTotalPct= wedgeTotalPct pieInfo.fontName=fontName pieInfo.fontSize=fontSize TwoDPieChart(graphName, pieInfo) PutPieStruct(graphName,pieInfo) // ensures that UpdatePieChartPanel sees the assigned values. return graphName End // ModifyPieChart modifies an existing pie chart (added for Igor 6.32) // Note: one of stringvalue=str or numValue=num must be specified. // Returns truth that graphName and name were valid Function ModifyPieChart(graphName, name [ ,stringValue, numValue, red, green, blue, wedge]) String graphName // name of the pie chart graph, pass "" for top pie chart. See also TopPieChart(). String name // programming name of pieStruct element to modify String stringValue // optional: string value to assign to pieStruct element Variable numValue // optional: numeric value to assign to pieStruct element Variable red, green, blue // optional: color value to assign to pieStruct element Variable wedge // optional: for changing the properties of one wedge. if( !IsPieChart(graphName) ) graphName= TopPieChart() endif STRUCT PieChartInfo pieInfo if( !GetPieStruct(graphName, pieInfo) ) // window userData is gone. return 0 endif if( ParamIsDefault(stringValue) ) stringValue= "" endif if( ParamIsDefault(numValue) ) numValue= 0 endif if( ParamIsDefault(red) || ParamIsDefault(green) || ParamIsDefault(blue) ) if( CmpStr(name,"allWedgesColor") == 0 ) red= pieInfo.allWedgesRed green= pieInfo.allWedgesGreen blue=pieInfo.allWedgesBlue else red= 0; green=0; blue=0 endif endif Variable valid= 1 // cleared by default: case strswitch(name) default: valid= 0 break // Numeric Data case "dataWave": WAVE/Z dataWave= $stringValue if( WaveExists(dataWave) ) // note that we don't check the number of rows. 200 is a practical upper limit pieInfo.dataWaveFolder= GetWavesDataFolder(dataWave,1) pieInfo.dataWaveName= NameOfWave(dataWave) endif break // Labels case "labelType": strswitch( stringValue ) case "_none_": pieInfo.labelType= kPieLabelNone break case "_value_": pieInfo.labelType= kPieLabelValue break case "_percent_": pieInfo.labelType= kPieLabelPercent break case "_percent_and_tenths_": pieInfo.labelType= kPieLabelPercentTenths break case "_wave_": pieInfo.labelType= kPieLabelWave // pieInfo.labelWaveFolder= GetWavesDataFolder(labelsTextWave,1) // set using "labelWave" and stringValue // pieInfo.labelWaveName= NameOfWave(labelsTextWave) break endswitch break case "labelWave": WAVE/Z/T labelsTextWave= $stringValue if( WaveExists(labelsTextWave) ) // note that we don't check the number of rows. 200 is a practical upper limit pieInfo.labelWaveFolder= GetWavesDataFolder(labelsTextWave,1) pieInfo.labelWaveName= NameOfWave(labelsTextWave) pieInfo.labelType= kPieLabelWave endif break case "labelRadius": pieInfo.labelRadius= limit(numValue,0,1) // 0 to 1 (relative coordinates) break case "labelFontName": pieInfo.fontName= stringValue break case "labelFontSize": pieInfo.fontSize= numValue break case "labelColor": pieInfo.labelRed= red pieInfo.labelGreen= green pieInfo.labelBlue= blue break // Background case "backgroundColor": pieInfo.bkgRed= red pieInfo.bkgGreen= green pieInfo.bkgBlue= blue break // Wedges case "wedgesTotalPct": pieInfo.wedgesTotalPct= limit(numValue, 0, 100) break case "wedgesRadius": pieInfo.wedgesRadius= limit(numValue, 0, 1) // 0 to 1 (relative coordinates) break case "angle0Degrees": strswitch( stringValue ) case "Right": pieInfo.angle0Degrees= 0 break case "Bottom": pieInfo.angle0Degrees= 90 break case "Left": pieInfo.angle0Degrees= 180 break case "Top": pieInfo.angle0Degrees= 270 break default: pieInfo.angle0Degrees= limit(numValue, -360,360) break endswitch break case "nextWedgeClockwise": pieInfo.nextClockwise= limit(numValue,0,1) // boolean. break case "wedgesX0": pieInfo.wedgesX0= limit(numValue, 0, 1) // 0 to 1 (relative coordinates) break case "wedgesY0": pieInfo.wedgesY0= limit(numValue, 0, 1) // 0 to 1 (relative coordinates) break // Wedge Colors case "wedgesStroke": pieInfo.stroke= numValue // stroke width in points. break case "strokeColor": pieInfo.strokeRed= red pieInfo.strokeGreen= green pieInfo.strokeBlue= blue break case "wedgesLightness": pieInfo.lightness= limit(numValue, 0, 100) // 0 to 100 break case "wedgesSaturation": pieInfo.saturation= limit(numValue, 0, 100) // 0 to 100 break case "autoWedgesColor": numValue= limit(numValue,0,1) // boolean. if( numValue ) pieInfo.useCustomColors= 0 pieInfo.useAllWedgesColor= 0 break endif // else FALL THROUGH to custom Colors numValue= 1 // custom case "customColors": numValue= limit(numValue,0,1) // boolean. if( numValue ) // want custom colors: therefore either the customColorTable must already be filled in (numCustomColorsInitialized > 0 ) // or stringValue must be a color table wave (a color index wave whose X scaling we ignore) WAVE/Z colorWave= $stringValue // expected N x 3 wave, n between 1 and 100 String pathToDataWave= pieInfo.dataWaveFolder + PossiblyQuoteName(pieInfo.dataWaveName) WAVE/Z dw= $pathToDataWave if( WaveExists(colorWave) && DimSize(colorWave,0) >= 1 && DimSize(colorWave,1) >= 3 ) Variable i, rows= limit(DimSize(colorWave,0),0,100) for( i=0; i 0 ) pieInfo.allWedgesRed= red pieInfo.allWedgesGreen= green pieInfo.allWedgesBlue= blue endif if( pieInfo.useAllWedgesColor != numValue ) pieInfo.useAllWedgesColor= numValue pieInfo.useCustomColors= 0 // unchecking returns to auto. endif break case "wedgeColor": if( ParamIsDefault(wedge) ) Print "ModifyPieChart error: wedge=wedgeNumber is missing" else Variable useCustomColors= 1 WMPieSetWedgeColor(graphName, pieInfo, wedge, red, green, blue, useCustomColors) endif break // Wedge Patterns case "autoWedgePatterns": for(i=0; i 0 End // Copy fields from a version 6 pie info struct, with its fixed-length char arrays, // into a current-version pie info struct, with its String representations // for wave paths, wave name, and data folder names. // // The limitations on Structure char[] arrays means that paths to wave with long names or data folders // can be properly represented by only String members, not char[400] members. // So we need a variable-length PieChartInfo to support long names. Static Function CopyFixedPieStructToVarLength(win, pieIn, pieOut) String win // when a pie chart is first constructed, win cannot be "" STRUCT PieChartInfoFixedLength &pieIn // must be fully updated to version 6 STRUCT PieChartInfo &pieOut // current version, Igor 8.03 or later, filled with default values // Version pieOut.version = pieIn.version // Numeric Data pieOut.dataWaveFolder = pieIn.dataWaveFolder // copies from char[] to String pieOut.dataWaveName = pieIn.dataWaveName // Labels pieOut.labelType = pieIn.labelType pieOut.labelWaveFolder = pieIn.labelWaveFolder pieOut.labelWaveName = pieIn.labelWaveName pieOut.labelRadius = pieIn.labelRadius pieOut.fontName = pieIn.fontName pieOut.fontSize = pieIn.fontSize pieOut.labelRed = pieIn.labelRed pieOut.labelGreen = pieIn.labelGreen pieOut.labelBlue = pieIn.labelBlue // Background pieOut.bkgRed = pieIn.bkgRed pieOut.bkgGreen = pieIn.bkgGreen pieOut.bkgBlue = pieIn.bkgBlue // Wedges pieOut.wedgesTotalPct = pieIn.wedgesTotalPct pieOut.stroke = pieIn.stroke pieOut.strokeRed = pieIn.strokeRed pieOut.strokeGreen = pieIn.strokeGreen pieOut.strokeBlue = pieIn.strokeBlue pieOut.wedgesRadius = pieIn.wedgesRadius pieOut.angle0Degrees = pieIn.angle0Degrees pieOut.nextClockwise = pieIn.nextClockwise pieOut.wedgesX0 = pieIn.wedgesX0 pieOut.wedgesY0 = pieIn.wedgesY0 pieOut.lightness = pieIn.lightness pieOut.saturation = pieIn.saturation // Delay (auto) updates pieOut.delayUpdates = pieIn.delayUpdates // Version 3 members start here pieOut.dependencyDataFolderName = pieIn.dependencyDataFolderName // Version 4 members start here pieOut.useCustomColors = pieIn.useCustomColors pieOut.numCustomColorsInitialized = pieIn.numCustomColorsInitialized pieOut.customColorTable = pieIn.customColorTable // Version 5 members start here pieOut.outlineWedgesThickness = pieIn.outlineWedgesThickness pieOut.outlineWedgesFirst = pieIn.outlineWedgesFirst pieOut.outlineNumWedges = pieIn.outlineNumWedges pieOut.outlineWedgesRed = pieIn.outlineWedgesRed pieOut.outlineWedgesGreen = pieIn.outlineWedgesGreen pieOut.outlineWedgesBlue = pieIn.outlineWedgesBlue pieOut.outlineHideSpokes = pieIn.outlineHideSpokes // Version 6 members start here pieOut.useAllWedgesColor = pieIn.useAllWedgesColor pieOut.allWedgesRed = pieIn.allWedgesRed pieOut.allWedgesGreen = pieIn.allWedgesGreen pieOut.allWedgesBlue = pieIn.allWedgesBlue pieOut.numFillPatternsInitialized = pieIn.numFillPatternsInitialized pieOut.fillPatterns = pieIn.fillPatterns pieOut.patBkRed = pieIn.patBkRed pieOut.patBkGreen = pieIn.patBkGreen pieOut.patBkBlue = pieIn.patBkBlue // Version 8 members start here pieOut.wedgesInnerRadius = pieIn.wedgesInnerRadius pieOut.labelRotation = pieIn.labelRotation pieOut.explodeWedgesDistance = pieIn.explodeWedgesDistance End // Copy fields from a the current version pie info struct // with its String representations for wave paths, wave name, and data folder names // into a pie info struct with its fixed-length char arrays. // // The limitations on Structure char[] arrays means that paths to wave with long names or data folders // can be properly represented by only String members, not char[400] members. // but only fixed-length structures can be stored in strings and window userdata, // so we need a fixed-length version of the current PieChartInfo. Static Function MakePieStructFixedLength(pieIn, pieOut) STRUCT PieChartInfo &pieIn // must be fully updated to version PieChartVersion STRUCT PieChartInfoFixedLength &pieOut // current version, Igor 8.03 or later, filled with default values // Version pieOut.version = pieIn.version // Numeric Data pieOut.dataWaveFolder = pieIn.dataWaveFolder // copies from char[] to String pieOut.dataWaveName = pieIn.dataWaveName // Labels pieOut.labelType = pieIn.labelType pieOut.labelWaveFolder = pieIn.labelWaveFolder pieOut.labelWaveName = pieIn.labelWaveName pieOut.labelRadius = pieIn.labelRadius pieOut.fontName = pieIn.fontName pieOut.fontSize = pieIn.fontSize pieOut.labelRed = pieIn.labelRed pieOut.labelGreen = pieIn.labelGreen pieOut.labelBlue = pieIn.labelBlue // Background pieOut.bkgRed = pieIn.bkgRed pieOut.bkgGreen = pieIn.bkgGreen pieOut.bkgBlue = pieIn.bkgBlue // Wedges pieOut.wedgesTotalPct = pieIn.wedgesTotalPct pieOut.stroke = pieIn.stroke pieOut.strokeRed = pieIn.strokeRed pieOut.strokeGreen = pieIn.strokeGreen pieOut.strokeBlue = pieIn.strokeBlue pieOut.wedgesRadius = pieIn.wedgesRadius pieOut.angle0Degrees = pieIn.angle0Degrees pieOut.nextClockwise = pieIn.nextClockwise pieOut.wedgesX0 = pieIn.wedgesX0 pieOut.wedgesY0 = pieIn.wedgesY0 pieOut.lightness = pieIn.lightness pieOut.saturation = pieIn.saturation // Delay (auto) updates pieOut.delayUpdates = pieIn.delayUpdates // Version 3 members start here pieOut.dependencyDataFolderName = pieIn.dependencyDataFolderName // Version 4 members start here pieOut.useCustomColors = pieIn.useCustomColors pieOut.numCustomColorsInitialized = pieIn.numCustomColorsInitialized pieOut.customColorTable = pieIn.customColorTable // Version 5 members start here pieOut.outlineWedgesThickness = pieIn.outlineWedgesThickness pieOut.outlineWedgesFirst = pieIn.outlineWedgesFirst pieOut.outlineNumWedges = pieIn.outlineNumWedges pieOut.outlineWedgesRed = pieIn.outlineWedgesRed pieOut.outlineWedgesGreen = pieIn.outlineWedgesGreen pieOut.outlineWedgesBlue = pieIn.outlineWedgesBlue pieOut.outlineHideSpokes = pieIn.outlineHideSpokes // Version 6 members start here pieOut.useAllWedgesColor = pieIn.useAllWedgesColor pieOut.allWedgesRed = pieIn.allWedgesRed pieOut.allWedgesGreen = pieIn.allWedgesGreen pieOut.allWedgesBlue = pieIn.allWedgesBlue pieOut.numFillPatternsInitialized = pieIn.numFillPatternsInitialized pieOut.fillPatterns = pieIn.fillPatterns pieOut.patBkRed = pieIn.patBkRed pieOut.patBkGreen = pieIn.patBkGreen pieOut.patBkBlue = pieIn.patBkBlue // Version 8 members start here pieOut.wedgesInnerRadius = pieIn.wedgesInnerRadius pieOut.labelRotation = pieIn.labelRotation pieOut.explodeWedgesDistance = pieIn.explodeWedgesDistance End Static Function UpdateFixedPieStructToCurrent(win, pieInfo) String win // when a pie chart is first constructed, win cannot be "" STRUCT PieChartInfoFixedLength &pieInfo if( pieInfo.version != PieChartVersion ) // The data and label waves are designed to always be valid. // That means that the order of structure members up to labelWaveName // MUST BE KEPT IN THE SAME ORDER AND HAVE THE SAME SIZES FOREVER. // remember whatever old settings exist, then transfer them to the new default Pie Struct. Variable oldVersion=pieInfo.version Printf "Old version Pie Chart (%g) detected: updating to newer version (%g), some settings may need to be reset to defaults.\r", oldVersion, PieChartVersion String dwf= pieInfo.dataWaveFolder String dwn= pieInfo.dataWaveName Variable labelType= pieInfo.labelType String twf= pieInfo.labelWaveFolder String twn= pieInfo.labelWaveName STRUCT piePatterns fillPatterns Variable numFillPatternsInitialized= 0 switch( oldVersion ) case PieChartVersion: // fall through case 8: // Version 8 members start here Variable wedgesInnerRadius = pieInfo.wedgesInnerRadius String labelRotation = pieInfo.labelRotation Variable explodeWedgesDistance= pieInfo.explodeWedgesDistance // fall through case 6: // Version 6 members start here Variable useAllWedgesColor = pieInfo.useAllWedgesColor Variable allWedgesRed = pieInfo.allWedgesRed Variable allWedgesGreen = pieInfo.allWedgesGreen Variable allWedgesBlue = pieInfo.allWedgesBlue numFillPatternsInitialized= pieInfo.numFillPatternsInitialized fillPatterns= pieInfo.fillPatterns Variable patBkRed= pieInfo.patBkRed Variable patBkGreen =pieInfo.patBkGreen Variable patBkBlue =pieInfo.patBkBlue // fall through case 5: Variable outlineHideSpokes= pieInfo.outlineHideSpokes Variable outlineWedgesThickness= pieInfo.outlineWedgesThickness Variable outlineWedgesFirst= pieInfo.outlineWedgesFirst Variable outlineNumWedges= pieInfo.outlineNumWedges Variable outlineWedgesRed= pieInfo.outlineWedgesRed Variable outlineWedgesGreen= pieInfo.outlineWedgesGreen Variable outlineWedgesBlue= pieInfo.outlineWedgesBlue // fall through case 4: Variable useCustomColors= pieInfo.useCustomColors Variable numCustomColorsInitialized= pieInfo.numCustomColorsInitialized STRUCT pieColorTable customColorTable customColorTable= pieInfo.customColorTable // fall through case 3: String dependencyDataFolderName= pieInfo.dependencyDataFolderName // fall through case 2: // preserve version 2 stuff, which is the same place as the current version Variable labelRadius= pieInfo.labelRadius String fontName= pieInfo.fontName Variable fontSize= pieInfo.fontSize Variable labelRed= pieInfo.labelRed Variable labelGreen= pieInfo.labelGreen Variable labelBlue= pieInfo.labelBlue Variable bkgRed= pieInfo.bkgRed Variable bkgGreen= pieInfo.bkgGreen Variable bkgBlue= pieInfo.bkgBlue Variable wedgesTotalPct= pieInfo.wedgesTotalPct Variable stroke= pieInfo.stroke Variable strokeRed= pieInfo.strokeRed Variable strokeGreen= pieInfo.strokeGreen Variable strokeBlue= pieInfo.strokeBlue Variable wedgesRadius= pieInfo.wedgesRadius Variable angle0Degrees= pieInfo.angle0Degrees Variable nextClockwise= pieInfo.nextClockwise Variable wedgesX0= pieInfo.wedgesX0 Variable wedgesY0= pieInfo.wedgesY0 Variable lightness= pieInfo.lightness Variable saturation= pieInfo.saturation Variable delayUpdates= pieInfo.delayUpdates break endswitch // initialize the fixed-length pieInfo. DefaultFixedLengthPieStruct(pieInfo) // Always put Version 1 stuff back pieInfo.dataWaveFolder= dwf pieInfo.dataWaveName= dwn pieInfo.labelType= labelType pieInfo.labelWaveFolder= twf pieInfo.labelWaveName= twn // Put more recent version stuff back if it was there switch( oldVersion ) case PieChartVersion: // fall through case 8: // Version 8 members start here pieInfo.wedgesInnerRadius= wedgesInnerRadius pieInfo.labelRotation= labelRotation pieInfo.explodeWedgesDistance= explodeWedgesDistance // fall through case 6: // Version 6 members start here pieInfo.useAllWedgesColor= useAllWedgesColor pieInfo.allWedgesRed= allWedgesRed pieInfo.allWedgesGreen= allWedgesGreen pieInfo.allWedgesBlue= allWedgesBlue pieInfo.numFillPatternsInitialized= pieInfo.numFillPatternsInitialized pieInfo.fillPatterns= fillPatterns pieInfo.patBkRed= patBkRed pieInfo.patBkGreen= patBkGreen pieInfo.patBkBlue= patBkBlue // fall through case 5: pieInfo.outlineHideSpokes= outlineHideSpokes pieInfo.outlineWedgesThickness= outlineWedgesThickness pieInfo.outlineWedgesFirst= outlineWedgesFirst pieInfo.outlineNumWedges= outlineNumWedges pieInfo.outlineWedgesRed= outlineWedgesRed pieInfo.outlineWedgesGreen= outlineWedgesGreen pieInfo.outlineWedgesBlue= outlineWedgesBlue // fall through case 4: pieInfo.useCustomColors=useCustomColors pieInfo.numCustomColorsInitialized= numCustomColorsInitialized pieInfo.customColorTable= customColorTable // fall through case 3: pieInfo.dependencyDataFolderName= dependencyDataFolderName // fall through case 2: // restore version 2 stuff pieInfo.labelRadius= labelRadius pieInfo.fontName= fontName pieInfo.fontSize= fontSize pieInfo.labelRed= labelRed pieInfo.labelGreen= labelGreen pieInfo.labelBlue= labelBlue pieInfo.bkgRed= bkgRed pieInfo.bkgGreen= bkgGreen pieInfo.bkgBlue= bkgBlue pieInfo.wedgesTotalPct= wedgesTotalPct pieInfo.stroke= stroke pieInfo.strokeRed= strokeRed pieInfo.strokeGreen= strokeGreen pieInfo.strokeBlue= strokeBlue pieInfo.wedgesRadius= wedgesRadius pieInfo.angle0Degrees= angle0Degrees pieInfo.nextClockwise= nextClockwise pieInfo.wedgesX0= wedgesX0 pieInfo.wedgesY0= wedgesY0 pieInfo.lightness= lightness pieInfo.saturation=saturation pieInfo.delayUpdates = delayUpdates break endswitch if( oldVersion < 3 ) // New for Version 3 pieInfo.dependencyDataFolderName= win endif endif End // The limitations on Structure char[] arrays means that paths to wave with long names or data folders // can be properly represented by only String members, not char[400] members. // MakePieStructCompatible() fills out the long-name members of STRUCT PieChartInfo // from other userdata strings. Static Function MakePieStructCompatible(win, pieInfo) String win // when a pie chart is first constructed, win cannot be "" STRUCT PieChartInfo &pieInfo // Numeric Data String dataWavePath = GetUserData(win, "", PIE_USERDATA_PATH_TO_NUM_WAVE) if( strlen(dataWavePath) ) pieInfo.dataWaveFolder = ParseFilePath(1, dataWavePath, ":", 1, 0) // doesn't include the ending element, has trailing ":" pieInfo.dataWaveName = ParseFilePath(0, dataWavePath, ":", 1, 0) // keep only the ending element, no leading ":" endif // Labels String labelWavePath = GetUserData(win, "", PIE_USERDATA_PATH_TO_LBL_WAVE) if( strlen(labelWavePath) ) pieInfo.labelWaveFolder = ParseFilePath(1, labelWavePath, ":", 1, 0) // doesn't include the ending element, has trailing ":" pieInfo.labelWaveName = ParseFilePath(0, labelWavePath, ":", 1, 0) // keep only the ending element, no leading ":" endif // DependencyDataFolderName is remembered so that the window can be renamed. // Once set, dependencyDataFolderName shouldn't be changed. String dependencyDataFolderName= GetUserData(win, "", PIE_USERDATA_DATAFOLDER_NAME) if( strlen(dependencyDataFolderName) ) pieInfo.dependencyDataFolderName= dependencyDataFolderName endif End // If the user keeps to 31-char object names, // the saved pieStruct can be read by an earlier version of the Pie Chart code. Static Function PutPieStruct(win, pieInfo) String win // must currently BE a pie chart window (graph) STRUCT PieChartInfo &pieInfo if( !IsPieChart(win) ) win= TopPieChart() if( strlen(win) == 0 ) return 0 endif endif SetPieStruct(win, pieInfo) return 1 End Static Function SetPieStruct(win, pieInfo) String win // when a pie chart is first constructed, win cannot be "" STRUCT PieChartInfo &pieInfo if( strlen(win) == 0 ) return 0 endif Variable wt = WinType(win) if( wt != 1 ) // must be graph return 0 endif String dataWavePath = pieInfo.dataWaveFolder + pieInfo.dataWaveName // Note: not PossiblyQuote()-d SetWindow $win userData($PIE_USERDATA_PATH_TO_NUM_WAVE)= dataWavePath String labelWavePath = pieInfo.labelWaveFolder + pieInfo.labelWaveName // Note: not PossiblyQuote()-d SetWindow $win userData($PIE_USERDATA_PATH_TO_LBL_WAVE)= labelWavePath String dependencyDataFolderName= pieInfo.dependencyDataFolderName SetWindow $win userData($PIE_USERDATA_DATAFOLDER_NAME)= dependencyDataFolderName STRUCT PieChartInfoFixedLength pie6 MakePieStructFixedLength(pieInfo, pie6) String infoStr StructPut/S pie6, infoStr SetWindow $win userData(WMPieChart)= infoStr return 1 End // Prior to 6.32, TopPieChart was a static function. Function/S TopPieChart() String list= WinList("*", ";", "WIN:1") Variable i=0 do String win= StringFromList(i,list) if( strlen(win) == 0 ) return "" endif String userdata = GetUserData(win, "", "WMPieChart") if( strlen(userData) ) return win endif i += 1 while(1) return "" End // Debugging Static Function fShowPieStructure() String win= TopPieChart() if( strlen(win) == 0 ) Print "(no pie charts)" return 0 endif STRUCT PieChartInfo pieInfo GetPieStruct("", pieInfo) Printf "Window: %s, version= %d\r", win, pieInfo.version String dwf= pieInfo.dataWaveFolder String dwn= pieInfo.dataWaveName String pathToDataWave= dwf + PossiblyQuoteName(dwn) WAVE/Z dw= $pathToDataWave if( !WaveExists(dw) ) Print "Could not locate data wave: \""+pathToDataWave+"\"!" else Print "Data Wave: "+pathToDataWave endif String lwf= pieInfo.labelWaveFolder String lwn= pieInfo.labelWaveName if( strlen(lwn) ) String pathToLabelWave= lwf + PossiblyQuoteName(lwn) WAVE/Z/T tw= $pathToLabelWave if( !WaveExists(tw) ) Print "Could not locate "+pathToLabelWave+"." else Print "Label Wave: "+pathToLabelWave endif endif if( pieInfo.version >= 3 ) Print "Chart data folder: \""+ pieInfo.dependencyDataFolderName + "\"" endif if( pieInfo.version >= 4 ) Printf "useCustomColors= %d, numCustomColorsInitialized=%d\r", pieInfo.useCustomColors, pieInfo.numCustomColorsInitialized Variable i for(i=0; i< pieInfo.numCustomColorsInitialized;i+=1 ) Printf "r,g,b[%d]= %d, %d, %d\r", i, pieInfo.customColorTable.customRed[i], pieInfo.customColorTable.customGreen[i], pieInfo.customColorTable.customBlue[i] endfor endif if( pieInfo.version >= 5 ) Printf "outlineHideSpokes= %d, outlineWedgesThickness=%d\r", pieInfo.outlineHideSpokes, pieInfo.outlineWedgesThickness Printf "outlineWedgesFirst= %d, outlineNumWedges=%d\r", pieInfo.outlineWedgesFirst, pieInfo.outlineNumWedges Printf "outlineWedges (r, g, b)= (%d, %d, %d)\r", pieInfo.outlineWedgesRed, pieInfo.outlineWedgesGreen, pieInfo.outlineWedgesBlue endif if( pieInfo.version >= 6 ) Printf "useAllWedgesColor= %d, color=(%d,%d,%d)\r", pieInfo.useAllWedgesColor, pieInfo.allWedgesRed, pieInfo.allWedgesGreen, pieInfo.allWedgesBlue Printf "numFillPatternsInitialized=%d\r", pieInfo.numFillPatternsInitialized for(i=0; i< pieInfo.numFillPatternsInitialized;i+=1 ) Printf "fillpat[%d]= %d\r", i, pieInfo.fillPatterns.fillpat[i] endfor Printf "pattern bkg(r, g, b)= (%d, %d, %d)\r", pieInfo.patBkRed, pieInfo.patBkGreen, pieInfo.patBkBlue endif End Static Function UpdatePieChart(win) String win // get settings from the pie chart structure (not the panel) // and update the pie chart if( !IsPieChart(win) ) win= TopPieChart() if( strlen(win) == 0 ) return 0 endif endif STRUCT PieChartInfo pieInfo GetPieStruct(win, pieInfo) TwoDPieChart(win, pieInfo) RestoreDependency(win, pieInfo) PutPieStruct(win,pieInfo) // save any change to pieInfo.dependencyDataFolderName End Static Function RestoreDependency(win, pieInfo) String win STRUCT PieChartInfo &pieInfo String pathToDataWave= pieInfo.dataWaveFolder + PossiblyQuoteName(pieInfo.dataWaveName) WAVE/Z dw= $pathToDataWave if( !WaveExists(dw) ) return 0 endif Variable labelType= pieInfo.labelType if( labelType == kPieLabelWave ) String pathToLabelWave= pieInfo.labelWaveFolder + PossiblyQuoteName(pieInfo.labelWaveName) WAVE/Z/T tw= $pathToLabelWave endif if( pieInfo.useCustomColors ) WAVE/Z/U/W cw= $WedgeColorWavePath(pieInfo) // might not exist, yet. else WAVE/Z/U/W cw= $"" endif pieInfo.dependencyDataFolderName= SetUpDependency(win, pieInfo.dependencyDataFolderName, dw, tw, colorWaveOrNULL=cw) PutPieStruct(win,pieInfo) // save any change to pieInfo.dependencyDataFolderName End // Debugging static Function fResetCustomColors([win]) String win if( ParamIsDefault(win) ) win= TopPieChart() endif if( !IsPieChart(win) ) Print "(no pie charts)" return 0 endif STRUCT PieChartInfo pieInfo GetPieStruct(win, pieInfo) String chartDFName= pieInfo.dependencyDataFolderName String pathToColorWave= ChartNameDFVar(chartDFName, "pieChartCustomColors") KillWaves/Z $pathToColorWave pieInfo.useCustomColors= 0 pieInfo.numCustomColorsInitialized= 0 pieInfo.useAllWedgesColor= 0 PutPieStruct(win,pieInfo) // save any change to pieInfo.dependencyDataFolderName UpdatePieChartPanel() UpdatePieChart("") End // You can use an override function to change this algorithm // DisplayHelpTopic "Function Overrides" Function WMPieAutomaticColor(wedge, numWedges, red, green, blue) Variable wedge // input, 0 is the first wedge. Variable numWedges // input, number of wedges in total Variable &red, &green, &blue // outputs each in the range of 0-65535 WM_GetDistinctColor(wedge, numWedges, red, green, blue,1) // red, green, blue are 0-65535 End // returns wedge color unmodified by saturation or lightness Function WMPieColorForWedge(pieWin, wedgeNo, numWedges, pieInfo, red, green, blue) String pieWin Variable wedgeNo, numWedges STRUCT PieChartInfo &pieInfo // see DefaultPieStruct and GetPieStruct Variable &red, &green, &blue // OUTPUTS Variable haveCustomColor= pieInfo.useCustomColors Variable oneColorForAll= pieInfo.useAllWedgesColor if( oneColorForAll ) red= pieInfo.allWedgesRed green= pieInfo.allWedgesGreen blue= pieInfo.allWedgesBlue elseif( haveCustomColor ) String pathToColorWave= CreateWedgeColorWave(pieWin, pieInfo) Wave/U/W/Z cw=$pathToColorWave if( !WaveExists(cw) || wedgeNo >= DimSize(cw,0) ) WMPieAutomaticColor(wedgeNo,numWedges,red, green, blue) // red, green, blue are 0-65535 else red= cw[wedgeNo][0] green= cw[wedgeNo][1] blue= cw[wedgeNo][2] endif else WMPieAutomaticColor(wedgeNo,numWedges,red, green, blue) // red, green, blue are 0-65535 endif End // returns truth that wedge is valid // returns wedge color unmodified by saturation or lightness Function WMPieGetWedgeColor(win, wedge, red, green, blue) String win Variable wedge Variable &red, &green, &blue Variable valid= 0 STRUCT PieChartInfo pieInfo if( GetPieStruct(win, pieInfo) ) String pathToDataWave= pieInfo.dataWaveFolder + PossiblyQuoteName(pieInfo.dataWaveName) WAVE/Z DataWave= $pathToDataWave if( WaveExists(DataWave) ) Variable NumWedges= numpnts(DataWave) if( wedge >= 0 && wedge < NumWedges ) WMPieColorForWedge(win, wedge, NumWedges, pieInfo, red, green, blue) // red, green, blue are 0-65535 valid= 1 endif endif endif return valid End // Note that calling this routine will never leave the pie chart in Automatic Colors mode. // don't forget to call // PutPieStruct(win,pieInfo) // save any change to pieInfo.dependencyDataFolderName // UpdatePieChartPanel() // UpdatePieChart(win) Function WMPieSetWedgeColor(win, pieInfo, wedge, red, green, blue, useCustomColors) String win STRUCT PieChartInfo &pieInfo Variable wedge Variable red, green, blue Variable useCustomColors // if 1 switch to custom colors without asking (appropriate for programmer's i/f) // if 0, switch to useAllWedgesColor mode Variable valid= 0 if( useCustomColors ) String pathToDataWave= pieInfo.dataWaveFolder + PossiblyQuoteName(pieInfo.dataWaveName) WAVE/Z DataWave= $pathToDataWave if( WaveExists(DataWave) ) Variable NumWedges= numpnts(DataWave) if( wedge >= 0 && wedge < NumWedges ) Variable wasAutoColors= pieInfo.useCustomColors == 0 && pieInfo.useAllWedgesColor == 0 Variable wasAllOneColor= pieInfo.useAllWedgesColor Variable wasCustomColors= pieInfo.useCustomColors String pathToColorWave= CreateWedgeColorWave(win, pieInfo) Wave/U/W/Z cw=$pathToColorWave // there are three important cases: // 1) the colors are all the same, in which case we copy the same color into each custom color // 2) the colors are automatic, in which case we copy the WM_distinct colors // 3) the color are already custom if( !wasCustomColors ) Variable i Variable oldRed= pieInfo.allWedgesRed Variable oldGreen= pieInfo.allWedgesGreen Variable oldBlue= pieInfo.allWedgesBlue for(i=0; i