Skip to content

Commit

Permalink
Merge pull request #546 from WildMeOrg/issue_291
Browse files Browse the repository at this point in the history
fix relationship diagram and relationship table display issue
  • Loading branch information
erinz2020 authored May 9, 2024
2 parents 2dbdbfd + df723c4 commit ef3d5cc
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 58 deletions.
18 changes: 12 additions & 6 deletions src/main/java/org/ecocean/MarkedIndividual.java
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ public boolean isDeceased() {
//}
for (int c = 0; c < encounters.size(); c++) {
Encounter temp = (Encounter) encounters.get(c);
if (temp.getLivingStatus().equals("dead")) {
if ((temp.getLivingStatus() != null) && temp.getLivingStatus().equals("dead")) {
return true;
}
}
Expand Down Expand Up @@ -2258,14 +2258,20 @@ public JSONObject uiJson(HttpServletRequest request, boolean includeEncounters)
jobj.put("maxYearsBetweenResightings", getMaxNumYearsBetweenSightings());
// note this does not re-compute thumbnail url (so we can get thumbnails on searchResults in a reasonable time)
jobj.put("thumbnailUrl", this.thumbnailUrl);
jobj.put("livingStatus", this.isDeceased() ? "dead" : "alive");

if(includeEncounters) {
Vector<String> encIDs = new Vector<String>();
for (Encounter enc : this.encounters) {
Vector<String> encIDs = new Vector<String>();
Encounter firstEncounter = null;
Encounter lastEncounter = null;
for (Encounter enc : this.getDateSortedEncounters()) {
encIDs.add(enc.getCatalogNumber());
}
jobj.put("encounterIDs", encIDs.toArray());
if (firstEncounter == null) firstEncounter = enc;
lastEncounter = enc;
}
if (includeEncounters) jobj.put("encounterIDs", encIDs.toArray());
if (firstEncounter != null) jobj.put("firstSightingDate", firstEncounter.getDate());
if (lastEncounter != null) jobj.put("mostRecentSightingDate", lastEncounter.getDate());

return sanitizeJson(request,decorateJson(request, jobj));
}

Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/ecocean/api/Login.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
myShepherd.closeDBTransaction();
}
}
myShepherd.rollbackAndClose();
}

