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

Wildwatch Kenya: fix Student Assignments's data downloads #351

Merged
merged 1 commit into from
Jun 9, 2022
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
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,29 @@ class ClassificationsDownloadButton extends React.Component {
state: 'idle',
};
}

// ----------------------------------------------------------------

componentDidMount() {
this.initialise(this.props);
}

componentWillReceiveProps(nextProps) {
this.initialise(nextProps);
}

initialise(props = this.props) {
}

render() {
const props = this.props;
const state = this.state;

let icon = <DownloadIcon size="small" />;
if (state.state === 'fetching') icon = <LoadingIcon size="small" />;

const onClick = this.onClick.bind(this);

return (
<Button
className="classifications-download-button button"
Expand All @@ -62,29 +62,29 @@ class ClassificationsDownloadButton extends React.Component {

return null;
}

onClick() {
this.initiateFetchData();
}

initiateFetchData() {
const props = this.props;

this.classificationsData = [];
this.safetyCounter = 0;

const fetchArguments = { page: 1 }; //Default page_size is 20
if (props.workflow_id) fetchArguments.workflow_id = props.workflow_id;

this.setState({ state: 'fetching' });
this.doFetchData(fetchArguments);
}

doFetchData(fetchArguments) {
if (!fetchArguments) return;

this.safetyCounter++;

apiClient.type('classifications').get(fetchArguments)
.then((data) => {
//For each Classification resource, add it to our collection.
Expand All @@ -95,20 +95,20 @@ class ClassificationsDownloadButton extends React.Component {
this.classificationsData.push(data)
}
});

//Fetch next set of data
if (data && data.length > 0 && this.safetyCounter < SAFETY_LIMIT) {
fetchArguments.page++;
this.doFetchData(fetchArguments)
} else {
this.finishFetchData();
}

return data;
})
.catch(err => this.handleError(err));
}

