Index: tmp/org.txm.analec.rcp/src/org/txm/macroprototypes/urs/exploit/SchemaAccessibilityScoresMacro.groovy
===================================================================
--- tmp/org.txm.analec.rcp/src/org/txm/macroprototypes/urs/exploit/SchemaAccessibilityScoresMacro.groovy	(revision 2146)
+++ tmp/org.txm.analec.rcp/src/org/txm/macroprototypes/urs/exploit/SchemaAccessibilityScoresMacro.groovy	(revision 2147)
@@ -1,148 +0,0 @@
-// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
-// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
-// @author mdecorde
-// @author sheiden
-
-// STANDARD DECLARATIONS
-package org.txm.macroprototypes.urs.exploit
-
-import org.kohsuke.args4j.*
-import groovy.transform.Field
-import org.txm.rcp.swt.widget.parameters.*
-import org.txm.annotation.urs.*
-import org.txm.macro.urs.AnalecUtils
-import visuAnalec.elements.*
-import org.txm.searchengine.cqp.corpus.*
-import org.txm.Toolbox
-import org.txm.rcp.commands.*
-import org.txm.statsengine.r.core.RWorkspace
-
-def selection = []
-for (def s : corpusViewSelections) {
-	if (s instanceof CQPCorpus) selection << s
-	else if (s instanceof Partition) selection.addAll(s.getParts())
-}
-
-if (selection.size() == 0) {
-	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
-	return false
-} else {
-	for (def c : selection) c.compute(false)
-}
-
-@Field @Option(name="schema_ursql", usage="TYPE@PROP=REGEX", widget="String", required=true, def="CHAINE")
-		String schema_ursql
-
-@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
-		int minimum_schema_size
-@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
-		int maximum_schema_size
-@Field @Option(name="schema_property_display", usage="schema property to show", widget="String", required=true, def="REF")
-		String schema_property_display
-@Field @Option(name="unit_ursql", usage="TYPE@PROP=REGEX", widget="String", required=false, def="MENTION")
-		String unit_ursql
-@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
-		boolean strict_inclusion
-@Field @Option(name="position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
-		int position_in_matches
-@Field @Option(name="sep", usage="choose between the len or freq columns", widget="Separator", metaVar="freq	len", required=true, def="")
-		def sep
-@Field @Option(name="sort_column", usage="choose between the len or freq columns", widget="StringArray", metaVar="freq	len", required=true, def="freq")
-		String sort_column
-@Field @Option(name="max_lines", usage="cut the number of lines shown. '0' means no cut", widget="Integer", required=false, def="0")
-		int max_lines
-//@Field @Option(name="output_graph", usage="Show chart", widget="Boolean", required=true, def="false")
-		output_graph = false
-@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
-		debug
-
-if (!ParametersDialog.open(this)) return;
-if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
-
-for (def corpus : selection) {
-	def analecCorpus = URSCorpora.getCorpus(corpus)
-
-	def errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)
-	if (errors.size() > 0) {
-		println "** The $schema_ursql schema URSQL cannot be computed in the corpus with types: $errors."
-		return;
-	}
-
-	errors=AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)
-	if (errors.size() > 0) {
-		println "** $unit_ursql unit URSQL cannot be computed in the corpus with types: $errors."
-		return;
-	}
-
-	def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, strict_inclusion);
-
-	int nSchemas = 0;
-
-	def scores = [:]
-	def lensnames = [:]
-	for (def schema : schemas) {
-
-		def allUnites = schema.getUnitesSousjacentesNonTriees()
-		
-		def units = AnalecUtils.filterElements(debug, allUnites, unit_ursql)
-		
-		selectedUnits = AnalecUtils.filterUniteByInclusion(debug, units, corpus.getMatches(), strict_inclusion, position_in_matches)
-		
-		int nUnites = selectedUnits.size();
-
-		if (!scores.containsKey(schema)) {
-			scores[schema] = 0;
-		}
-
-		scores[schema] = units.su
-		
-		String value = schema.getProp(schema_property_display);
-		nSchemas++;
-	}
-
-	//println "nSchemas=$nSchemas"
-	def freqs = lens.keySet();
-	freqs.sort();
-	int t = 0;
-	int n = 0;
-	//println "Fréquences ("+freqs.size()+")"
-	for (def f : freqs) {
-		t += f * lens[f]
-		n += lens[f]
-	}
-
-	if (n == 0) {
-		println "No units selected for schemas=$schema_ursql and units=$unit_ursql"
-		return false;
-	}
-	
-	coef = (t/n)
-	
-	def slens = null
-	if ("freq".equals(sort_column)) {
-		slens = lens.sort { a, b -> -a.value <=> -b.value ?: -a.key <=> -b.key }
-	} else {
-		slens = lens.sort { a, b -> -a.key <=> -b.key ?: -a.value <=> -b.value }
-	}
-	
-	def flens = []
-	slens.each { key, value -> value.times { flens << key } }
-	def nbins = flens.size()*2
-
-	println "Schema scores in '$corpus'. The average schema score is $t/$n = "+coef
-	println "Index:\nlen\tfreq\tcfreq"
-	int nShown = 0;
-	for( def it : slens) {
-		println it.key+"	"+it.value+"	"+(cfreq+=it.value)+"	"+lensnames[it.key].join(", ")
-		nShown++
-		if (max_lines > 0 && nShown >= max_lines) {
-			println "... (${slens.size() - max_lines})"
-			break;
-		}
-	}
-
-	
-	//return ["result":coef, "data":lens]
-}
-
-
Index: tmp/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasRatioMacro.groovy
===================================================================
--- tmp/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasRatioMacro.groovy	(revision 0)
+++ tmp/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemasRatioMacro.groovy	(revision 2147)
@@ -0,0 +1,135 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.exploit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.macro.urs.AnalecUtils
+import visuAnalec.elements.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.Toolbox
+import org.txm.rcp.commands.*
+import org.txm.statsengine.r.core.RWorkspace
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+} else {
+	for (def c : selection) c.compute(false)
+}
+
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=REGEX", widget="String", required=true, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="schema_property_display", usage="schema property to show", widget="String", required=true, def="REF")
+		String schema_property_display
+		
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=REGEX", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int position_in_matches
+		
+@Field @Option(name="units_margin_ursql", usage="TYPE@PROP=REGEX", widget="String", required=false, def="MENTION")
+		String units_margin_ursql
+@Field @Option(name="margin_strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean margin_strict_inclusion
+@Field @Option(name="margin_position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int margin_position_in_matches
+		
+@Field @Option(name="sep", usage="choose between the len or freq columns", widget="Separator", metaVar="freq	len", required=false, def="")
+		def sep
+@Field @Option(name="sort_column", usage="choose between the len or freq columns", widget="StringArray", metaVar="score	name", required=true, def="score")
+		String sort_column
+@Field @Option(name="max_lines", usage="cut the number of lines shown. '0' means no cut", widget="Integer", required=false, def="0")
+		int max_lines
+//@Field @Option(name="output_graph", usage="Show chart", widget="Boolean", required=true, def="false")
+		output_graph = false
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+for (def corpus : selection) {
+	def analecCorpus = URSCorpora.getCorpus(corpus)
+
+	def errors = AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)
+	if (errors.size() > 0) {
+		println "** The $schema_ursql schema URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+
+	errors=AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)
+	if (errors.size() > 0) {
+		println "** $unit_ursql unit URSQL cannot be computed in the corpus with types: $errors."
+		return;
+	}
+
+	def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, strict_inclusion);
+
+	int nSchemas = 0;
+
+	def scores = [:]
+	def fs = [:]
+	def fs_margin = [:]
+	for (def schema : schemas) {
+
+		def allUnites = schema.getUnitesSousjacentesNonTriees()
+		def units = AnalecUtils.filterElements(debug, allUnites, unit_ursql)
+		selectedUnits = AnalecUtils.filterUniteByInclusion(debug, units, corpus.getMatches(), strict_inclusion, position_in_matches)
+		
+		def units_margin = AnalecUtils.filterElements(debug, allUnites, units_margin_ursql)
+		selectedUnits_margin = AnalecUtils.filterUniteByInclusion(debug, units_margin, corpus.getMatches(), margin_strict_inclusion, margin_position_in_matches)
+		
+		if (!scores.containsKey(schema)) {
+			scores[schema] = 0;
+		}
+
+		scores[schema] = 0;
+		fs[schema] = selectedUnits.size();
+		fs_margin[schema] = selectedUnits_margin.size();
+		if (selectedUnits_margin.size() > 0) {
+			scores[schema] = (float)selectedUnits.size() / (float)selectedUnits_margin.size()
+		}
+		
+		nSchemas++;
+	}
+
+	if ("score".equals(sort_column)) {
+		scores = scores.sort { a, b -> -a.value <=> -b.value ?: -fs[a.key]<=> -fs[b.key] ?: a.key.getProps()[schema_property_display].compareTo(b.key.getProps()[schema_property_display]) }
+	} else {
+		scores = scores.sort { a, b -> a.key.getProps()[schema_property_display].compareTo(b.key.getProps()[schema_property_display]) ?: -a.value <=> -b.value ?: -fs[a.key]<=> -fs[b.key]}
+	}
+	
+	println "Schema scores in '$corpus'."
+	println "${schema_property_display}\tF\tF margin\tscore"
+	int nShown = 0;
+	for( def it : scores) {
+		println ""+it.key.getProps()[schema_property_display]+"\t"+fs[it.key]+"\t"+fs_margin[it.key]+"\t"+String.format( "%.2f", it.value * 100.0d )+"%"
+		nShown++
+		if (max_lines > 0 && nShown >= max_lines) {
+			println "... (${scores.size() - max_lines})"
+			break;
+		}
+	}
+
+	//return ["result":coef, "data":lens]
+}
+
Index: tmp/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemaLengthsMacro.groovy
===================================================================
--- tmp/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemaLengthsMacro.groovy	(revision 2146)
+++ tmp/org.txm.analec.rcp/src/org/txm/macro/urs/exploit/SchemaLengthsMacro.groovy	(revision 2147)
@@ -45,7 +45,7 @@
 		boolean strict_inclusion
 @Field @Option(name="position_in_matches", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
 		int position_in_matches
-@Field @Option(name="sep", usage="choose between the len or freq columns", widget="Separator", metaVar="freq	len", required=true, def="")
+@Field @Option(name="sep", usage="choose between the len or freq columns", widget="Separator", metaVar="freq	len", required=false, def="")
 		def sep
 @Field @Option(name="sort_column", usage="choose between the len or freq columns", widget="StringArray", metaVar="freq	len", required=true, def="freq")
 		String sort_column