if (success) {
Expand Down
121 changes: 121 additions & 0 deletions src/main/webapp/encounters/relatedIndividuals.jsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<%@ page contentType="application/json; charset=utf-8" language="java" import="org.joda.time.LocalDateTime,
org.joda.time.format.DateTimeFormatter,
org.joda.time.format.ISODateTimeFormat,java.net.*,
org.ecocean.grid.*,org.ecocean.ia.*,java.util.*,
java.io.*,java.util.*, java.io.FileInputStream,

org.datanucleus.api.rest.orgjson.JSONArray,
org.datanucleus.api.rest.orgjson.JSONException,
org.datanucleus.api.rest.orgjson.JSONObject,
org.datanucleus.api.rest.RESTUtils,
org.datanucleus.ExecutionContext,
java.util.Set, java.util.HashSet,
java.lang.reflect.Method,
org.datanucleus.api.jdo.JDOPersistenceManager,
org.ecocean.cache.*,
org.ecocean.social.Relationship,
java.util.zip.GZIPOutputStream,
java.io.File, java.io.FileNotFoundException, org.ecocean.*,org.ecocean.servlet.*,javax.jdo.*, java.lang.StringBuffer, java.util.Vector, java.util.Iterator, java.lang.NumberFormatException"%>
<%!
// Returns a somewhat rest-like JSON object containing the metadata
public JSONObject uiJson(MarkedIndividual indy, HttpServletRequest request) throws JSONException {
JSONObject jobj = new JSONObject();
jobj.put("individualID", indy.getIndividualID());
jobj.put("displayName", indy.getDisplayName(request));
jobj.put("sex", indy.getSex());
jobj.put("nickname", indy.getNickName());
jobj.put("nickname", indy.getNickName());
jobj.put("timeOfBirth", indy.getTimeOfBirth());
jobj.put("timeOfDeath", indy.getTimeofDeath());
jobj.put("dateFirstIdentified", indy.getDateFirstIdentified());
jobj.put("dateTimeLatestSighting", indy.getDateLatestSighting());
jobj.put("genus", request.getParameter("genus"));
jobj.put("specificEpithet", request.getParameter("specificEpithet"));
jobj.put("numberEncounters", indy.getNumEncounters());
JSONArray jArray =new JSONArray();
for (Encounter enc : indy.getEncounterList()) {
JSONObject jobjEnc = new JSONObject();
jobjEnc.put("lifeStage", enc.getLifeStage());
jobjEnc.put("dateInMilliseconds", enc.getDateInMilliseconds());
jobjEnc.put("decimalLatitude", enc.getDecimalLatitude());
jobjEnc.put("decimalLongitude", enc.getDecimalLongitude());
jobjEnc.put("year", enc.getYear());
jobjEnc.put("month", enc.getMonth());
jobjEnc.put("day", enc.getDay());
jArray.put(jobjEnc);
}
jobj.put("encounters",jArray);
return jobj;
}
%>
<%!
void tryCompress(HttpServletRequest req, HttpServletResponse resp, JSONArray jo, boolean useComp) throws IOException, JSONException {
//System.out.println("??? TRY COMPRESS ??");
//String s = scrubJson(req, jo).toString();
String s = jo.toString();
if (!useComp || (s.length() < 3000)) { //kinda guessing on size here, probably doesnt matter
resp.getWriter().write(s);
} else {
resp.setHeader("Content-Encoding", "gzip");
OutputStream o = resp.getOutputStream();
GZIPOutputStream gz = new GZIPOutputStream(o);
gz.write(s.getBytes());
gz.flush();
gz.close();
o.close();
}
}
%>
<%
response.setHeader("Access-Control-Allow-Origin", "*");
String context="context0";
context=ServletUtilities.getContext(request);
Shepherd myShepherd=new Shepherd(context);
myShepherd.setAction("relatedIndividuals.jsp");
MarkedIndividual indiv = myShepherd.getMarkedIndividual(request.getParameter("individualID"));
if (indiv == null) {
response.setStatus(404);
myShepherd.rollbackDBTransaction();
myShepherd.closeDBTransaction();
return;
}
Set<MarkedIndividual> already = new HashSet<MarkedIndividual>();
try {
JSONArray jarr = new JSONArray();
jarr.put(uiJson(indiv, request));
for (Relationship rel : indiv.getAllRelationships(myShepherd)) {
MarkedIndividual other = rel.getMarkedIndividual1();
if (other.getId().equals(indiv.getId())) other = rel.getMarkedIndividual2();
if (already.contains(other)) continue;
already.add(other);
jarr.put(uiJson(other, request));
}
out.println(jarr.toString());
} catch(Exception e){
e.printStackTrace();
}
finally{
myShepherd.rollbackDBTransaction();
myShepherd.closeDBTransaction();
}
%>
85 changes: 45 additions & 40 deletions src/main/webapp/javascript/bubbleDiagram/encounter-calls.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ var makeRelTable = function(items, tableHeadLocation, tableBodyLocation, sortOn)
return "<button type='button' name='button' value='" + d[1] + "' class='btn btn-sm btn-block deleteRelationshipBtn' id='remove" + d[1] + "'>Remove</button><div class='confirmDelete' value='" + d[1] + "'><p>Are you sure you want to delete this relationship?</p><button class='btn btn-sm btn-block yesDelete' type='button' name='button' value='" +d[1]+ "'>Yes</button><button class='btn btn-sm btn-block cancelDelete' type='button' name='button' value='" + d[1] + "'>No</button></div>";
}
if(d.length > 2) {
return "<a href='individuals.jsp?number=" + d[0] + "'>" + d[5] + "</a><br><span>" + dict['nickname'] + " : " + d[1]+ "</span><br><span>" + dict['alternateID'] + ": " + d[2] + "</span><br><span>" + dict['sex'] + ": " + d[3] + "</span><br><span>" + dict['haplotype'] +": " + d[4] + "</span>";
return "<a href='individuals.jsp?number=" + d[0] + "'>" + d[5] + "</a><br><span>" + dict['nickname'] + " : " + (d[1] ?? "")+ "</span><br><span>" + dict['alternateID'] + ": " + (d[2] ?? "") + "</span><br><span>" + dict['sex'] + ": " + (d[3] ?? "") + "</span><br><span>" + dict['haplotype'] +": " + (d[4] ?? "") + "</span>";
}
return d[0].italics() + "-" + d[1];
//}
Expand Down Expand Up @@ -687,48 +687,53 @@ var getRelationshipTableData = function(individualID) {
relationship = {"roles": [markedIndividualRole, relationshipWithRole], "relationshipWith": [whaleID], "type": type, "socialUnit": relatedSocialUnitName, "edit": ["edit", relationshipID], "remove": ["remove", relationshipID]};
relationshipArray.push(relationship);
}
getIndividualData(relationshipArray);
console.log("gonna makeRelTable");
makeRelTable(relationshipArray, "#relationshipHead", "#relationshipBody", "text");
getIndividualData(relationshipArray, function (relationshipTableData) {
console.log("All data has been processed:", JSON.stringify(relationshipTableData));
makeRelTable(relationshipTableData, "#relationshipHead", "#relationshipBody", "text");
});

});
}

