...
 
Commits (43)
......@@ -127,7 +127,7 @@ public class CommonService extends Service {
protected static ConditionTO mapConditionToConditionTO(int condId, Condition cond) {
log.entry(condId, cond);
return log.exit(new ConditionTO(condId, cond.getAnatEntityId(), cond.getDevStageId(),
cond.getSpeciesId()));
cond.getSpeciesId(), null));
}
/**
......
......@@ -911,7 +911,7 @@ public abstract class Call<T extends Enum<T> & SummaryCallType, U extends CallDa
return this.getExpressionLevelInfo() == null? null: this.getExpressionLevelInfo().getRank();
}
/**
* Helper method delegated to {@link org.bgee.model.expressiondata.baseelements.ExpressionLevelInfo#getRank()
* Helper method delegated to {@link org.bgee.model.expressiondata.baseelements.ExpressionLevelInfo#getFormattedRank()
* ExpressionLevelInfo.getFormattedRank()} from {@link #getExpressionLevelInfo()}.
* @return See {@link org.bgee.model.expressiondata.baseelements.ExpressionLevelInfo#getFormattedRank()
* ExpressionLevelInfo.getFormattedRank()}.
......@@ -923,6 +923,31 @@ public abstract class Call<T extends Enum<T> & SummaryCallType, U extends CallDa
return log.exit(this.getExpressionLevelInfo() == null? null:
this.getExpressionLevelInfo().getFormattedRank());
}
/**
* Helper method delegated to {@link org.bgee.model.expressiondata.baseelements.ExpressionLevelInfo#getExpressionScore()
* ExpressionLevelInfo.getExpressionScore()} from {@link #getExpressionLevelInfo()}.
* @return See {@link org.bgee.model.expressiondata.baseelements.ExpressionLevelInfo#getExpressionScore()
* ExpressionLevelInfo.getExpressionScore()}.
* @see #getExpressionLevelInfo()
* @see #getMeanRank()
* @see #getFormattedExpressionScore()
*/
public BigDecimal getExpressionScore() {
return this.getExpressionLevelInfo() == null? null: this.getExpressionLevelInfo().getExpressionScore();
}
/**
* Helper method delegated to {@link org.bgee.model.expressiondata.baseelements.ExpressionLevelInfo#getFormattedExpressionScore()
* ExpressionLevelInfo.getFormattedExpressionScore()} from {@link #getExpressionLevelInfo()}.
* @return See {@link org.bgee.model.expressiondata.baseelements.ExpressionLevelInfo#getFormattedExpressionScore()
* ExpressionLevelInfo.getFormattedExpressionScore()}.
* @see #getExpressionLevelInfo()
* @see #getExpressionScore()
*/
public String getFormattedExpressionScore() {
log.entry();
return log.exit(this.getExpressionLevelInfo() == null? null:
this.getExpressionLevelInfo().getFormattedExpressionScore());
}
@Override
public int hashCode() {
......
......@@ -72,8 +72,44 @@ public class ExpressionLevelInfo {
}
return log.exit(formatter);
}
/**
* @param number The {@code BigDecimal} to format.
* @return A {@code String} corresponding to the provided {@code number}, formatted
* with always 3 digits displayed, e.g.: 1.23, 12.3, 123, 1.23e3.
* No value returned will be equal to 0, the smallest value returned will be 0.01
*/
private static final String formatExpressionNumber(BigDecimal number) {
log.entry(number);
if (number == null) {
return log.exit(null);
}
BigDecimal threshold = new BigDecimal("0.01");
BigDecimal numberToFormat = number;
if (number.compareTo(threshold) < 0) {
numberToFormat = threshold;
}
NumberFormat formatter = null;
//start with values over 1000, more chances to have a match.
//And since we are going to round half up, 999.5 will be rounded to 1000
//IMPORTANT: if you want to change the rounding etc, you have to change the method getNumberFormat
if (numberToFormat.compareTo(new BigDecimal("999.5")) >= 0) {
formatter = FORMAT1000;
//2 significant digits kept below 10, so 9.995 will be rounded to 10
} else if (numberToFormat.compareTo(new BigDecimal("9.995")) < 0) {
formatter = FORMAT1;
//1 significant digit kept below 100, so 99.95 will be rounded to 100
} else if (numberToFormat.compareTo(new BigDecimal("99.95")) < 0) {
formatter = FORMAT10;
//0 significant digit kept below 1000, so 999.5 will be rounded to 1000
} else if (numberToFormat.compareTo(new BigDecimal("999.5")) < 0) {
formatter = FORMAT100;
}
//1E2 to 1e2
return log.exit(formatter.format(numberToFormat).toLowerCase(Locale.ENGLISH));
}
private final BigDecimal rank;
private final BigDecimal expressionScore;
private final QualitativeExpressionLevel<Gene> qualExprLevelRelativeToGene;
private final QualitativeExpressionLevel<AnatEntity> qualExprLevelRelativeToAnatEntity;
......@@ -81,21 +117,29 @@ public class ExpressionLevelInfo {
* @param rank See {@link #getRank()}
*/
public ExpressionLevelInfo(BigDecimal rank) {
this(rank, null, null);
this(rank, null, null, null);
}
/**
* @param rank See {@link #getRank()}
* @param expressionScore See {@link #getExpressionScore()}
* @param qualExprLevelRelativeToGene See {@link #getQualExprLevelRelativeToGene()}
* @param qualExprLevelRelativeToAnatEntity See {@link #getQualExprLevelRelativeToAnatEntity()}
*/
public ExpressionLevelInfo(BigDecimal rank,
public ExpressionLevelInfo(BigDecimal rank, BigDecimal expressionScore,
QualitativeExpressionLevel<Gene> qualExprLevelRelativeToGene,
QualitativeExpressionLevel<AnatEntity> qualExprLevelRelativeToAnatEntity) {
if (rank != null && rank.compareTo(new BigDecimal(0)) <= 0) {
if (rank != null && rank.compareTo(new BigDecimal("0")) <= 0) {
throw log.throwing(new IllegalArgumentException(
"The rank cannot be less than or equal to 0."));
}
if (expressionScore != null &&
(expressionScore.compareTo(new BigDecimal("0")) <= 0 ||
expressionScore.compareTo(new BigDecimal("100")) > 0)) {
throw log.throwing(new IllegalArgumentException(
"The expression score must be greater than 0 and less than or equal to 100"));
}
this.rank = rank;
this.expressionScore = expressionScore;
this.qualExprLevelRelativeToGene = qualExprLevelRelativeToGene;
this.qualExprLevelRelativeToAnatEntity = qualExprLevelRelativeToAnatEntity;
}
......@@ -110,32 +154,41 @@ public class ExpressionLevelInfo {
}
/**
* @return A {@code String} corresponding to the rank score of this call, formatted
* with always 3 digits displayed, e.g.: 1.23, 12.3, 123, 1.23e3, ...
* with always 3 digits displayed, e.g.: 1.23, 12.3, 123, 1.23e3.
* @see #getRank()
*/
public String getFormattedRank() {
log.entry();
if (this.rank == null) {
return log.exit(null);
}
NumberFormat formatter = null;
//start with values over 1000, more chances to have a match.
//And since we are going to round half up, 999.5 will be rounded to 1000
//IMPORTANT: if you want to change the rounding etc, you have to change the method getNumberFormat
if (this.rank.compareTo(new BigDecimal(999.5)) >= 0) {
formatter = FORMAT1000;
//2 significant digits kept below 10, so 9.995 will be rounded to 10
} else if (this.rank.compareTo(new BigDecimal(9.995)) < 0) {
formatter = FORMAT1;
//1 significant digit kept below 100, so 99.95 will be rounded to 100
} else if (this.rank.compareTo(new BigDecimal(99.95)) < 0) {
formatter = FORMAT10;
//0 significant digit kept below 1000, so 999.5 will be rounded to 1000
} else if (this.rank.compareTo(new BigDecimal(999.5)) < 0) {
formatter = FORMAT100;
}
//1E2 to 1e2
return log.exit(formatter.format(this.rank).toLowerCase(Locale.ENGLISH));
return log.exit(formatExpressionNumber(this.rank));
}
/**
* @return The {@code BigDecimal} corresponding to the expression score,
* reflecting the expression level of an {@code ExpressionCall}.
* The expression score is:
* <ul>
* <li> a normalization of the rank returned by {@link #getRank()}
* to a value between 1 and 100
* <li>The values are inverted as compared to the rank returned by {@link #getRank()}:
* the higher the expression score, the higher the expression level (for ranks, it is the opposite,
* the lower the rank, the higher the expression level).
* </ul>
* So, the max rank in a species corresponds to an expression score of 1,
* and a rank of 1 corresponds to an expression score of 100.
*
* @see #getFormattedExpressionScore()
* @see #getRank()
*/
public BigDecimal getExpressionScore() {
return expressionScore;
}
/**
* @return A {@code String} corresponding to the expression score of this call, formatted
* with always 3 digits displayed, e.g.: 1.23, 12.3, 100.
* @see #getExpressionScore()
*/
public String getFormattedExpressionScore() {
log.entry();
return log.exit(formatExpressionNumber(this.expressionScore));
}
/**
* @return {@code QualitativeExpressionLevel} for an {@code ExpressionCall}
......@@ -166,6 +219,7 @@ public class ExpressionLevelInfo {
+ ((qualExprLevelRelativeToAnatEntity == null) ? 0 : qualExprLevelRelativeToAnatEntity.hashCode());
result = prime * result + ((qualExprLevelRelativeToGene == null) ? 0 : qualExprLevelRelativeToGene.hashCode());
result = prime * result + ((rank == null) ? 0 : rank.hashCode());
result = prime * result + ((expressionScore == null) ? 0 : expressionScore.hashCode());
return result;
}
@Override
......@@ -201,6 +255,13 @@ public class ExpressionLevelInfo {
} else if (!rank.equals(other.rank)) {
return false;
}
if (expressionScore == null) {
if (other.expressionScore != null) {
return false;
}
} else if (!expressionScore.equals(other.expressionScore)) {
return false;
}
return true;
}
......@@ -208,6 +269,7 @@ public class ExpressionLevelInfo {
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("ExpressionLevelInfo [rank=").append(rank)
.append(", expressionScore=").append(expressionScore)
.append(", qualExprLevelRelativeToGene=").append(qualExprLevelRelativeToGene)
.append(", qualExprLevelRelativeToAnatEntity=")
.append(qualExprLevelRelativeToAnatEntity).append("]");
......
......@@ -209,7 +209,7 @@ public interface GlobalExpressionCallDAO extends DAO<GlobalExpressionCallDAO.Att
* as compared to {@code RawExpressionCallTO}s).
*
* @author Frederic Bastian
* @version Bgee 14, Feb. 2017
* @version Bgee 14, Jun. 2019
* @since Bgee 14, Feb. 2017
*/
public static class GlobalExpressionCallTO extends RawExpressionCallTO {
......@@ -221,11 +221,15 @@ public interface GlobalExpressionCallDAO extends DAO<GlobalExpressionCallDAO.Att
private final Set<GlobalExpressionCallDataTO> callDataTOs;
public GlobalExpressionCallTO(Integer id, Integer bgeeGeneId, Integer conditionId,
BigDecimal meanRank, Set<GlobalExpressionCallDataTO> callDataTOs) {
BigDecimal meanRank, Collection<GlobalExpressionCallDataTO> callDataTOs) {
super(id, bgeeGeneId, conditionId);
this.meanRank = meanRank;
this.callDataTOs = callDataTOs;
if (callDataTOs != null) {
this.callDataTOs = Collections.unmodifiableSet(new HashSet<>(callDataTOs));
} else {
this.callDataTOs = null;
}
//there should be at most one GlobalExpressionCallDataTO per data type.
//we simply use Collectors.toMap that throws an exception in case of key collision
if (this.callDataTOs != null) {
......@@ -244,8 +248,8 @@ public interface GlobalExpressionCallDAO extends DAO<GlobalExpressionCallDAO.Att
return meanRank;
}
/**
* @return A {@code Set} of {@code GlobalExpressionCallDataTO}s storing the data supporting this call,
* one for each of the requested
* @return An unmodifiable {@code Set} of {@code GlobalExpressionCallDataTO}s
* storing the data supporting this call, one for each of the requested
* {@link org.bgee.model.dao.api.expressiondata.DAODataType DAODataType}s.
*/
public Set<GlobalExpressionCallDataTO> getCallDataTOs() {
......
......@@ -19,7 +19,7 @@ import org.bgee.model.dao.api.anatdev.mapping.SummarySimilarityAnnotationDAO.Sum
import org.bgee.model.dao.api.expressiondata.BaseConditionTO;
import org.bgee.model.dao.api.expressiondata.CallDAO.CallTO;
import org.bgee.model.dao.api.expressiondata.ConditionDAO.ConditionTO;
import org.bgee.model.dao.api.expressiondata.ConditionDAO.GlobalConditionMaxRankTO;
import org.bgee.model.dao.api.expressiondata.ConditionDAO.ConditionRankInfoTO;
import org.bgee.model.dao.api.expressiondata.DiffExpressionCallDAO.DiffExpressionCallTO;
import org.bgee.model.dao.api.expressiondata.ExperimentExpressionDAO.ExperimentExpressionTO;
import org.bgee.model.dao.api.expressiondata.GlobalExpressionCallDAO.EntityMinMaxRanksTO;
......@@ -160,8 +160,8 @@ public class TOComparator {
return log.exit(areTOsEqual((ConditionTO) to1, (ConditionTO) to2, compareId));
} else if (to1 instanceof RawDataConditionTO) {
return log.exit(areTOsEqual((RawDataConditionTO) to1, (RawDataConditionTO) to2, compareId));
} else if (to1 instanceof GlobalConditionMaxRankTO) {
return log.exit(areTOsEqual((GlobalConditionMaxRankTO) to1, (GlobalConditionMaxRankTO) to2));
} else if (to1 instanceof ConditionRankInfoTO) {
return log.exit(areTOsEqual((ConditionRankInfoTO) to1, (ConditionRankInfoTO) to2));
} else if (to1 instanceof RawExpressionCallTO) {
return log.exit(areTOsEqual((RawExpressionCallTO) to1, (RawExpressionCallTO) to2,
compareId));
......@@ -768,7 +768,14 @@ public class TOComparator {
private static boolean areTOsEqual(ConditionTO to1, ConditionTO to2, boolean compareId) {
log.entry(to1, to2, compareId);
if (areTOsEqual((BaseConditionTO) to1, (BaseConditionTO) to2, compareId)) {
if (areTOsEqual((BaseConditionTO) to1, (BaseConditionTO) to2, compareId) &&
//ConditionRankInfoTO do not implement hashCode/equals
(to1.getRankInfoTOs() == null && to2.getRankInfoTOs() == null ||
to1.getRankInfoTOs() != null && to2.getRankInfoTOs() != null &&
to1.getRankInfoTOs().stream()
.allMatch(c1 -> to2.getRankInfoTOs().stream()
.anyMatch(c2 -> areTOsEqual(c1, c2))))) {
return log.exit(true);
}
return log.exit(false);
......@@ -804,12 +811,10 @@ public class TOComparator {
* @param to2 An {@code ConditionTO} to be compared to {@code to1}.
* @return {@code true} if {@code to1} and {@code to2} have all attributes equal.
*/
//TODO: unit test
private static boolean areTOsEqual(GlobalConditionMaxRankTO to1, GlobalConditionMaxRankTO to2) {
private static boolean areTOsEqual(ConditionRankInfoTO to1, ConditionRankInfoTO to2) {
log.entry(to1, to2);
if (Objects.equals(to1.getConditionId(), to2.getConditionId()) &&
Objects.equals(to1.getDataType(), to2.getDataType()) &&
if (Objects.equals(to1.getDataType(), to2.getDataType()) &&
areBigDecimalEquals(to1.getMaxRank(), to2.getMaxRank()) &&
areBigDecimalEquals(to1.getGlobalMaxRank(), to2.getGlobalMaxRank())) {
return log.exit(true);
......
......@@ -22,6 +22,7 @@ import org.bgee.model.dao.api.anatdev.mapping.SummarySimilarityAnnotationDAO.Sum
import org.bgee.model.dao.api.expressiondata.BaseConditionTO.Sex;
import org.bgee.model.dao.api.expressiondata.CallDAO.CallTO.DataState;
import org.bgee.model.dao.api.expressiondata.ConditionDAO;
import org.bgee.model.dao.api.expressiondata.ConditionDAO.ConditionRankInfoTO;
import org.bgee.model.dao.api.expressiondata.ConditionDAO.ConditionTO;
import org.bgee.model.dao.api.expressiondata.rawdata.RawDataConditionDAO.RawDataConditionTO;
import org.bgee.model.dao.api.expressiondata.DAODataType;
......@@ -419,24 +420,61 @@ public class TOComparatorTest extends TestAncestor {
assertTrue(TOComparator.areTOsEqual(to1, to2, false));
}
/**
* Test the generic method {@link TOComparator#areTOsEqual(TransferObject, TransferObject, boolean)}
* using {@code ConditionRankInfoTO}s.
*/
@Test
public void testAreConditionRankInfoTOsEqual() {
ConditionRankInfoTO to1 = new ConditionRankInfoTO(DAODataType.AFFYMETRIX, new BigDecimal("1000"), new BigDecimal("10000"));
ConditionRankInfoTO to2 = new ConditionRankInfoTO(DAODataType.AFFYMETRIX, new BigDecimal("1000"), new BigDecimal("10000"));
assertTrue(TOComparator.areTOsEqual(to1, to2));
//Check with BigDecimals of different scales
to2 = new ConditionRankInfoTO(DAODataType.AFFYMETRIX, new BigDecimal("1000.00"), new BigDecimal("10000.00"));
assertTrue(TOComparator.areTOsEqual(to1, to2));
//Check when they are not equal
to2 = new ConditionRankInfoTO(DAODataType.EST, new BigDecimal("1000"), new BigDecimal("10000"));
assertFalse(TOComparator.areTOsEqual(to1, to2, true));
to2 = new ConditionRankInfoTO(DAODataType.AFFYMETRIX, new BigDecimal("5000"), new BigDecimal("10000"));
assertFalse(TOComparator.areTOsEqual(to1, to2, true));
to2 = new ConditionRankInfoTO(DAODataType.AFFYMETRIX, new BigDecimal("1000"), new BigDecimal("50000"));
assertFalse(TOComparator.areTOsEqual(to1, to2, true));
}
/**
* Test the generic method {@link TOComparator#areTOsEqual(TransferObject, TransferObject, boolean)}
* using {@code ConditionTO}s.
*/
@Test
public void testAreConditionTOsEqual() {
ConditionTO to1 = new ConditionTO(1, "anatEntityId1", "stageId1", 99);
ConditionTO to2 = new ConditionTO(1, "anatEntityId1", "stageId1", 99);
ConditionTO to1 = new ConditionTO(1, "anatEntityId1", "stageId1", 99, null);
ConditionTO to2 = new ConditionTO(1, "anatEntityId1", "stageId1", 99, null);
assertTrue(TOComparator.areTOsEqual(to1, to2, true));
assertTrue(TOComparator.areTOsEqual(to1, to2, false));
to2 = new ConditionTO(1, "anatEntityId1", "stageId1", 8);
Collection<ConditionRankInfoTO> rankTOs = Arrays.asList(
new ConditionRankInfoTO(DAODataType.AFFYMETRIX, new BigDecimal("1000"), new BigDecimal("10000")),
new ConditionRankInfoTO(DAODataType.EST, new BigDecimal("1000"), new BigDecimal("10000")));
to1 = new ConditionTO(1, "anatEntityId1", "stageId1", 99, rankTOs);
to2 = new ConditionTO(1, "anatEntityId1", "stageId1", 99, rankTOs);
assertTrue(TOComparator.areTOsEqual(to1, to2, true));
assertTrue(TOComparator.areTOsEqual(to1, to2, false));
to2 = new ConditionTO(1, "anatEntityId1", "stageId1", 99, null);
assertFalse(TOComparator.areTOsEqual(to1, to2, true));
to2 = new ConditionTO(1, "anatEntityId2", "stageId1", 99);
to1 = new ConditionTO(1, "anatEntityId1", "stageId1", 99, null);
to2 = new ConditionTO(1, "anatEntityId1", "stageId1", 8, null);
assertFalse(TOComparator.areTOsEqual(to1, to2, true));
to2 = new ConditionTO(86, "anatEntityId1", "stageId1", 99);
to2 = new ConditionTO(1, "anatEntityId2", "stageId1", 99, null);
assertFalse(TOComparator.areTOsEqual(to1, to2, true));
to2 = new ConditionTO(86, "anatEntityId1", "stageId1", 99, null);
assertFalse(TOComparator.areTOsEqual(to1, to2, true));
assertTrue(TOComparator.areTOsEqual(to1, to2, false));
}
......
......@@ -201,7 +201,7 @@ public class GenerateOncoMXFile {
CallService.Attribute.ANAT_ENTITY_ID,
CallService.Attribute.DEV_STAGE_ID,
CallService.Attribute.CALL_TYPE, CallService.Attribute.DATA_QUALITY,
CallService.Attribute.MEAN_RANK,
CallService.Attribute.MEAN_RANK, CallService.Attribute.EXPRESSION_SCORE,
CallService.Attribute.GENE_QUAL_EXPR_LEVEL,
CallService.Attribute.ANAT_ENTITY_QUAL_EXPR_LEVEL));
}
......@@ -224,7 +224,7 @@ public class GenerateOncoMXFile {
"Developmental stage ID", "Developmental stage name",
"Expression level relative to gene",
"Expression level relative to anatomical entity",
"Call quality", "Expression rank score" });
"Call quality", "Expression rank score", "Expression score" });
}
// ************************************
......@@ -325,7 +325,8 @@ public class GenerateOncoMXFile {
new IsIncludedIn(allowedExpressionCategories), // gene expression cat.
new IsIncludedIn(allowedExpressionCategories), // anat. entity expression cat.
new IsIncludedIn(allowedCallQualities), // call qual.
new StrNotNullOrEmpty() // rank score
new StrNotNullOrEmpty(), // rank score
new StrNotNullOrEmpty() // expression score
};
//Write the calls
......@@ -349,6 +350,7 @@ public class GenerateOncoMXFile {
.getExpressionLevelCategory().toString());
toWrite.add(call.getSummaryQuality().toString());
toWrite.add(call.getFormattedMeanRank());
toWrite.add(call.getFormattedExpressionScore());
} catch (IllegalArgumentException e) {
log.error("Error with call: {}", call);
throw log.throwing(e);
......
......@@ -177,7 +177,7 @@ public class GenerateOncoMXFileTest extends TestAncestor {
//*** Gene calls ***
ExpressionCall gene1Call1 = new ExpressionCall(gene1, cond2_1, null,
ExpressionSummary.EXPRESSED, SummaryQuality.BRONZE,
null, new ExpressionLevelInfo(new BigDecimal("1"),
null, new ExpressionLevelInfo(new BigDecimal("1"), new BigDecimal("1"),
new QualitativeExpressionLevel<>(
ExpressionLevelCategory.getExpressionLevelCategory(gene1MinMaxRanks,
new BigDecimal("1")),
......@@ -188,7 +188,7 @@ public class GenerateOncoMXFileTest extends TestAncestor {
anat2MinMaxRanks)));
ExpressionCall gene1Call2 = new ExpressionCall(gene1, cond1_1, null,
ExpressionSummary.EXPRESSED, SummaryQuality.BRONZE,
null, new ExpressionLevelInfo(new BigDecimal("10.1"),
null, new ExpressionLevelInfo(new BigDecimal("10.1"), new BigDecimal("99.98319"),
new QualitativeExpressionLevel<>(
ExpressionLevelCategory.getExpressionLevelCategory(gene1MinMaxRanks,
new BigDecimal("10.1")),
......@@ -199,7 +199,7 @@ public class GenerateOncoMXFileTest extends TestAncestor {
anat1MinMaxRanks)));
ExpressionCall gene1Call3 = new ExpressionCall(gene1, cond3_1, null,
ExpressionSummary.EXPRESSED, SummaryQuality.BRONZE,
null, new ExpressionLevelInfo(new BigDecimal("200"),
null, new ExpressionLevelInfo(new BigDecimal("200"), new BigDecimal("99.63242"),
new QualitativeExpressionLevel<>(
ExpressionLevelCategory.getExpressionLevelCategory(gene1MinMaxRanks,
new BigDecimal("200")),
......@@ -211,7 +211,7 @@ public class GenerateOncoMXFileTest extends TestAncestor {
//not expressed call, should not have been seen in the anat. entity calls
ExpressionCall gene1Call4 = new ExpressionCall(gene1, cond3_2, null,
ExpressionSummary.NOT_EXPRESSED, SummaryQuality.SILVER,
null, new ExpressionLevelInfo(new BigDecimal("500"),
null, new ExpressionLevelInfo(new BigDecimal("500"), new BigDecimal("99.07828"),
new QualitativeExpressionLevel<>(
ExpressionLevelCategory.getExpressionLevelCategory(gene1MinMaxRanks,
new BigDecimal("500")),
......@@ -222,7 +222,7 @@ public class GenerateOncoMXFileTest extends TestAncestor {
anat3MinMaxRanks)));
ExpressionCall gene2Call1 = new ExpressionCall(gene2, cond1_2, null,
ExpressionSummary.EXPRESSED, SummaryQuality.BRONZE,
null, new ExpressionLevelInfo(new BigDecimal("100"),
null, new ExpressionLevelInfo(new BigDecimal("100"), new BigDecimal("99.81713"),
new QualitativeExpressionLevel<>(
ExpressionLevelCategory.getExpressionLevelCategory(gene2MinMaxRanks,
new BigDecimal("100")),
......@@ -233,7 +233,7 @@ public class GenerateOncoMXFileTest extends TestAncestor {
anat1MinMaxRanks)));
ExpressionCall gene2Call2 = new ExpressionCall(gene2, cond3_3, null,
ExpressionSummary.EXPRESSED, SummaryQuality.BRONZE,
null, new ExpressionLevelInfo(new BigDecimal("1000"),
null, new ExpressionLevelInfo(new BigDecimal("1000"), new BigDecimal("98.15472"),
new QualitativeExpressionLevel<>(
ExpressionLevelCategory.getExpressionLevelCategory(gene2MinMaxRanks,
new BigDecimal("1000")),
......@@ -244,7 +244,7 @@ public class GenerateOncoMXFileTest extends TestAncestor {
anat3MinMaxRanks)));
ExpressionCall gene3Call1 = new ExpressionCall(gene3, cond1_3, null,
ExpressionSummary.EXPRESSED, SummaryQuality.BRONZE,
null, new ExpressionLevelInfo(new BigDecimal("300"),
null, new ExpressionLevelInfo(new BigDecimal("300"), new BigDecimal("99.44771"),
new QualitativeExpressionLevel<>(
ExpressionLevelCategory.getExpressionLevelCategory(gene3MinMaxRanks,
new BigDecimal("300")),
......@@ -288,7 +288,8 @@ public class GenerateOncoMXFileTest extends TestAncestor {
new StrNotNullOrEmpty(), // gene expression cat.
new StrNotNullOrEmpty(), // anat. entity expression cat.
new StrNotNullOrEmpty(), // call qual.
new StrNotNullOrEmpty() // rank score
new StrNotNullOrEmpty(), // rank score
new StrNotNullOrEmpty() // expression score
};
List<List<Object>> allLines = new ArrayList<>();
String[] headers;
......@@ -308,7 +309,7 @@ public class GenerateOncoMXFileTest extends TestAncestor {
c.getCondition().getDevStage().getId(), c.getCondition().getDevStage().getName(),
c.getExpressionLevelInfo().getQualExprLevelRelativeToGene().getExpressionLevelCategory().toString(),
c.getExpressionLevelInfo().getQualExprLevelRelativeToAnatEntity().getExpressionLevelCategory().toString(),
c.getSummaryQuality().toString(), c.getFormattedMeanRank()))
c.getSummaryQuality().toString(), c.getFormattedMeanRank(), c.getFormattedExpressionScore()))
.collect(Collectors.toList());
assertEquals("Inccorect data written in file", expectedLines, allLines);
}
......
......@@ -135,8 +135,8 @@
<!-- WARNING: never removes these properties, otherwise your files will be named, e.g.,
*${filter.org.bgee.webapp.css.version.extension}.css. If you want to disable
versioning of CSS and JS files, just leave these properties empty. -->
<filter.org.bgee.webapp.css.version.extension>min${project.version}f</filter.org.bgee.webapp.css.version.extension>
<filter.org.bgee.webapp.javascript.version.extension>min${project.version}f</filter.org.bgee.webapp.javascript.version.extension>
<filter.org.bgee.webapp.css.version.extension>min${project.version}g</filter.org.bgee.webapp.css.version.extension>
<filter.org.bgee.webapp.javascript.version.extension>min${project.version}g</filter.org.bgee.webapp.javascript.version.extension>
<!-- This property defines where the minified CSS and JS files will be stored.
This is useful to be able to change this setting when running the webapp from within Eclipse
(Eclipse acquires its resources before any plugin can process them, so we modify
......@@ -368,6 +368,7 @@
<cssSourceFile>general.css</cssSourceFile>
<cssSourceFile>topanat.css</cssSourceFile>
<cssSourceFile>gene.css</cssSourceFile>
<cssSourceFile>species.css</cssSourceFile>
<cssSourceFile>source.css</cssSourceFile>
<cssSourceFile>sparql.css</cssSourceFile>
<cssSourceFile>raw_data.css</cssSourceFile>
......@@ -658,6 +659,10 @@
<jsSourceFiles>
<jsSourceFile>lib/jquery_plugins/jquery.dataTables.min.js</jsSourceFile>
<jsSourceFile>lib/jquery_plugins/dataTables.responsive.min.js</jsSourceFile>
<jsSourceFile>lib/jquery_plugins/dataTables.buttons.min.js</jsSourceFile>
<jsSourceFile>lib/jquery_plugins/dataTables.sort.min.js</jsSourceFile>
<jsSourceFile>lib/jquery_plugins/buttons.html5.min.js</jsSourceFile>
<jsSourceFile>lib/jquery_plugins/jszip.min.js</jsSourceFile>
</jsSourceFiles>
<!-- Files already provided minified. The suffix will then not be added -->
<jsFinalFile>vendor_expr_comp.${filter.org.bgee.webapp.javascript.version.extension}.js</jsFinalFile>
......@@ -667,6 +672,7 @@
<cssSourceFiles>
<cssSourceFile>lib/jquery_plugins/jquery.dataTables.min.css</cssSourceFile>
<cssSourceFile>lib/jquery_plugins/responsive.dataTables.min.css</cssSourceFile>
<cssSourceFile>lib/jquery_plugins/buttons.dataTables.min.css</cssSourceFile>
</cssSourceFiles>
<!-- Files already provided minified. The suffix will then not be added -->
<cssFinalFile>vendor_expr_comp.${filter.org.bgee.webapp.css.version.extension}.css</cssFinalFile>
......
......@@ -243,10 +243,6 @@ public class CommandGene extends CommandParent {
* and keys correspond to {@code AnatEntity}s
* @param filterRedundantCalls A {@code boolean} defining whether redundant calls
* should be filtered for the grouping and clustering steps.
<<<<<<< HEAD
* @param conditionGraph A {@code ConditionGraph} built from {@code exprCalls}.
=======
>>>>>>> review_rawdata_genestats_fixtests_oncomxnewfile_multispecies
* @return A built {@code GeneResponse}.
*/
private GeneResponse buildGeneResponse(Gene gene, LinkedHashMap<AnatEntity,
......@@ -290,14 +286,9 @@ public class CommandGene extends CommandParent {
/**
* Return the {@code Function} corresponding to the clustering method to used,
* based on the properties {@link BgeeProperties#getGeneScoreClusteringMethod()}
* and {@link BgeeProperties#getGeneScoreClusteringThreshold()}. The {@code Function}
<<<<<<< HEAD
* and {@link BgeeProperties#getGeneScoreClusteringThreshold()}. The {@code Function}
* will trigger a call to {@link ExpressionCall#generateMeanRankScoreClustering(
* List, ClusteringMethod, double)}.
=======
* will trigger a call to {@link ExpressionCall#generateMeanRankScoreClustering(List,
* ClusteringMethod, double)}.
>>>>>>> review_rawdata_genestats_fixtests_oncomxnewfile_multispecies
*
* @return A {@code Function} accepting a {@code List} of {@code ExpressionCall}s
* as input, and returns a {@code Map} corresponding to the clustering as output.
......
package org.bgee.controller;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
......@@ -9,7 +11,9 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bgee.model.Entity;
import org.bgee.model.ServiceFactory;
import org.bgee.model.file.SpeciesDataGroup;
import org.bgee.model.species.Species;
import org.bgee.view.SpeciesDisplay;
import org.bgee.view.ViewFactory;
......@@ -18,8 +22,8 @@ import org.bgee.view.ViewFactory;
* Controller handling requests relative to species.
*
* @author Valentine Rech de Laval
* @version Bgee 14, Mar. 2017
* @since Bgee 13 Nov 2015
* @version Bgee 14, July 2019
* @since Bgee 13, Nov 2015
*/
public class CommandSpecies extends CommandParent {
......@@ -52,27 +56,61 @@ public class CommandSpecies extends CommandParent {
SpeciesDisplay display = this.viewFactory.getSpeciesDisplay();
// Get submitted species ID
Integer speciesId = this.requestParameters.getSpeciesId();
if (speciesId != null) {
final Set<Species> speciesSet = this.serviceFactory.getSpeciesService()
.loadSpeciesByIds(Collections.singleton(speciesId), true);
if (speciesSet.isEmpty()) {
throw log.throwing(new IllegalStateException(
"A SpeciesService did not allow to obtain any Species."));
}
assert speciesSet.size() == 1;
Species sp = speciesSet.iterator().next();
List<SpeciesDataGroup> groups = serviceFactory.getSpeciesDataGroupService().loadAllSpeciesDataGroup();
if (groups.isEmpty()) {
throw log.throwing(new IllegalStateException("A SpeciesDataGroupService did not allow "
+ "to obtain any SpeciesDataGroup."));
}
Set<SpeciesDataGroup> speciesDataGroups = groups.stream()
.filter(g -> g.isSingleSpecies() && g.getMembers().contains(sp))
.collect(Collectors.toSet());
assert speciesDataGroups.size() == 1;
display.displaySpecies(sp, speciesDataGroups.iterator().next());
log.exit(); return;
}
// Get submitted species IDs
Collection<Integer> submittedSpeciesIds = this.requestParameters.getValues(
this.requestParameters.getUrlParametersInstance().getParamSpeciesList());
Collection<Integer> submittedSpeciesIds = this.requestParameters.getSpeciesList();
// Load detected species
Set<Species> species = this.serviceFactory.getSpeciesService().
loadSpeciesByIds(submittedSpeciesIds, true);
if (species.isEmpty()) {
throw log.throwing(new IllegalStateException(
"A SpeciesService did not allow to obtain any Species."));
if (submittedSpeciesIds != null && !submittedSpeciesIds.isEmpty()) {
// Load detected species
Set<Species> species = this.serviceFactory.getSpeciesService().
loadSpeciesByIds(submittedSpeciesIds, true);
if (species.isEmpty()) {
throw log.throwing(new IllegalStateException(
"A SpeciesService did not allow to obtain any Species."));
}
display.sendSpeciesResponse(
species.stream()
//filter species with no data (insertion error in Bgee 13 database)
.filter(s -> !s.getDataTypesByDataSourcesForData().isEmpty())
//order species by ID for consistent rendering
//XXX: should we add ordering attributes to SpeciesService?
.sorted(Comparator.comparing(Entity::getId))
.collect(Collectors.toList())
);
}
display.sendSpeciesResponse(
species.stream()
//filter species with no data (insertion error in Bgee 13 database)
.filter(s -> !s.getDataTypesByDataSourcesForData().isEmpty())
//order species by ID for consistent rendering
//XXX: should we add ordering attributes to SpeciesService?
.sorted(Comparator.comparing(s -> s.getId()))
.collect(Collectors.toList())
);
Set<Species> species = this.serviceFactory.getSpeciesService().loadSpeciesByIds(null, false);
display.displaySpeciesHomePage(species.stream()
.sorted(Comparator.comparing(Species::getPreferredDisplayOrder))
.collect(Collectors.toList()));
log.exit();
}
......
......@@ -126,9 +126,6 @@ public class FrontController extends HttpServlet {
* @param userService A {@link UserService} instance, allowing to create
* {@code User} objects to identify and track users in the webapp.
* If {@code null}, the default constructor of {@code UserService} is used.
* @param geneMatchResultService A {@link GeneMatchResultService} instance, allowing to search
* {@code GeneMatchResult} objects to identify and track users in the webapp.
* If {@code null}, the default constructor of {@code UserService} is used.
* @param serviceFactoryProvider A {@code Supplier} of {@code ServiceFactory}s, allowing
* to obtain a new {@code ServiceFactory} instance
* at each call to the {@code doRequest} method. If {@code null},
......@@ -284,7 +281,8 @@ public class FrontController extends HttpServlet {
controller = new CommandSource(response, requestParameters, this.prop, factory, serviceFactory);
} else if (requestParameters.isASpeciesPageCategory()){
controller = new CommandSpecies(response, requestParameters, this.prop, factory, serviceFactory);
controller = new CommandSpecies(response, requestParameters, this.prop, factory, serviceFactory);
} else if (requestParameters.isASearchPageCategory()) {
controller = new CommandSearch(response, requestParameters, this.prop, factory,
serviceFactory);
......@@ -294,20 +292,25 @@ public class FrontController extends HttpServlet {
} else if (requestParameters.isARPackagePageCategory()) {
controller = new CommandRPackage(response, requestParameters, this.prop, factory,
serviceFactory, this.jobService, user);
} else if (requestParameters.isASparqlPageCategory()) {
controller = new CommandSparql(response, requestParameters, this.prop, factory, serviceFactory);
} else if (requestParameters.isAResourcesPageCategory()) {
controller = new CommandResources(response, requestParameters, this.prop, factory, serviceFactory);
}else if (requestParameters.isAStatsPageCategory()) {
} else if (requestParameters.isAStatsPageCategory()) {
//no specific controllers for this for now.
//We simply respond with a 'success no content' so that the client get no errors,
//and so that we get correct information stored in our Apache logs.
//TODO: In the future, this should call our Google Monitoring implementation
factory.getGeneralDisplay().respondSuccessNoContent();
setCookie = false;
} else if (requestParameters.isAAnatSimilarityPageCategory()) {
controller = new CommandAnatomicalSimilarity(
response, requestParameters, this.prop, factory, serviceFactory);
} else {
throw log.throwing(new PageNotFoundException("Request not recognized."));
}
......
......@@ -76,7 +76,7 @@ public class URLParameters {
* of one parameter. Contains: "\r\n", "\r", "\n", ",".
* @see URLParameters.Parameter#allowsSeparatedValues().
*/
protected static final List<String> DEFAULT_SEPARATORS = Arrays.asList("\r\n", "\r", "\n", ",");
protected static final List<String> DEFAULT_SEPARATORS = Arrays.asList("\r\n", "\r", "\n", ","," ");
/**
* A {@code boolean} that contains the default value for {@link URLParameters.Parameter#isStorable}
......
......@@ -2,6 +2,7 @@ package org.bgee.view;
import java.util.List;
import org.bgee.model.file.SpeciesDataGroup;
import org.bgee.model.species.Species;
/**
......@@ -9,14 +10,24 @@ import org.bgee.model.species.Species;
* has to implements
*
* @author Valentine Rech de Laval
* @version Bgee 13 Sep. 2016
* @since Bgee 13 Nov. 15
* @version Bgee 14, July 2019
* @since Bgee 13, Nov. 15
*/
public interface SpeciesDisplay {
/**
* Display the species page.
* Display the species home page.
*/
public void displaySpeciesHomePage(List<Species> speciesList);
/**
* Display the page for several species.
*/
public void sendSpeciesResponse(List<Species> species);
/**
* Display the one species page.
*/
public void displaySpecies(Species species, SpeciesDataGroup speciesDataGroup);
}
\ No newline at end of file
......@@ -15,6 +15,7 @@ import org.apache.logging.log4j.Logger;
import org.bgee.controller.BgeeProperties;
import org.bgee.controller.RequestParameters;
import org.bgee.model.expressiondata.baseelements.DataType;
import org.bgee.model.file.SpeciesDataGroup;
import org.bgee.model.species.Species;
import org.bgee.view.SpeciesDisplay;
import org.bgee.view.ViewFactory;
......@@ -29,8 +30,9 @@ import org.supercsv.io.ICsvMapWriter;
* Implementation of {@code SpeciesDisplay} for CSV/TSV rendering.
*
* @author Frederic Bastian
* @version Bgee 13, Sep. 2016
* @since Bgee 13 Sep. 2016
* @author Valentine Rech de Laval
* @version Bgee 14, July 2019
* @since Bgee 13, Sep. 2016
*/
public class CsvSpeciesDisplay extends CsvParentDisplay implements SpeciesDisplay {
private final static Logger log = LogManager.getLogger(CsvSpeciesDisplay.class.getName());
......@@ -41,6 +43,11 @@ public class CsvSpeciesDisplay extends CsvParentDisplay implements SpeciesDispla
super(response, requestParameters, prop, factory, delimiter);
}
@Override
public void displaySpeciesHomePage(List<Species> speciesList) {
throw log.throwing(new UnsupportedOperationException("Not available for CSV display"));
}
@Override
public void sendSpeciesResponse(List<Species> species) {
log.entry(species);
......@@ -102,4 +109,9 @@ public class CsvSpeciesDisplay extends CsvParentDisplay implements SpeciesDispla
log.exit();
}
@Override
public void displaySpecies(Species species, SpeciesDataGroup speciesDataGroup) {
throw log.throwing(new UnsupportedOperationException("Not available for CSV display"));
}
}
package org.bgee.view.html;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
......@@ -70,15 +73,15 @@ public class HtmlAboutDisplay extends HtmlParentDisplay implements AboutDisplay
title += "release " + version + " ";
}
title += "about page";
this.startDisplay(title);
this.startDisplay(title, "AboutPage");
this.writeln("<h1>About</h1>");
this.writeln("<h1 property='schema:name'>About</h1>");
this.writeln("<div class='row'>");
this.writeln("<div class='" + CENTERED_ELEMENT_CLASS + "'>");
this.writeln("<h2>What is Bgee?</h2>");
this.writeln("<h2 property='schema:description'>What is Bgee?</h2>");
this.writeln("<p>Bgee is a database to retrieve and compare gene expression patterns "
+ "in multiple animal species, produced from multiple data types "
......@@ -121,32 +124,35 @@ public class HtmlAboutDisplay extends HtmlParentDisplay implements AboutDisplay
this.writeln("<h2>How to cite us?</h2>");
this.writeln("<ul>");
this.writeln("<li>For the use of Bgee: "
+ "<br>Bastian FB, Parmentier G, Roux J, Moretti S, Laudet V, Robinson-Rechavi M."
+ "<br>Bgee: Integrating and Comparing Heterogeneous Transcriptome Data Among Species."
+ "<br><em>in</em> DILS: Data Integration in Life Sciences. "
+ "<strong>Lecture Notes in Computer Science</strong>. "
this.writeln("<li typeof='schema:ScholarlyArticle'>For the use of Bgee: "
+ "<br>" + this.getAuthors(Arrays.asList("Bastian FB", "Parmentier G", "Roux J",
"Moretti S", "Laudet V", "Robinson-Rechavi M"))
+ "<br>" + this.getTitle("Bgee: Integrating and Comparing Heterogeneous Transcriptome Data Among Species")
+ "<br><em>in</em> " + this.getPeriodical("DILS: Data Integration in Life Sciences")
+ " <strong>Lecture Notes in Computer Science</strong>. "
+ "5109:124-131. [<a href='http://www.springerlink.com/content/92q428161616w8r5/' "
+ "title='Bgee paper in LNCS' target='_blank'>url</a>] "
+ "<a href='ftp://ftp.bgee.org/general/citation01.ris'>RIS</a></li>");
this.writeln("<li>For UBERON: "
+ "<br>Haendel MA, Balhoff JP, Bastian FB, Blackburn DC, Blake JA, Bradford Y, "
+ "Comte A, Dahdul WM, Dececchi TA, Druzinsky RE, Hayamizu TF, Ibrahim N, Lewis SE, "
+ "Mabee PM, Niknejad A, Robinson-Rechavi M, Sereno PC, Mungall CJ."
+ "<br>Unification of multi-species vertebrate anatomy ontologies for comparative biology in Uberon."
+ "<br><em>in</em> J Biomed Semantics (2014): 5:21. "
+ "title='Bgee paper in LNCS' target='_blank' property='schema:url'>url</a>] "
+ "<a href='ftp://ftp.bgee.org/general/citation01.ris' property='schema:sameAs'>RIS</a></li>");
this.writeln("<li typeof='schema:ScholarlyArticle'>For UBERON: "
+ "<br>" + this.getAuthors(Arrays.asList("Haendel MA", "Balhoff JP", "Bastian FB",
"Blackburn DC", "Blake JA", "Bradford Y", "Comte A", "Dahdul WM", "Dececchi TA",
"Druzinsky RE", "Hayamizu TF", "Ibrahim N", "Lewis SE", "Mabee PM", "Niknejad A",
"Robinson-Rechavi M", "Sereno PC", "Mungall CJ"))
+ "<br>" + this.getTitle("Unification of multi-species vertebrate anatomy ontologies for comparative biology in Uberon")
+ "<br><em>in</em> " + this.getPeriodical("J Biomed Semantics") + " (2014): 5:21. "
+ "[<a target='_blank' href='https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4089931/' "
+ "title='Unification of multi-species vertebrate anatomy ontologies for comparative biology in Uberon'>url</a>] "
+ "<a href='ftp://ftp.bgee.org/general/citation04.ris'>RIS</a></li>");
this.writeln("<li>For the use of the BgeeDB R package: "
+ "<br>Komljenovic A, Roux J, Robinson-Rechavi M and Bastian F."
+ "<br>BgeeDB, an R package for retrieval of curated expression datasets and "
+ "for gene list enrichment tests."
+ "<br><em>in</em> F1000Research. "
this.writeln("<li typeof='schema:ScholarlyArticle'>For the use of the BgeeDB R package: "
+ "<br>" + this.getAuthors(Arrays.asList("Komljenovic A", "Roux J", "Wollbrett J",
"Robinson-Rechavi M", "Bastian F"))
+ "<br>" + this.getTitle("BgeeDB, an R package for retrieval of curated expression datasets and "
+ "for gene list enrichment tests")
+ "<br><em>in</em> " + this.getPeriodical("F1000Research") + " 2018, 5:2748. "
+ "[<a target='_blank' href='https://f1000research.com/articles/5-2748/v2' "
+ "title='BgeeDB, an R package for retrieval of curated expression datasets and "
+ "for gene list enrichment tests'>url</a>] "
+ "<a href='ftp://ftp.bgee.org/general/citation05.ris'>RIS</a></li>");
+ "for gene list enrichment tests' property='schema:url'>url</a>] "
+ "<a href='ftp://ftp.bgee.org/general/citation05.ris' property='schema:sameAs'>RIS</a></li>");
this.writeln("</ul>");
this.writeln("<h2>Which license did we choose?</h2>");
......@@ -154,13 +160,13 @@ public class HtmlAboutDisplay extends HtmlParentDisplay implements AboutDisplay
this.writeln("<p>" +
" To the extent possible under law, Bgee team has waived all copyright and related " +
" or neighboring rights to Bgee project. This work is published under the " +
" <a rel='license' href='" + LICENCE_CC0_URL + "' target='_blank'>" +
" <a href='" + LICENCE_CC0_URL + "' target='_blank'>" +
" Creative Commons Zero license (CC0)</a> from Switzerland. " +
" Although CC0 doesn’t legally require users of the data to cite the source, " +
" if you intend to use data from Bgee, it would be nice to cite us." +
"</p>" +
"<p>" +
" <a rel='license' href='" + LICENCE_CC0_URL + "' target='_blank'>" +
" <a href='" + LICENCE_CC0_URL + "' target='_blank'>" +
" <img src='" + this.prop.getBgeeRootDirectory() +
this.prop.getImagesRootDirectory() + "cc-zero-large.png' alt='CC0' />" +
" </a>" +
......@@ -193,6 +199,32 @@ public class HtmlAboutDisplay extends HtmlParentDisplay implements AboutDisplay
log.exit();
}
private String getTitle(String title) {
log.entry(title);
return log.exit("<span property='schema:headline'>" + title + "</span>.");
}
private String getAuthors(List<String> names) {
log.entry(names);
return log.exit(names.stream().map(this::getAuthor).collect(Collectors.joining(", ", "", ".")));
}
private String getAuthor(String name) {
log.entry(name);
return log.exit(
"<span property='schema:author' typeof='schema:Person'>" +
" <span property='schema:name'>" + name + "</span>" +
"</span>");
}
private String getPeriodical(String journalName) {
log.entry(journalName);
return log.exit(
"<span property='schema:isPartOf' typeof='schema:Periodical'>" +
" <span property='schema:name'>" + journalName + "</span>" +
"</span>.");
}
@Override
protected void includeCss() {
log.entry();
......
......@@ -26,7 +26,7 @@ import java.util.stream.Collectors;
* This class is the HTML implementation of the {@code AnatomicalSimilarityDisplay}.
*
* @author Valentine Rech de Laval
* @version Bgee 14, May 2019
* @version Bgee 14, July 2019
* @since Bgee 14, May 2019
*/
public class HtmlAnatomicalSimilarityDisplay extends HtmlParentDisplay
......@@ -80,6 +80,8 @@ public class HtmlAnatomicalSimilarityDisplay extends HtmlParentDisplay
this.startDisplay("Anatomical homology");
this.addSchemaMarkups();
this.writeln("<h1>Anatomical homology</h1>");
this.writeln("<div id='bgee_introduction'>");
......@@ -117,7 +119,7 @@ public class HtmlAnatomicalSimilarityDisplay extends HtmlParentDisplay
" value='" + sp.getId() + "' " +
(userSpeciesIds!= null && userSpeciesIds.contains(sp.getId())
? "checked" : "") +
" /> " + htmlEntities(sp.getScientificName()) +
" /> <em>" + htmlEntities(sp.getScientificName()) + "</em>"+
" </label>" +
" </div>")
.collect(Collectors.joining());
......@@ -290,7 +292,8 @@ public class HtmlAnatomicalSimilarityDisplay extends HtmlParentDisplay
.flatMap(Set::stream)
.distinct()
.filter(sp -> result.getRequestedSpecies().contains(sp))
.map(species -> htmlEntities(species.getScientificName()))
.map(species -> "<a href='"+getSpeciesPageUrl(species.getId())+"'><em>"
+ htmlEntities(species.getScientificName()) + "</em></a>")
.sorted()
.collect(Collectors.joining(" - ")));
row.append(" </td>");
......@@ -299,6 +302,36 @@ public class HtmlAnatomicalSimilarityDisplay extends HtmlParentDisplay
return log.exit(row.toString());
}
/**
* Add schema.org markups to the page.
*/
private void addSchemaMarkups() {
log.entry();
RequestParameters url = this.getNewRequestParameters();
url.setPage(RequestParameters.PAGE_ANAT_SIM);
this.writeln("<script type='application/ld+json'>");
this.writeln("{" +
" \"@context\": \"https://schema.org\"," +
" \"@type\": \"WebApplication\"," +
" \"@id\": \"" + url.getRequestURL() + "\"," +
" \"name\": \"Anatomical homology\"," +
" \"url\": \"" + url.getRequestURL() + "\"," +
" \"description\": \"Retrieve anatomical homologies from a list of species and a list of Uberon IDs\"," +
" \"offers\": {" +
" \"@type\": \"Offer\"," +
" \"price\": \"0.00\"," +
" \"priceCurrency\": \"CHF\"" +
" }, " +
" \"applicationCategory\": \"https://www.wikidata.org/wiki/Q15544757\"" + // science software
"}");
this.writeln("</script>");
log.exit();
}
@Override
protected void includeCss() {
log.entry();
......
......@@ -44,14 +44,14 @@ public class HtmlCollaborationDisplay extends HtmlParentDisplay implements Colla
public void displayCollaborationPage() {
log.entry();
this.startDisplay("Bgee collaborations");
this.startDisplay("Bgee collaborations", "WebPage");
this.writeln("<h1>Bgee collaborations</h1>");
this.writeln("<h1 property='schema:name'>Bgee collaborations</h1>");
this.writeln("<div class='row'>");
this.writeln("<div class='" + CENTERED_ELEMENT_CLASS + "'>");
this.writeln("<p>This page provides current collaborations of the Bgee project" +
this.writeln("<p property='schema:description'>This page provides current collaborations of the Bgee project" +
" (in alphabetical order).</p>");
......
......@@ -20,7 +20,7 @@ import org.bgee.controller.RequestParameters;
* @author Valentine Rech de Laval
* @author Julien Wollbrett
* @see HtmlDocumentationDisplay
* @version Bgee 14, Jan. 2019
* @version Bgee 14, July 2019
* @since Bgee 13, May 2015
*/
public class HtmlDocumentationCallFile extends HtmlDocumentationDownloadFile {
......@@ -1739,12 +1739,12 @@ public class HtmlDocumentationCallFile extends HtmlDocumentationDownloadFile {
protected void writeDocumentation() {
log.entry();
this.writeln("<h1>Expression call download file documentation</h1>");
this.writeln("<h1 property='schema:name'>Expression call download file documentation</h1>");
RequestParameters urlDownloadGenerator = this.getNewRequestParameters();
urlDownloadGenerator.setPage(RequestParameters.PAGE_DOWNLOAD);
urlDownloadGenerator.setAction(RequestParameters.ACTION_DOWLOAD_CALL_FILES);
this.writeln("<div id='bgee_introduction'><p>Bgee provides calls of baseline "
this.writeln("<div id='bgee_introduction' property='schema:description'><p>Bgee provides calls of baseline "
+ "presence/absence of expression, and of differential over-/under-expression, "
+ "either for single species, or compared between species (orthologous genes "
+ "in homologous organs). This documentation describes the format of these "
......@@ -1977,16 +1977,7 @@ public class HtmlDocumentationCallFile extends HtmlDocumentationDownloadFile {
+ "that, in the midbrain at adult stage, gene A and B are both expressed, "
+ "while gene C is not, thanks to call propagation.</p>");
this.writeln("<p>It is possible to select two different combinations of <code>condition parameters</code>:</p>"
+ "<ul class='doc_content'>"
+ "<li><span class='list_element_title'>anatomical entities only (by default) </span> "
+ "files contain one expression call for each unique pair of gene and anatomical entity."
+ "If more than one developmental stage map this unique pair, the resulting expression "
+ "call correspond to summarized information coming from all developmental stages. "
+ "</li>"
+ "<li><span class='list_element_title'>anatomical entities and developmental stages</span> "
+ "files contain one expression call for each unique gene, anatomical entity and developmental stage. "
+ "</li>"
+ "</ul>");
+ COND_PARAM_DESC_LIST);
this.writeln("<p>Presence/absence calls are then filtered and presented differently "
+ "depending on whether a <code>simple file</code>, "
+ "or an <code>advanced file</code> is used. Notably: <code>simple files</code> "
......
......@@ -64,9 +64,10 @@ public class HtmlDocumentationDataSets extends HtmlDocumentationDownloadFile {
RequestParameters urlTopAnat = this.getNewRequestParameters();
urlTopAnat.setPage(RequestParameters.PAGE_TOP_ANAT);
this.writeln("<h1>GTEx data into Bgee</h1>");
this.writeln("<h1 property='schema:name'>GTEx data into Bgee</h1>");
this.writeln("<div id='bgee_introduction'><p>In addition to the continuous growth of transcriptomics datasets, "
this.writeln("<div id='bgee_introduction' property='schema:description'>"
+ "<p>In addition to the continuous growth of transcriptomics datasets, "
+ "some specific projects produce large amounts of data, generated and accessible "
+ "in a consistent manner, as, notably, "
+ "the <a href='https://www.gtexportal.org/home/' title='GTEx portal' target='_blank'>" +
......
......@@ -287,7 +287,7 @@ public class HtmlDocumentationDisplay extends HtmlParentDisplay implements Docum
public void displayCallDownloadFileDocumentation() {
log.entry();
this.startDisplay("Expression call download file documentation");
this.startDisplay("Expression call download file documentation", "WebPage");
this.writeln("<div class='row'>");
this.writeln("<div class='" + CENTERED_ELEMENT_CLASS + "'>");
......@@ -305,6 +305,7 @@ public class HtmlDocumentationDisplay extends HtmlParentDisplay implements Docum
public void displayRefExprDownloadFileDocumentation() {
log.entry();
// TODO add schema.org property "WebPage" when the documentation will be finished
this.startDisplay(PROCESSED_EXPR_VALUES_PAGE_NAME + " download file documentation");
this.writeln("<div class='row'>");
......@@ -324,7 +325,7 @@ public class HtmlDocumentationDisplay extends HtmlParentDisplay implements Docum
public void displayTopAnatDocumentation() {
log.entry();
this.startDisplay("TopAnat documentation");
this.startDisplay("TopAnat documentation", "WebPage");
this.writeln("<div class='row'>");
this.writeln("<div class='" + CENTERED_ELEMENT_CLASS + "'>");
......@@ -343,7 +344,7 @@ public class HtmlDocumentationDisplay extends HtmlParentDisplay implements Docum
public void displayDataSets() {
log.entry();
this.startDisplay("Data sets into Bgee");
this.startDisplay("Data sets into Bgee", "WebPage");
this.writeln("<div class='row'>");
this.writeln("<div class='" + CENTERED_ELEMENT_CLASS + "'>");
......@@ -362,7 +363,7 @@ public class HtmlDocumentationDisplay extends HtmlParentDisplay implements Docum
public void displayFaq() {
log.entry();
this.startDisplay("Bgee FAQ");
this.startDisplay("Bgee FAQ", "FAQPage");
this.writeln("<div class='row'>");
this.writeln("<div class='" + CENTERED_ELEMENT_CLASS + "'>");
......
......@@ -84,6 +84,8 @@ public class HtmlDocumentationRefExprFile extends HtmlDocumentationDownloadFile
*
* @see HtmlDocumentationDisplay#displayCallDownloadFileDocumentation()
*/
// TODO continue to write that documentation and then add schema.org properties.
// We don't want to index not finished pages
protected void writeDocumentation() {
log.entry();
......
......@@ -55,11 +55,11 @@ public class HtmlDocumentationTopAnat extends HtmlDocumentationDownloadFile {
protected void writeDocumentation() {
log.entry();
this.writeln("<h1>TopAnat documentation</h1>");
this.writeln("<h1 property='schema:name'>TopAnat documentation</h1>");
// Introduction
this.writeln("<p>TopAnat is a tool to identify and visualize enriched anatomical terms, "
+ "from the expression patterns of a list of genes.</p>");
this.writeln("<p property='schema:description'>TopAnat is a tool to identify and visualize "
+ "enriched anatomical terms, from the expression patterns of a list of genes.</p>");
this.writeln("<p>It allows to discover where genes from a set are preferentially expressed, "
+ "as compared to a background, represented by default by all expression data in Bgee "
+ "for the requested species. It is is similar to a Gene Ontology enrichment test, "
......
......@@ -21,6 +21,10 @@ import org.bgee.model.species.Species;
import org.bgee.view.DownloadDisplay;
import org.bgee.view.JsonHelper;
import static org.bgee.model.file.DownloadFile.CategoryEnum.AFFY_DATA;
import static org.bgee.model.file.DownloadFile.CategoryEnum.EXPR_CALLS_COMPLETE;
import static org.bgee.model.file.DownloadFile.CategoryEnum.RNASEQ_DATA;
/**
* This class displays the page having the category "download", i.e. with the parameter
* page=download for the HTML view.
......@@ -28,7 +32,7 @@ import org.bgee.view.JsonHelper;
* @author Mathieu Seppey
* @author Valentine Rech de Laval
* @author Philippe Moret
* @version Bgee 14, Apr. 2019
* @version Bgee 14, July 2019
* @since Bgee 13, July 2014
*/
public class HtmlDownloadDisplay extends HtmlParentDisplay implements DownloadDisplay {
......@@ -76,18 +80,20 @@ public class HtmlDownloadDisplay extends HtmlParentDisplay implements DownloadDi
this.startDisplay("Bgee gene expression call download page");
this.writeln(this.getExprCallSchemaMarkups(groups));
this.writeln(this.getMoreResultDivs());
this.writeln(getDataGroupScriptTag(groups));
this.writeln(getKeywordScriptTag(keywords, groups, DownloadPageType.EXPR_CALLS));
this.writeln("<div id='expr_calls'>");
this.writeln("<h1>");
this.writeln("<h1 property='schema:name'>");
this.writeln("<img src='" + this.prop.getBgeeRootDirectory() + this.prop.getLogoImagesRootDirectory() + "expr_calls_logo.png' " +
"alt='" + GENE_EXPR_CALLS_PAGE_NAME + " logo'/>" + GENE_EXPR_CALLS_PAGE_NAME);
this.writeln("</h1>");
// Introduction
this.writeln("<div id='bgee_introduction'>");
this.writeln("<div id='bgee_introduction' property='schema:description'>");
this.writeln(this.getIntroduction(DownloadPageType.EXPR_CALLS));
this.writeln("</div>");
......@@ -113,12 +119,65 @@ public class HtmlDownloadDisplay extends HtmlParentDisplay implements DownloadDi
log.exit();
}
private String getExprCallSchemaMarkups(List<SpeciesDataGroup> groups) {
log.entry(groups);
List<String> datasets = groups.stream()
.filter(SpeciesDataGroup::isSingleSpecies)
.map(sdg -> {
Integer spId = sdg.getMembers().get(0).getId();
return "{" +
" \"@type\": \"Dataset\"," +
" \"@id\": \"" + this.getDatasetSchemaId(spId, EXPR_CALLS_COMPLETE) + "\"," +
" \"name\": \"" + this.getDatasetSchemaName(spId, EXPR_CALLS_COMPLETE) + "\"," +
" \"description\": \"" + this.getDatasetSchemaDescription(spId, EXPR_CALLS_COMPLETE) + "\"," +
" \"license\": \"" + LICENCE_CC0_URL + "\"," +
" \"sameAs\": \"" + this.getSpeciesPageUrl(spId) + "\"" +
"}";
}
)
.collect(Collectors.toList());
return log.exit(getSchemaMarkupGraph(datasets));
}
private String getProcValuesSchemaMarkups(List<SpeciesDataGroup> groups) {
log.entry(groups);
List<String> datasets = groups.stream()
.filter(SpeciesDataGroup::isSingleSpecies)
.map(sdg -> {
Integer spId = sdg.getMembers().get(0).getId();
return "{" +
" \"@type\": \"Dataset\"," +
" \"@id\": \"" + this.getDatasetSchemaId(spId, RNASEQ_DATA) + "\"," +
" \"name\": \"" + this.getDatasetSchemaName(spId, RNASEQ_DATA) + "\"," +
" \"description\": \"" + this.getDatasetSchemaDescription(spId, RNASEQ_DATA) + "\"," +
" \"license\": \"" + LICENCE_CC0_URL + "\"," +
" \"sameAs\": \"" + this.getSpeciesPageUrl(spId) + "\"" +
"}," +
"{" +
" \"@type\": \"Dataset\"," +
" \"@id\": \"" + this.getDatasetSchemaId(spId, AFFY_DATA) + "\"," +
" \"name\": \"" + this.getDatasetSchemaName(spId, AFFY_DATA) + "\"," +
" \"description\": \"" + this.getDatasetSchemaDescription(spId, AFFY_DATA) + "\"," +
" \"license\": \"" + LICENCE_CC0_URL + "\"," +
" \"sameAs\": \"" + this.getSpeciesPageUrl(spId) + "\"" +
"}";
}
)
.collect(Collectors.toList());
return log.exit(getSchemaMarkupGraph(datasets));
}
@Override
public void displayProcessedExpressionValuesDownloadPage(List<SpeciesDataGroup> groups,
Map<Integer, Set<String>> keywords) {
log.entry(groups, keywords);
this.startDisplay("Bgee " + PROCESSED_EXPR_VALUES_PAGE_NAME.toLowerCase() + " download page");
this.writeln(getProcValuesSchemaMarkups(groups));
this.writeln(getDataGroupScriptTag(groups));
this.writeln(getKeywordScriptTag(keywords, groups, DownloadPageType.PROC_EXPR_VALUES));
this.writeln(this.getExprValuesDirectoryScriptTag(groups));
......@@ -127,14 +186,13 @@ public class HtmlDownloadDisplay extends HtmlParentDisplay implements DownloadDi
this.writeln("<div id='proc_values'>");
this.writeln("<h1>");
this.writeln("<h1 property='schema:name'>");
this.writeln("<img src='" + this.prop.getBgeeRootDirectory() + this.prop.getLogoImagesRootDirectory() + "proc_values_logo.png'" +
"' alt='" + PROCESSED_EXPR_VALUES_PAGE_NAME + " logo'/>" +
PROCESSED_EXPR_VALUES_PAGE_NAME);
" alt='" + PROCESSED_EXPR_VALUES_PAGE_NAME + " logo'/>" + PROCESSED_EXPR_VALUES_PAGE_NAME);
this.writeln("</h1>");
// Introduction
this.writeln("<div id='bgee_introduction'>");