code changes for release 2.2.0

This commit is contained in:
2021-09-09 12:45:39 +02:00
parent c50ca2e577
commit e3e80f5796
25 changed files with 3519 additions and 238 deletions

View File

@ -1,12 +1,13 @@
#pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma version = 1.8
#pragma version = 1.9
#pragma IgorVersion = 6.2
#pragma ModuleName = PearlAnglescanProcess
#include "pearl-vector-operations"
#include "pearl-polar-coordinates"
#include <New Polar Graphs>
// copyright (c) 2013-17 Paul Scherrer Institut
// copyright (c) 2013-21 Paul Scherrer Institut
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -64,7 +65,7 @@
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2013-17 Paul Scherrer Institut @n
/// @copyright 2013-21 Paul Scherrer Institut @n
/// Licensed under the Apache License, Version 2.0 (the "License"); @n
/// you may not use this file except in compliance with the License. @n
/// You may obtain a copy of the License at
@ -80,6 +81,70 @@
/// PearlAnglescanProcess is declared in @ref pearl-anglescan-process.ipf.
/// append an angle scan strip to another one
///
/// concatenate two angle scan strips including matching attribute waves
/// and replace the first strip with the resulting waves.
/// this is useful if a scan was interrupted and continues in a second data file.
///
/// all accompanying 1D waves which have a matching length and exist in both source and destination folders
/// are concatenated and stored in the destination.
/// 'accompanying waves' are those in the same folder as the 2D strip wave and those in the :attr sub-folder.
///
/// @attention this function modifies all matching waves in the data and attr folders of strip1!
/// consider a backup before calling the function, or work on a copy of the original data
/// (cf. Igor's DuplicateDataFolder operation)!
///
/// @param[in,out] strip1 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan.
/// this is the first source wave and destination wave.
///
/// @param[in] strip2 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan.
/// this is the second source wave.
///
/// @return (string) semicolon-separated list of modified wave names (without folder path).
///
function /s strip_append(strip1, strip2)
wave strip1
wave strip2
dfref df1 = GetWavesDataFolderDFR(strip1)
dfref df2 = GetWavesDataFolderDFR(strip2)
variable ny1 = dimsize(strip1, 1)
variable ny2 = dimsize(strip2, 1)
concatenate /np=1 {strip2}, strip1
string modified = AddListItem(NameOfWave(strip1), "")
variable idf = 0
do
variable iw = 0
do
wave /z w1 = WaveRefIndexedDFR(df1, iw)
if (!WaveExists(w1))
break
endif
wave /z w2 = df2:$(NameOfWave(w1))
if (WaveExists(w1) && WaveExists(w2))
if ((DimSize(w1, 0) == ny1) && (DimSize(w1, 1) == 0) && (DimSize(w2, 0) == ny2) && (DimSize(w2, 1) == 0))
concatenate /np=0 {w2}, w1
modified = AddListItem(NameOfWave(w1), modified, "", Inf)
endif
endif
iw += 1
while(1)
df1 = df1:attr
df2 = df2:attr
if ((DataFolderRefStatus(df1) != 1) || (DataFolderRefStatus(df2) != 1))
break
endif
idf += 1
while(idf < 2)
return modified
end
/// delete a contiguous range of frames from a strip.
///
/// this can be used to remove a region of bad frames due to, e.g., measurement problems.
@ -299,7 +364,9 @@ function normalize_strip_phi(strip, theta, phi, [theta_offset, theta_range, chec
endif
// average over analyser angles
wave dist = ad_profile_y(strip, -inf, inf, "")
duplicate /free strip, strip_copy
MatrixFilter NanZapMedian strip_copy
wave dist = ad_profile_y(strip_copy, -inf, inf, "")
// smooth distribution function
duplicate /free dist, dist_smoo
@ -385,7 +452,9 @@ function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smoot
endif
// average over analyser angles
wave dist = ad_profile_y(strip, -inf, inf, "")
duplicate /free strip, strip_copy
MatrixFilter NanZapMedian strip_copy
wave dist = ad_profile_y(strip_copy, -inf, inf, "")
// smooth distribution function
duplicate /free dist, dist_smoo
@ -484,7 +553,9 @@ function normalize_strip_thetaphi(strip, theta, phi, [theta_offset, smooth_metho
endif
// average over analyser angles
wave dist = ad_profile_y(strip, -inf, inf, "")
duplicate /free strip, strip_copy
MatrixFilter NanZapMedian strip_copy
wave dist = ad_profile_y(strip_copy, -inf, inf, "")
// smooth distribution function
duplicate /free dist, dist_smoo
@ -542,7 +613,9 @@ function normalize_strip_theta_scans(strip, theta, [theta_offset, smooth_method,
endif
// average over analyser angles
wave dist = ad_profile_y(strip, -inf, inf, "")
duplicate /free strip, strip_copy
MatrixFilter NanZapMedian strip_copy
wave dist = ad_profile_y(strip_copy, -inf, inf, "")
// smooth distribution function
duplicate /free dist, dist_smoo
@ -635,6 +708,7 @@ function normalize_strip_2d(strip, theta, [theta_offset, smooth_method, smooth_f
variable ny = dimsize(strip, 1)
duplicate /free strip, dist, alpha_int, theta_int
MatrixFilter NanZapMedian dist
theta_int = theta[q] - theta_offset
alpha_int = dimoffset(strip, 0) + p * dimdelta(strip, 0)
redimension /n=(nx * ny) dist, alpha_int, theta_int
@ -1955,7 +2029,7 @@ static function /s display_polar_graph(graphname, [angle_offset, do_ticks])
WMPolarGraphSetVar(graphname, "doAngleTickLabelSubRange", 1)
WMPolarGraphSetVar(graphname, "angleTickLabelRangeStart", 0)
WMPolarGraphSetVar(graphname, "angleTickLabelRangeExtent", 90)
WMPolarGraphSetStr(graphname, "angleTickLabelNotation", "%g<EFBFBD>")
WMPolarGraphSetStr(graphname, "angleTickLabelNotation", "%g°")
WMPolarGraphSetVar(graphname, "doPolarGrids", 0)
WMPolarGraphSetVar(graphname, "doRadiusTickLabels", 0)
@ -2083,9 +2157,9 @@ static function /s draw_hemi_axes(graphname, [do_grids])
SetDrawEnv /W=$graphname textxjust= 1,textyjust= 2
SetDrawEnv /W=$graphname save
radi = calc_graph_radius(30, projection=projection)
DrawText /W=$graphname radi, -0.1, "30<EFBFBD>"
DrawText /W=$graphname radi, -0.1, "30°"
radi = calc_graph_radius(60, projection=projection)
DrawText /W=$graphname radi, -0.1, "60<EFBFBD>"
DrawText /W=$graphname radi, -0.1, "60°"
endif
setdatafolder savedf
@ -2205,7 +2279,7 @@ function /s display_scanlines(nickname, alpha_lo, alpha_hi, m_theta, m_tilt, m_p
make /n=1 /d /free d_polar, d_azi
variable n_alpha = round(alpha_hi - alpha_lo) + 1
make /n=(n_alpha) /d /free analyser
setscale /i x alpha_lo, alpha_hi, "<EFBFBD>", analyser
setscale /i x alpha_lo, alpha_hi, "°", analyser
analyser = x
convert_angles_ttpa2polar(m_theta, loc_m_tilt, m_phi, analyser, d_polar, d_azi)
@ -2526,50 +2600,78 @@ function set_polar_graph_cursor(nickname, cursorname, polar_angle, azim_angle, [
endif
end
/// add an arbitrary angle scan to a hemispherical scan grid.
/// add arbitrary angle scan data to a hemispherical scan grid.
///
/// the hemi grid must have been created in the current data folder by the make_hemi_grid function.
/// the function determines the bin size at the given polar angle,
/// and adds all data points which fall into a bin.
/// a point which lies exactly on the upper boundary falls into the next bin.
/// this function does not clear previous values before adding new data.
/// the function fills the input data into bins defined by the hemi scan grid.
/// it sums up the values and weights of the data points which fall into each bin,
/// and adds the results to the totals and weights waves of the existing hemi grid.
/// finally, it updates the values wave (values divided by weights).
///
/// the hemi grid must have been created in the current data folder by the make_hemi_grid() function.
/// the function does not clear previous values before adding new data.
/// values are added to the _tot wave, weights to the _wt wave.
/// the intensity (_i) wave is calculated as _tot / _wt.
/// the intensity (_i/values) wave is calculated as _tot divided by _wt.
///
/// @param nickname name prefix of holo waves.
/// empty if waves are in current data folder.
/// @param values counts/intensity values at the positions given in the polara nd azi waves.
/// one- or two-dimensional.
/// NaN values are ignored.
/// @param polar polar angles (in degrees) of each data point.
/// allowed range 0 <= theta <= 90.
/// no specific ordering required.
/// @param azi azimuthal angles (in degrees) of each data point.
/// allowed range -360 <= phi < +360.
/// no specific order required.
/// @param weights weight or accumulation time of each point of values.
/// weights must be positive. values with weight 0 are ignored.
/// defaults to 1 if not specified.
///
/// the values, weights, polar and azi waves must have the same dimensions (one- or two-dimensional).
/// no specific order is required, the function sorts (copies of) the arrays internally.
///
/// the actual binning is delegated to the thread-safe add_anglescan_worker() function
/// under Igor's automatic multi-threading facility.
///
function hemi_add_anglescan(nickname, values, polar, azi, [weights])
string nickname // name prefix of holo waves.
// may be empty.
wave values // intensity values
// the wave can be one- or two-dimensional.
// no specific order required, the function sorts the arrays internally
wave polar // polar coordinates. allowed range 0 <= theta <= 90
// dimensions corresponding to value.
wave azi // azimuthal coordinates. allowed range -360 <= phi < +360
// dimensions corresponding to value.
wave weights // total accumulation time of each point of values. default = 1
string nickname
wave values
wave polar
wave azi
wave weights
dfref savedf = GetDataFolderDFR()
if (ParamIsDefault(weights))
duplicate /free values, weights
weights = 1
endif
// quick check whether hemi grid is existing
string s_prefix = ""
string s_int = "values"
dfref df = find_hemi_data(nickname, s_prefix, s_int)
string s_totals = s_prefix + "tot"
string s_weights = s_prefix + "wt"
string s_polar = s_prefix + "pol"
string s_azim = s_prefix + "az"
string s_index = s_prefix + "index"
string s_theta = s_prefix + "th"
wave /sdfr=df /z w_values = $s_int
wave /sdfr=df /z w_azim = $s_azim
wave /sdfr=df /z w_polar = $s_polar
wave /sdfr=df /z w_theta = $s_theta
if (!waveexists(w_values) || !waveexists(w_azim) || !waveexists(w_polar))
abort "Missing hemispherical scan grid. Please call make_hemi_grid() first."
endif
string s_dphi = s_prefix + "dphi"
string s_nphis = s_prefix + "nphis"
// make internal copies, one-dimensional, ordered in theta
wave /sdfr=df w_polar = $s_polar
wave /sdfr=df w_azim = $s_azim
wave /sdfr=df w_values = $s_int
wave /sdfr=df w_totals = $s_totals
wave /sdfr=df w_weights = $s_weights
wave /sdfr=df w_index = $s_index
wave /sdfr=df w_theta = $s_theta
wave /sdfr=df w_dphi = $s_dphi
wave /sdfr=df w_nphis = $s_nphis
// make internal copies of input, one-dimensional, ordered in theta
duplicate /free values, values_copy
duplicate /free polar, polar_copy
duplicate /free azi, azi_copy
@ -2577,49 +2679,186 @@ function hemi_add_anglescan(nickname, values, polar, azi, [weights])
variable nn = dimsize(values, 0) * max(dimsize(values, 1), 1)
redimension /n=(nn) values_copy, polar_copy, azi_copy, weights_copy
sort /r polar_copy, polar_copy, azi_copy, values_copy, weights_copy
make /n=(numpnts(w_theta)) /free /df dfw
// for debugging: remove the MultiThread keyword and the ThreadSafe keywords of sub-functions
MultiThread dfw = add_anglescan_worker(p, values_copy, weights_copy, polar_copy, azi_copy, w_polar, w_azim, w_theta, w_index, w_dphi, w_nphis)
variable pp
for (pp = 0; pp < numpnts(dfw); pp += 1)
dfref tdf= dfw[pp]
wave df_totals = tdf:w_totals
wave df_weights = tdf:w_weights
w_totals += df_totals
w_weights += df_weights
endfor
w_values = w_weights > 0 ? w_totals / w_weights : nan
variable pol
SetDataFolder savedf
end
/// thread worker for hemi_add_anglescan
///
/// this function extracts one azimuthal scan from the input data and adds it to an existing holo scan.
/// it should be considered as a part of hemi_add_anglescan and not used elsewhere,
/// as its interface may change in the future.
///
/// the function takes as input the entire input data, an existing hemi grid and the index of a polar angle to work on.
/// the results are a w_totals and w_weights wave that can be added to the hemi scan.
/// the two waves are returned in a free data folder referenced by the return value of the function.
/// the function does not change global data.
///
threadsafe static function /df add_anglescan_worker(ith, values, weights, polar, azi, w_polar, w_azim, w_theta, w_index, w_dphi, w_nphis)
variable ith // index into w_theta
wave values // input data: intensity/counts
wave weights // input data: weights/dwell time
wave polar // input data: polar angles
wave azi // input data: azimuthal angles
wave w_polar // hemi grid
wave w_azim // hemi grid
wave w_theta // hemi grid
wave w_index // hemi grid
wave w_dphi // hemi grid
wave w_nphis // hemi grid
dfref savedf= GetDataFolderDFR()
dfref freedf= NewFreeDataFolder()
SetDataFolder freedf
make /n=(numpnts(w_polar)) /d w_totals, w_weights
variable pol = w_theta[ith]
variable pol_st = abs(w_theta[1] - w_theta[0])
variable pol1, pol2
variable pol1 = pol - pol_st / 2
variable pol2 = pol + pol_st / 2
extract /free /indx polar, sel, (pol1 < polar) && (polar <= pol2) && (numtype(values) == 0) && (weights > 0)
if (numpnts(sel) > 0)
duplicate /free /r=[0, numpnts(sel)-1] azi, azi_slice
duplicate /free /r=[0, numpnts(sel)-1] values, values_slice
duplicate /free /r=[0, numpnts(sel)-1] weights, weights_slice
azi_slice = azi[sel]
values_slice = values[sel]
weights_slice = weights[sel]
add_aziscan_core(values_slice, weights_slice, pol, azi_slice, w_theta, w_azim, w_index, w_dphi, w_totals, w_weights)
endif
SetDataFolder savedf
return freedf
end
/// thread worker for hemi_add_anglescan and hemi_add_aziscan
///
/// this function adds one azimuthal scan to an existing holo scan.
/// it should be considered as a part of hemi_add_anglescan and hemi_add_aziscan and not used elsewhere,
/// as its interface may change in the future.
///
/// the function takes as input an azimuthal scan and an existing hemi grid.
/// the results are added to w_totals and w_weights waves.
///
/// @attention the function sorts the input arrays by azimuthal angle!
/// these waves must not refer to global objects if multi-threading is used!
///
threadsafe static function add_aziscan_core(values, weights, polar, azi, w_theta, w_azim, w_index, w_dphi, w_totals, w_weights)
wave values // input data: intensity/counts
wave weights // input data: weights/dwell time
variable polar // input data: polar angle
wave azi // input data: angle positions of the azimuthal scan
// acceptable range: >= -360 and < +360
// no specific order required, the function sorts the array in place (!)
wave w_theta // hemi grid
wave w_azim // hemi grid
wave w_index // hemi grid
wave w_dphi // hemi grid
wave w_totals // output data: total counts in hemi grid order
wave w_weights // output data: total weights in hemi grid order
duplicate /free azi_copy, azi_slice
duplicate /free values_copy, values_slice
duplicate /free weights_copy, weights_slice
for (pol = 90; pol >= 0; pol -= pol_st)
pol1 = pol - pol_st / 2
pol2 = pol + pol_st / 2
extract /free /indx polar_copy, sel, (pol1 < polar_copy) && (polar_copy <= pol2)
if (numpnts(sel) > 0)
redimension /n=(numpnts(sel)) azi_slice, values_slice, weights_slice
azi_slice = azi_copy[sel]
values_slice = values_copy[sel]
weights_slice = weights_copy[sel]
hemi_add_aziscan(nickname, values_slice, pol, azi_slice, weights=weights_slice)
// destination slice coordinates
variable ipol = BinarySearch(w_theta, polar)
if (ipol < 0)
return -1
endif
variable d1, d2
if (ipol >= 1)
d1 = w_index[ipol - 1]
else
d1 = 0
endif
d2 = w_index[ipol] - 1
variable nd = d2 - d1 + 1
variable dphi = w_dphi[ipol]
make /n=(nd+1) /free bin_index
setscale /i x w_azim[d1] - dphi/2, w_azim[d2] + dphi/2, "deg", bin_index
// source slice coordinates
// order the slice from -dphi/2 to 360-dphi/2
azi = azi < 0 ? azi + 360 : azi
azi = azi >= 360 - dphi/2 ? azi - 360 : azi
sort azi, values, weights, azi
setscale /p x 0, 1, "", values, weights, azi
bin_index = BinarySearch(azi, x) + 1
bin_index = bin_index == -2 ? 0 : bin_index[p]
bin_index = bin_index == -1 ? numpnts(azi) : bin_index[p]
bin_index[nd] = numpnts(azi)
// loop over destination
variable id
variable v1, v2, w1, w2
for (id = 0; id < nd; id += 1)
if (bin_index[id+1] > bin_index[id])
v1 = w_totals[d1 + id]
w1 = w_weights[d1 + id]
if ((numtype(v1) == 2) || (w1 <= 0))
v1 = 0
w1 = 0
endif
v2 = sum(values, bin_index[id], bin_index[id+1] - 1)
w2 = sum(weights, bin_index[id], bin_index[id+1] - 1)
w_totals[d1 + id] = v1 + v2
w_weights[d1 + id] = w1 + w2
endif
endfor
end
/// add an azimuthal scan to a hemispherical scan grid.
/// add azimuthal data to a hemispherical scan grid.
///
/// the hemi grid must have been created in the current data folder by the make_hemi_grid function.
/// the hemi grid must have been created in the current data folder by the make_hemi_grid() function.
/// the function determines the bin size at the given polar angle,
/// and calculates the mean values of the data points which fall into a bin.
/// a point which lies exactly on the upper boundary falls into the next bin.
/// sums up the values and weights of the data points which fall into each bin,
/// and adds the results to the totals and weights waves of the existing hemi grid.
/// finally, it updates the values wave (values divided by weights).
///
/// @param nickname name prefix of holo waves.
/// empty if waves are in current data folder.
/// @param values counts/intensity values of the azimuthal scan at the positions given in the azi parameter.
/// @param polar polar angle (in degrees) where to add the azi scan.
/// @param azi angle positions of the azimuthal scan.
/// acceptable range: >= -360 and < +360.
/// no specific order required, the function sorts the array internally.
/// @param weights weight or accumulation time of each point of values.
/// defaults to 1 if not specified.
///
/// the actual binning is delegated to the thread-safe add_aziscan_core() function shared with hemi_add_anglescan().
///
function hemi_add_aziscan(nickname, values, polar, azi, [weights])
string nickname // name prefix of holo waves.
// may be empty.
wave values // intensity values of the azimuthal scan at the positions given in the azi parameter
variable polar // polar angle where to add the azi scan
wave azi // angle positions of the azimuthal scan
// acceptable range: >= -360 and < +360
// no specific order required, the function sorts the array internally
wave weights // total accumulation time of each point of values. default = 1
string nickname
wave values
variable polar
wave azi
wave weights
dfref savedf = GetDataFolderDFR()
duplicate /free values, values_copy
duplicate /free azi, azi_copy
if (ParamIsDefault(weights))
duplicate /free values, weights
weights = 1
duplicate /free values, weights_copy
weights_copy = 1
else
duplicate /free weights, weights_copy
endif
// hemi grid waves
string s_prefix = ""
string s_int = "values"
@ -2644,56 +2883,11 @@ function hemi_add_aziscan(nickname, values, polar, azi, [weights])
wave /sdfr=df w_dphi = $s_dphi
wave /sdfr=df w_nphis = $s_nphis
// destination slice coordinates
//polar = round(polar)
//variable ipol = 90 - polar
variable ipol = BinarySearch(w_theta, polar)
if (ipol < 0)
abort "assertion failed in hemi_add_aziscan(): polar angle not found in grid."
endif
variable d1, d2
if (ipol >= 1)
d1 = w_index[ipol - 1]
else
d1 = 0
endif
d2 = w_index[ipol] - 1
variable nd = d2 - d1 + 1
variable dphi = w_dphi[ipol]
variable az1, az2
// source slice coordinates
// order the slice from -dphi/2 to 360-dphi/2
azi = azi < 0 ? azi + 360 : azi
azi = azi >= 360 - dphi/2 ? azi - 360 : azi
duplicate /free values, sel_values
duplicate /free weights, sel_weights
// loop over destination
variable id
variable v1, v2, w1, w2
for (id = 0; id < nd; id += 1)
az1 = (id - 0.5) * dphi
az2 = (id + 0.5) * dphi
extract /free /indx azi, sel, (az1 <= azi) && (azi < az2)
if (numpnts(sel) > 0)
redimension /n=(numpnts(sel)) sel_values, sel_weights
sel_values = values[sel]
sel_weights = weights[sel]
v1 = w_totals[d1 + id]
w1 = w_weights[d1 + id]
if ((numtype(v1) == 2) || (w1 <= 0))
v1 = 0
w1 = 0
endif
v2 = sum(sel_values)
w2 = sum(sel_weights)
w_totals[d1 + id] = v1 + v2
w_weights[d1 + id] = w1 + w2
endif
endfor
w_values[d1, d1 + nd - 1] = w_totals[p] / w_weights[p]
add_aziscan_core(values_copy, weights_copy, polar, azi_copy, w_theta, w_azim, w_index, w_dphi, w_totals, w_weights)
w_values = w_weights > 0 ? w_totals / w_weights : nan
SetDataFolder savedf
end
/// interpolate a hemispherical scan onto a rectangular grid
@ -3011,8 +3205,9 @@ function import_tpi_scan(nickname, theta, phi, intensity, [folding, npolar, nogr
variable ifold
duplicate /free phi, fold_phi
for (ifold = 0; ifold < folding; ifold += 1)
fold_phi = fold_phi >= 360 ? fold_phi - 360 : fold_phi
hemi_add_anglescan(nickname, intensity, theta, fold_phi)
fold_phi = fold_phi >= 180 ? fold_phi + 360 / folding - fold_phi : fold_phi + 360 / folding
fold_phi += 360 / folding
endfor
if (nograph==0)
@ -3199,7 +3394,7 @@ function /wave hemi_azi_cut(nickname, pol)
make /n=(nsel) /o $s_cut
wave w_cut = $s_cut
w_cut = w_values[sel]
setscale /i x w_azim[sel[0]], w_azim[sel[nsel-1]], "<EFBFBD>", w_cut
setscale /i x w_azim[sel[0]], w_azim[sel[nsel-1]], "°", w_cut
setdatafolder savedf
return w_cut
else
@ -3209,23 +3404,37 @@ function /wave hemi_azi_cut(nickname, pol)
setdatafolder savedf
end
static function check_contrast(values, pcmin, pcmax, vmin, vmax)
static function check_contrast(values, pcmin, pcmax, vmin, vmax, sym)
wave values
variable pcmin
variable pcmax
variable &vmin
variable &vmax
variable sym
dfref save_df = GetDataFolderDFR()
dfref dfr = NewFreeDataFolder()
setdatafolder dfr
StatsQuantiles /inan /iw /q /z values
wave index = w_quantilesindex
variable imin = round(numpnts(index) * pcmin / 100)
variable imax = round(numpnts(index) * (100 - pcmax) / 100)
vmin = values[index[imin]]
vmax = values[index[imax]]
wave /z index = w_quantilesindex
setdatafolder save_df
if (waveexists(index))
variable imin = round(numpnts(index) * pcmin / 100)
variable imax = round(numpnts(index) * (100 - pcmax) / 100)
vmin = values[index[imin]]
vmax = values[index[imax]]
if (sym)
variable d = vmax - vmin
if ((vmax >= d/4) && (-vmin >= d/4))
vmax = min(abs(vmin), abs(vmax))
vmin = -vmax
endif
endif
else
vmin = wavemin(values)
vmax = wavemax(values)
endif
end
/// set the pseudocolor contrast by percentile.
@ -3243,12 +3452,21 @@ end
/// @param pcmax percentile above the maximum color (0-100).
/// @param graphname name of graph. default: top graph.
/// @param colortable name of new colortable. default: keep current table.
/// @param reversecolors reverse colors of new colorable.
/// takes effect only if colortable argument is defined.
/// @arg 0 (default) normal colors,
/// @arg 1 reverse color table
/// @param symmetric make scale symmetric about zero (for modulation functions, e.g.).
/// @arg 0 (default) do not enforce symmetry.
/// @arg 1 try symmetric scale if "reasonable".
///
function set_contrast(pcmin, pcmax, [graphname, colortable])
function set_contrast(pcmin, pcmax, [graphname, colortable, reversecolors, symmetric])
variable pcmin
variable pcmax
string graphname
string colortable
variable reversecolors
variable symmetric
if (ParamIsDefault(graphname))
graphname = ""
@ -3256,6 +3474,12 @@ function set_contrast(pcmin, pcmax, [graphname, colortable])
if (ParamIsDefault(colortable))
colortable = ""
endif
if (ParamIsDefault(reversecolors))
reversecolors = 0
endif
if (ParamIsDefault(symmetric))
symmetric = 0
endif
dfref save_df = GetDataFolderDFR()
@ -3285,9 +3509,12 @@ function set_contrast(pcmin, pcmax, [graphname, colortable])
rev = str2num("0" + StringFromList(4, info, ","))
if (strlen(colortable) > 0)
ctab = colortable
rev = reversecolors
endif
check_contrast(w, pcmin, pcmax, vmin, vmax, symmetric)
if (vmax > vmin)
ModifyGraph /w=$graphname zColor($objname)={w, vmin, vmax, $ctab, rev}
endif
check_contrast(w, pcmin, pcmax, vmin, vmax)
ModifyGraph /w=$graphname zColor($objname)={w, vmin, vmax, $ctab, rev}
endif
endif
endfor
@ -3307,9 +3534,12 @@ function set_contrast(pcmin, pcmax, [graphname, colortable])
rev = str2num("0" + StringFromList(3, info, ","))
if (strlen(colortable) > 0)
ctab = colortable
rev = reversecolors
endif
check_contrast(w, pcmin, pcmax, vmin, vmax, symmetric)
if (vmax > vmin)
ModifyImage /w=$graphname $objname ctab={vmin, vmax, $ctab, rev}
endif
check_contrast(w, pcmin, pcmax, vmin, vmax)
ModifyImage /w=$graphname $objname ctab={vmin, vmax, $ctab, rev}
endif
endif
endfor