var getIndividualData = function(relationshipArray) {
console.log("getIndividualData");
var relationshipTableData = [];
for(var i=0; i < relationshipArray.length; i++) {
d3.json(wildbookGlobals.baseUrl + "/api/org.ecocean.MarkedIndividual/" + relationshipArray[i].relationshipWith[0], function(error, json) {
if(error) {
console.log("error")
}
//console.log("json: "+JSON.stringify(json));
let jsonData = json;
var individualInfo = relationshipArray.filter(function(obj) {
return obj.relationshipWith[0] === jsonData.individualID;
})[0];
console.log(individualInfo.relationshipWith);
individualInfo.relationshipWith[1] = jsonData.nickName;
individualInfo.relationshipWith[2] = jsonData.alternateid;
individualInfo.relationshipWith[3] = jsonData.sex;
individualInfo.relationshipWith[4] = jsonData.localHaplotypeReflection;
individualInfo.relationshipWith[5] = jsonData.displayName;
relationshipTableData.push(individualInfo);

if(relationshipTableData.length == relationshipArray.length) {
for(var j = 0; j < relationshipArray.length; j++) {
if(relationshipArray[j].relationshipWith.length == 1) {
relationshipArray[j].relationshipWith[1] = jsonData.nickName;
relationshipArray[j].relationshipWith[2] = jsonData.alternateid;
relationshipArray[j].relationshipWith[3] = jsonData.sex;
relationshipArray[j].relationshipWith[4] = jsonData.localHaplotypeReflection;
relationshipArray[j].relationshipWith[5] = jsonData.displayName;
}
}

}
});
}
var getIndividualData = function (relationshipArray, onComplete) {
var relationshipTableData = [];
var completedRequests = 0;

for (var i = 0; i < relationshipArray.length; i++) {
d3.json(wildbookGlobals.baseUrl + "/api/org.ecocean.MarkedIndividual/" + relationshipArray[i].relationshipWith[0], function (error, json) {
if (error) {
console.log("Error loading data");
return;
}

let jsonData = json;
var individualInfo = relationshipArray.filter(function (obj) {
return obj.relationshipWith[0] === jsonData.individualID;
})[0];

individualInfo.relationshipWith[1] = jsonData.nickName;
individualInfo.relationshipWith[2] = jsonData.alternateid;
individualInfo.relationshipWith[3] = jsonData.sex;
individualInfo.relationshipWith[4] = jsonData.localHaplotypeReflection;
individualInfo.relationshipWith[5] = jsonData.displayName;

relationshipTableData.push(individualInfo);
completedRequests++;

if (completedRequests === relationshipArray.length) {
for (var j = 0; j < relationshipArray.length; j++) {
if (relationshipArray[j].relationshipWith.length == 1) {
relationshipArray[j].relationshipWith[1] = jsonData.nickName;
relationshipArray[j].relationshipWith[2] = jsonData.alternateid;
relationshipArray[j].relationshipWith[3] = jsonData.sex;
relationshipArray[j].relationshipWith[4] = jsonData.localHaplotypeReflection;
relationshipArray[j].relationshipWith[5] = jsonData.displayName;
}
}
onComplete(relationshipTableData);
}
});
}
}

function whatIsIt(object) {
Expand All @@ -753,4 +758,4 @@ function whatIsIt(object) {
{
return "don't know";
}
}
}
47 changes: 36 additions & 11 deletions src/main/webapp/javascript/relationshipDiagrams/jsonParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class JSONQuerier {
*/
async preFetchData(iId, genus, epithet, callbacks, diagramIds, parsers=[]) {
await this.queryIndividualIDNodeData(iId);
await this.queryIndividualIDRelatedNodeData(iId);
await this.queryIndividualIDRelationshipData(iId);
await this.queryIndividualIDOccurrences(iId);

Expand Down Expand Up @@ -139,6 +140,16 @@ class JSONQuerier {
return this.queryData("nodeData", query, this.storeQueryAsDict);
}

queryIndividualIDRelatedNodeData(individualID) {
let query;
if (!this.localFiles) {
query = wildbookGlobals.baseUrl + "/encounters/relatedIndividuals.jsp?";
if (individualID) query += "individualID=" + individualID;
}
else query = "./MarkedIndividual.json";
return this.queryData("relatedNodeData", query, this.storeQueryAsDict);
}


/**
* Query wrapper for the storage of Relationship data
Expand Down Expand Up @@ -316,7 +327,7 @@ class JSONParser {
*/
processNodeData(iId, isCoOccurrence) {
//Generate a two way mapping of all node relationships
let nodes = this.getNodeSelection();
let nodes = this.getNodeSelection(isCoOccurrence);
let relationships = this.mapRelationships(nodes);
let [graphNodes, groupNum] = this.traverseRelationshipTree(iId, nodes, relationships, isCoOccurrence);

Expand Down Expand Up @@ -613,17 +624,31 @@ class JSONParser {
* Return node data as filtered by selected nodes
* @return {nodeData} [array] - Any node data matching {selectedNodes} ids
*/
getNodeSelection() {
if (this.selectedNodes) {
let nodes = {};
Object.entries(JSONParser.nodeData).forEach(([key, data]) => {
if (this.selectedNodes.has(key)) { //Filter out any keys not in {selectedNodes}
nodes[key] = data;
getNodeSelection(isCoOccurrence) {
if (isCoOccurrence) {
if (this.selectedNodes) {
let nodes = {};
Object.entries(JSONParser.nodeData).forEach(([key, data]) => {
if (this.selectedNodes.has(key)) { //Filter out any keys not in {selectedNodes}
nodes[key] = data;
}
});
return nodes;
}
return JSONParser.nodeData;
}else {
if (this.selectedNodes) {
let nodes = {};
Object.entries(JSONParser.relatedNodeData).forEach(([key, data]) => {
if (this.selectedNodes.has(key)) { //Filter out any keys not in {selectedNodes}
nodes[key] = data;
}
});
return nodes;
}
return JSONParser.relatedNodeData;
}
});
return nodes;
}
return JSONParser.nodeData;

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class SocialGraph extends ForceLayoutAbstract {
* Wrapper function to gather species data from the Wildbook DB and generate a graph
*/
applySocialData() {
this.parser.processJSON((nodes, links) => this.graphSocialData(nodes, links), this.id);
this.parser.processJSON((nodes, links) => this.graphSocialData(nodes, links), this.id, false);
}

/**
Expand Down

0 comments on commit ef3d5cc

Please sign in to comment.