finishFetchData() {
Promise.resolve(this.props.transformData(this.classificationsData))
.then((classifications) => {
Expand All @@ -117,13 +117,14 @@ class ClassificationsDownloadButton extends React.Component {
this.setState({ state: 'idle' });
});
}

handleError(err) {
Actions.notification.setNotification({ status: 'critical' , message: 'Something went wrong.' });
console.error(err);
}

saveFile(data) {

saveFile(data = '') {
console.log('+++ data: [[[', data, ']]]', `[${this.props.contentType}]`)
saveAs(blobbifyData(data, this.props.contentType), generateFilename(this.props.fileNameBase));
}
};
Expand All @@ -139,7 +140,7 @@ function csvStr (str) {

function jsonToCsv (json) {
let csv = '';

//Get the header
if (json[0]) {
csv += Object.keys(json[0]).map(csvStr).join(',') + '\n';
Expand All @@ -149,8 +150,8 @@ function jsonToCsv (json) {
json.forEach((row) => {
csv += Object.values(row).map(csvStr).join(',') + '\n'
});
return csv;

return (csv.length > 0) ? csv : 'No data';
}

/*
Expand All @@ -173,4 +174,4 @@ ClassificationsDownloadButton.propTypes = {
workflow_id: PropTypes.string,
};

export default ClassificationsDownloadButton;
export default ClassificationsDownloadButton;
8 changes: 4 additions & 4 deletions src/programs/kenya/wildwatch-kenya.classroom-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,12 @@ function classificationResourceToJson (classifications) {
return data;
}

function combineWithSubjectMetadata (classifications) {
function combineWithSubjectMetadata (classifications = []) {
if (classifications.length === 0) return []

const allSubjectIds = classifications.map(c => c.subject_id).join(',')
const query = mapConfig.database.queries.selectAllSubjects
.replace('{WHERE}', '')
.replace('{WHERE}', allSubjectIds ? ` WHERE subject_id IN (${allSubjectIds})` : '')
.replace('{ORDER}', '')
.replace('{LIMIT}', '');
const url = mapConfig.database.urls.json.replace('{SQLQUERY}', query);
Expand All @@ -109,8 +111,6 @@ function combineWithSubjectMetadata (classifications) {
camera: '',
//subject_id: '' // No, leave this alone
location: '',
month: '',
year: '',
'data.choice': '',
'data.choice_count': '',
'data.total_vote_count': '',
Expand Down
43 changes: 22 additions & 21 deletions src/programs/kenya/wildwatch-kenya.map-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const mapConfig = {
ORDER BY
count DESC
`,

//Get all the details for all the (filtered) results.
'selectForDownload': `
SELECT
Expand Down Expand Up @@ -83,7 +83,7 @@ const mapConfig = {
cam.id = sbjagg.camera
{WHERE}
`,

//Get all the minimum Subject details for all the (filtered) results. Has Order By and Limit clauses.
'selectForAssignment': `
SELECT
Expand All @@ -108,19 +108,20 @@ const mapConfig = {
cam.id = sbjagg.camera
{WHERE} {ORDER} {LIMIT}
`,

//Get all subjects, with camera data.
'selectAllSubjects': `
SELECT
sbj.subject_id, sbj.camera, cam.longitude, sbj.date, sbj.month, sbj.year, sbj.location, cam.latitude, cam.season
sbj.subject_id, sbj.camera, cam.longitude, sbj.location, cam.latitude, cam.season
FROM
subjects AS sbj
LEFT JOIN
cameras AS cam
ON
sbj.camera = cam.id
{WHERE} {ORDER} {LIMIT}
`,

//Select all the photos from a specific camera. Similar to selectForDownload
'selectCameraData': `
SELECT
Expand All @@ -145,15 +146,15 @@ const mapConfig = {
cam.id = sbjagg.camera
{WHERE}
`,

//Select a single camera, mostly for the camera's metadata.
'selectCameraMetadata': 'SELECT * FROM cameras {WHERE}',
}
},

//The map visualisation bits. Compatible with Leaflet tech.
'map': {
'centre': { //Some arbitrary point in Kenya.
'centre': { //Some arbitrary point in Kenya.
'latitude': 1.5,
'longitude': 40,
'zoom': 7,
Expand Down Expand Up @@ -464,7 +465,7 @@ const mapConfig = {
},
}
},

//Misc stuff related to the program
'program': {
dataGuideURL: '/#/wildwatch-kenya-lab/explorers/data-guide/',
Expand All @@ -477,7 +478,7 @@ const mapConfig = {
return Promise.reject(csvData.errors[0].message);
}

return Promise.resolve(null);
return Promise.resolve(null);
}
},
};
Expand All @@ -490,23 +491,23 @@ function transformDownloadData(csvData) {
let output = '';
const header = csvData.data[0].slice();
header.push('consensus_count'); //Append consensus count to the final column of each row.

const headerLookup = {};
header.forEach((item, index) => {
if (item.startsWith('data.answers.howmany.')) headerLookup[item] = index;
});

output = header.map(str => csvStr(str)).join(',') + '\n';

for (let i = 1; i < csvData.data.length; i ++) {
let row = csvData.data[i];

if (row.join().length === 0) continue

let consensusCount = undefined;
let numberForConsensus = 0;
//Which "animal was seen X times in this photo" has the highest count?

//Which "animal was seen X times in this photo" has the highest count?
Object.keys(headerLookup).forEach((key) => {
const index = headerLookup[key];
const currentNumber = row[index];
Expand All @@ -517,19 +518,19 @@ function transformDownloadData(csvData) {
if (consensusCount === '21') consensusCount = '21+';
}
});

if (!consensusCount) {
row.push('-')
} else {
row.push(consensusCount)
}

output += row.map(str => csvStr(str)).join(',') + '\n';
}

return output;
}

function csvStr(str) {
return '"' + str.replace(/"/g, '""') + '"';
}
}