Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix relationship diagram and relationship table display issue #546

Merged
merged 7 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading