Skip to content

Commit 5823b1b

Browse files
committed
Add imagej plugins to generate charts from tables
1 parent e25199b commit 5823b1b

5 files changed

Lines changed: 397 additions & 0 deletions

File tree

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package tableplugins;
2+
3+
import net.imagej.plot.AbstractPlot;
4+
import net.imagej.plot.BoxSeries;
5+
import net.imagej.plot.CategoryChart;
6+
import net.imagej.plot.PlotService;
7+
import net.imagej.table.Column;
8+
import net.imagej.table.Table;
9+
import org.scijava.ItemIO;
10+
import org.scijava.ItemVisibility;
11+
import org.scijava.command.Command;
12+
import org.scijava.plugin.Parameter;
13+
import org.scijava.plugin.Plugin;
14+
import net.imagej.ui.swing.widget.MultipleChoices;
15+
import net.imagej.ui.swing.widget.MutableChoices;
16+
17+
import java.util.*;
18+
19+
@Plugin(type = Command.class, menuPath="Table>BoxPlot")
20+
public class BoxPlotPlugin implements Command {
21+
22+
@Parameter(label = "Select table", callback = "tableChanged")
23+
private Table<Column<?>,?> table;
24+
25+
@Parameter(label = "Select columns", initializer = "tableChanged")
26+
public MultipleChoices<Column<Double>> valueColumns;
27+
28+
@Parameter(visibility = ItemVisibility.MESSAGE)
29+
private final String LABEL_OPTIONAL = "optional";
30+
31+
@Parameter(label = "Select key column", initializer = "tableChanged", required = false)
32+
public MutableChoices<Column<?>> keyColumn;
33+
34+
@Parameter(label = "Boxplot", type = ItemIO.OUTPUT)
35+
public AbstractPlot output;
36+
37+
@Parameter
38+
private PlotService plotService;
39+
40+
@Override
41+
public void run() {
42+
createChart();
43+
}
44+
45+
private void tableChanged() {
46+
if(keyColumn != null)
47+
keyColumn.setChoices(table, c -> c.getHeader());
48+
if(valueColumns != null) {
49+
Iterable<Column<Double>> choices = TablePluginUtils.filterDoubleColumns(table);
50+
valueColumns.setChoices(choices, c -> c.getHeader());
51+
for(Column<Double> choice : choices)
52+
valueColumns.set(choice, true);
53+
}
54+
}
55+
56+
private void createChart() {
57+
if (keyColumn != null)
58+
buildChartWithKeys();
59+
else
60+
buildChartWithoutKeys();
61+
}
62+
63+
private void buildChartWithKeys() {
64+
output = ChartBuilderWithKey.build(plotService, keyColumn.get(), valueColumns.get());
65+
buildTitle();
66+
}
67+
68+
private void buildChartWithoutKeys() {
69+
CategoryChart<String> chart = plotService.newCategoryChart(String.class);
70+
chart.numberAxis().setAutoRange();
71+
chart.categoryAxis().setLabel("Column");
72+
Map<String, Collection<Double>> data = new TreeMap<>();
73+
for (Column<Double> valueColumn : valueColumns.get())
74+
data.put(valueColumn.getHeader(), valueColumn);
75+
BoxSeries<String> series = chart.addBoxSeries();
76+
series.setLabel("data");
77+
series.setLegendVisible(false);
78+
series.setValues(data);
79+
output = chart;
80+
buildTitle();
81+
}
82+
83+
private void buildTitle() {
84+
String title = "Boxplot - ";
85+
for(Column<Double> col : valueColumns.get())
86+
title += col.getHeader() + ", ";
87+
output.setTitle(title.substring(0, title.length() - 2));
88+
}
89+
90+
91+
static private class ChartBuilderWithKey<K> {
92+
93+
final PlotService plotService;
94+
95+
private CategoryChart<K> chart;
96+
97+
private ChartBuilderWithKey(PlotService plotService) {
98+
this.plotService = plotService;
99+
}
100+
101+
private CategoryChart<K> getChart(Column<K> keyColumn, Iterable<Column<Double>> valueColumns) {
102+
chart = plotService.newCategoryChart(keyColumn.getType());
103+
chart.numberAxis().setAutoRange();
104+
chart.categoryAxis().setLabel(keyColumn.getHeader());
105+
for (Column<Double> valueColumn : valueColumns)
106+
addColumn(keyColumn, valueColumn);
107+
return chart;
108+
}
109+
110+
private void addColumn(Column<K> keyColumn, Column<Double> valueColumn) {
111+
BoxSeries<K> series = chart.addBoxSeries();
112+
series.setLabel(valueColumn.getHeader());
113+
MyMultiMap<K, Double> map = new MyMultiMap<>(keyColumn, valueColumn);
114+
series.setValues(map.toMap());
115+
}
116+
117+
static private <K> CategoryChart<K> build(PlotService plotService,
118+
Column<K> keyColumn, Iterable<Column<Double>> valueColumn) {
119+
return new ChartBuilderWithKey<K>(plotService).getChart(keyColumn, valueColumn);
120+
}
121+
}
122+
123+
static private class MyMultiMap<K,V> {
124+
125+
private Map<K, List<V>> map;
126+
127+
public MyMultiMap(Collection<? extends K> keys, Collection<? extends V> values) {
128+
map = new HashMap<>();
129+
Iterator<? extends K> kIterator = keys.iterator();
130+
Iterator<? extends V> vIterator = values.iterator();
131+
while(kIterator.hasNext() && vIterator.hasNext())
132+
add(kIterator.next(), vIterator.next());
133+
}
134+
135+
public void add(K k, V v) { get(k).add(v); }
136+
137+
private List<V> get(K k) {
138+
List<V> list = map.get(k);
139+
if(list == null) {
140+
list = new ArrayList<>();
141+
map.put(k, list);
142+
}
143+
return list;
144+
}
145+
146+
public Map<K, List<V>> toMap() { return map; }
147+
}
148+
149+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package tableplugins;
2+
3+
import net.imagej.table.*;
4+
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
5+
import org.apache.commons.math3.stat.descriptive.rank.Median;
6+
import org.scijava.ItemIO;
7+
import org.scijava.command.Command;
8+
import org.scijava.display.Display;
9+
import org.scijava.plugin.Parameter;
10+
import org.scijava.plugin.Plugin;
11+
12+
@Plugin(type = Command.class, menuPath="Table>Calculate Descriptive Statistics")
13+
public class DescriptiveStatisticsPlugIn implements Command {
14+
15+
@Parameter
16+
public Display<Table<Column<?>,?>> activeTableDisplay;
17+
18+
@Parameter(label = "Descriptive Statistics", type = ItemIO.OUTPUT)
19+
public Table<?,?> output;
20+
21+
@Override
22+
public void run() {
23+
GenericTable table = setupResultTable();
24+
for(Column<Double> column : TablePluginUtils.filterDoubleColumns(activeTableDisplay.get(0)))
25+
table.add(setupStatisticsColumn(column));
26+
output = table;
27+
}
28+
29+
static private GenericTable setupResultTable() {
30+
GenericTable table = new DefaultGenericTable();
31+
table.setRowCount(8);
32+
table.setRowHeader(0,"mean");
33+
table.setRowHeader(1,"standard deviation");
34+
table.setRowHeader(2,"variance");
35+
table.setRowHeader(3,"min");
36+
table.setRowHeader(4,"max");
37+
table.setRowHeader(5,"sum");
38+
table.setRowHeader(6,"median");
39+
table.setRowHeader(7,"N");
40+
return table;
41+
}
42+
43+
private static DoubleColumn setupStatisticsColumn(Column<Double> column) {
44+
SummaryStatistics stat = calculateSummaryStatistics(column);
45+
double median = calculateMean(column);
46+
DoubleColumn c = new DoubleColumn();
47+
c.setHeader(column.getHeader());
48+
c.add(stat.getMean());
49+
c.add(stat.getStandardDeviation());
50+
c.add(stat.getVariance());
51+
c.add(stat.getMin());
52+
c.add(stat.getMax());
53+
c.add(stat.getSum());
54+
c.add(median);
55+
c.add((double) stat.getN());
56+
return c;
57+
}
58+
59+
public static double calculateMean(Column<Double> column) {
60+
return new Median().evaluate(TablePluginUtils.toArray(column));
61+
}
62+
63+
public static SummaryStatistics calculateSummaryStatistics(Column<Double> column) {
64+
SummaryStatistics stat = new SummaryStatistics();
65+
for(double x : column)
66+
stat.addValue(x);
67+
return stat;
68+
}
69+
70+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package tableplugins;/*
2+
* To the extent possible under law, the ImageJ developers have waived
3+
* all copyright and related or neighboring rights to this tutorial code.
4+
*
5+
* See the CC0 1.0 Universal license for details:
6+
* http://creativecommons.org/publicdomain/zero/1.0/
7+
*/
8+
9+
import net.imagej.plot.*;
10+
import net.imagej.table.Column;
11+
import net.imagej.table.Table;
12+
import org.scijava.ItemIO;
13+
import org.scijava.command.Command;
14+
import org.scijava.plugin.Parameter;
15+
import org.scijava.plugin.Plugin;
16+
import org.scijava.util.Colors;
17+
import net.imagej.ui.swing.widget.MutableChoices;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
@Plugin(type = Command.class, menuPath="Table>ScatterPlot")
23+
public class ScatterPlotPlugin implements Command {
24+
25+
@Parameter(label = "Table", callback = "tableChanged")
26+
public Table<Column<?>, ?> table;
27+
28+
@Parameter(label = "X Column", initializer = "tableChanged")
29+
public MutableChoices<Column<Double>> xColumn;
30+
31+
@Parameter(label = "Y Column", initializer = "tableChanged")
32+
public MutableChoices<Column<Double>> yColumn;
33+
34+
@Parameter(label = "Scatter Plot", type = ItemIO.OUTPUT)
35+
public AbstractPlot output;
36+
37+
@Parameter
38+
private PlotService plotService;
39+
40+
@Override
41+
public void run() {
42+
generateChart();
43+
}
44+
45+
private void tableChanged() {
46+
Iterable<Column<Double>> l = TablePluginUtils.filterDoubleColumns(table);
47+
if(xColumn != null)
48+
xColumn.setChoices(l, c -> c.getHeader());
49+
if(yColumn != null)
50+
yColumn.setChoices(l, c -> c.getHeader());
51+
}
52+
53+
private void generateChart() {
54+
final String xLabel = xColumn.get().getHeader();
55+
final String yLabel = yColumn.get().getHeader();
56+
final String chart_title = "ScatterPlot - " + xLabel + " - " + yLabel;
57+
XYPlot plot = plotService.newXYPlot();
58+
plot.setTitle("Line Styles");
59+
List<Double> xs = new ArrayList<>(xColumn.get());
60+
List<Double> ys = new ArrayList<>(yColumn.get());
61+
XYSeries series = plot.addXYSeries();
62+
series.setValues(xs,ys);
63+
series.setStyle(plot.newSeriesStyle(Colors.RED, LineStyle.NONE, MarkerStyle.CIRCLE));
64+
plot.setTitle(chart_title);
65+
plot.xAxis().setLabel(xLabel);
66+
plot.yAxis().setLabel(yLabel);
67+
output = plot;
68+
}
69+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package tableplugins;
2+
3+
import net.imagej.table.Column;
4+
import net.imagej.table.Table;
5+
import org.apache.commons.math3.stat.inference.TTest;
6+
import org.scijava.ItemIO;
7+
import org.scijava.ItemVisibility;
8+
import org.scijava.command.Command;
9+
import org.scijava.plugin.Parameter;
10+
import org.scijava.plugin.Plugin;
11+
import net.imagej.ui.swing.widget.MutableChoices;
12+
13+
@Plugin(type = Command.class, menuPath="Table>Calculate t-Test")
14+
public class TTestPlugIn implements Command {
15+
16+
static final private String UNPAIRED = "unpaired t-test";
17+
static final private String PAIRED = "paired t-test";
18+
static final private String HOMOSCEDASTIC = "homoscedastic t-test";
19+
20+
@Parameter(label = "Select t-Test", choices = {UNPAIRED, PAIRED, HOMOSCEDASTIC})
21+
public String kindOfTTest = UNPAIRED;
22+
23+
@Parameter(label = "Table", callback = "tableChanged")
24+
public Table<Column<?>, ?> table;
25+
26+
@Parameter(label = "Column with first sample", initializer = "tableChanged")
27+
public MutableChoices<Column<Double>> firstColumn;
28+
29+
@Parameter(label = "Second with second sample", initializer = "tableChanged")
30+
public MutableChoices<Column<Double>> secondColumn;
31+
32+
@Parameter(label = "Properties", visibility = ItemVisibility.MESSAGE)
33+
private final String LABEL_PROPERTIES = "two-sampled, two-tailed t-tests comparing mean";
34+
35+
@Parameter(label = "p-value", type = ItemIO.OUTPUT)
36+
public double p_value;
37+
38+
private void tableChanged() {
39+
Iterable<Column<Double>> l = TablePluginUtils.filterDoubleColumns(table);
40+
if(firstColumn != null)
41+
firstColumn.setChoices(l, c -> c.getHeader());
42+
if(secondColumn != null)
43+
secondColumn.setChoices(l, c -> c.getHeader());
44+
}
45+
46+
@Override
47+
public void run() {
48+
Column<Double> s1 = firstColumn.get();
49+
Column<Double> s2 = secondColumn.get();
50+
switch (kindOfTTest) {
51+
case UNPAIRED:
52+
p_value = tTest(s1,s2);
53+
return;
54+
case PAIRED:
55+
p_value = pairedTTest(s1,s2);
56+
return;
57+
case HOMOSCEDASTIC:
58+
p_value = homoscedasticTTest(s1,s2);
59+
return;
60+
default:
61+
throw new IllegalArgumentException();
62+
}
63+
}
64+
65+
static public double tTest(Column<Double> sample1, Column<Double> sample2) {
66+
return new TTest().tTest(TablePluginUtils.toArray(sample1), TablePluginUtils.toArray(sample2));
67+
}
68+
69+
static public double pairedTTest(Column<Double> sample1, Column<Double> sample2) {
70+
return new TTest().pairedTTest(TablePluginUtils.toArray(sample1), TablePluginUtils.toArray(sample2));
71+
}
72+
73+
static public double homoscedasticTTest(Column<Double> sample1, Column<Double> sample2) {
74+
return new TTest().homoscedasticTTest(TablePluginUtils.toArray(sample1), TablePluginUtils.toArray(sample2));
75+
}
76+
}

0 commit comments

Comments
 (0)