Skip to content

Commit

Permalink
Google Analitics and UI changes (#420)
Browse files Browse the repository at this point in the history
* Hotfix: removing duplicate

* Solving more Issues (#418)

* Added category to full text search

* Fixed models compare

* Show fixed parameter on execution

* Added link on sample resources

* Added GA and small fixes (#419)

* handle 404

* Loading inputs from firebase instead of model catalog

* Allow removing fixed values on setups

* Added google analytics

* New remote sensing page
  • Loading branch information
hvarg authored Aug 6, 2020
1 parent c4ecfdd commit 8d02ff4
Show file tree
Hide file tree
Showing 26 changed files with 457 additions and 158 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
"marked": "^0.7.0",
"moment": "^2.24.0",
"multiselect-combo-box": "^2.0.2",
"prop-types": "^15.7.2",
"pwa-helpers": "^0.9.0",
"react": "^16.13.1",
"react-ga": "^3.1.2",
"redux": "^4.0.0",
"redux-thunk": "^2.3.0",
"reselect": "^4.0.0",
Expand Down
4 changes: 4 additions & 0 deletions src/app/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { DefaultApi } from '@mintproject/modelcatalog_client';
import { dexplorerSelectDataset, dexplorerSelectDatasetArea } from 'screens/datasets/ui-actions';
import { selectEmulatorModel } from 'screens/emulators/actions';

import ReactGA from 'react-ga';

export const BASE_HREF = document.getElementsByTagName("base")[0].href.replace(/^http(s)?:\/\/.*?\//, "/");

export const UPDATE_PAGE = 'UPDATE_PAGE';
Expand Down Expand Up @@ -97,6 +99,7 @@ export const fetchUser: ActionCreator<UserThunkResult> = () => (dispatch) => {
//console.log("Subscribing to user authentication updates");
auth.onAuthStateChanged(user => {
if (user) {
ReactGA.set({ userId: user.email });
dispatch(fetchUserProfile(user)).then(() => {
// Check the state of the model-catalog access token.
let state: any = store.getState();
Expand Down Expand Up @@ -214,6 +217,7 @@ export const goToRegionPage = (regionid: string, page:string) => {

export const navigate: ActionCreator<ThunkResult> = (path: string) => (dispatch) => {
//console.log(path);
ReactGA.pageview(path);
// Extract the page name from path.
let cpath = path === BASE_HREF ? '/home' : path.slice(BASE_HREF.length);
let regionIndex = cpath.indexOf("/");
Expand Down
4 changes: 4 additions & 0 deletions src/app/mint-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { LitElement, html, property, PropertyValues, customElement, css } from '
import { connect } from 'pwa-helpers/connect-mixin';
import { installRouter } from 'pwa-helpers/router';
import { updateMetadata } from 'pwa-helpers/metadata';
import ReactGA from 'react-ga';

// This element is connected to the Redux store.
import { store, RootState } from './store';
Expand Down Expand Up @@ -482,6 +483,9 @@ export class MintApp extends connect(store)(LitElement) {
}

protected firstUpdated() {
ReactGA.initialize('UA-174574572-1', {
siteSpeedSampleRate: 100
});
installRouter((location) => store.dispatch(navigate(decodeURIComponent(location.pathname))));
store.dispatch(fetchUser());
}
Expand Down
Binary file added src/assets/images/thumbnails/GageLocation.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/videos/data-1050819440-658.mp4
Binary file not shown.
Binary file added src/assets/videos/data-1050883510-17704.mp4
Binary file not shown.
38 changes: 29 additions & 9 deletions src/components/notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,41 @@ export class CustomNotification extends LitElement {
@property({type:String}) public icon: string = "error";
@property({type:String}) public message: string = "Notification text";
@property({type:Number}) public delay : number = 3000;
@property({type:String}) public buttonName: string = "";
private buttonFn : any;

private snackbar: Snackbar;

protected render() {
return html`
<wl-snackbar id="snackbar" fixed backdrop disableFocusTrap hideDelay="${this.delay}">
<wl-icon slot="icon">${this.icon}</wl-icon>
${this.icon ? html`<wl-icon slot="icon">${this.icon}</wl-icon>` : ''}
${this.buttonName && this.buttonFn ? html`
<wl-button @click="${this.buttonFn}" slot="action" flat inverted> ${this.buttonName} </wl-button>
`:''}
<span>${this.message}</span>
</wl-snackbar>`;
}

protected updated () {
if (!this.snackbar) this.snackbar = this.shadowRoot.querySelector<Snackbar>("#snackbar");
}

public show () {
let notification : Snackbar = this.shadowRoot.querySelector<Snackbar>("#snackbar")!;
if(notification) notification.show();
let q = this.snackbar.show();
q.then(() => {
this.buttonName = "";
this.buttonFn = null;
});
return q;
}

public hide () {
let notification : Snackbar = this.shadowRoot.querySelector<Snackbar>("#snackbar")!;
try {
if(notification) notification.hide();
} catch {}
this.icon = "error";
this.message = "Notification text";
this.buttonName = "";
this.buttonFn = null;
return this.snackbar.hide();
}

public error (msg: string) {
Expand All @@ -40,9 +56,13 @@ export class CustomNotification extends LitElement {
this.show();
}

public custom (msg: string, icon: string) {
this.icon = icon;
public custom (msg: string, icon: string, buttonName?: string, buttonFn?: any) {
this.message = msg;
this.icon = icon;
if (buttonName && buttonFn) {
this.buttonFn = buttonFn;
this.buttonName = buttonName;
}
this.show();
}

Expand Down
109 changes: 59 additions & 50 deletions src/screens/datasets/datasets-rs-workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export class DatasetsRemoteSensingWorkflows extends connect(store)(PageViewEleme
}
video {
width: 90%;
margin-bottom: 1em;
}
Expand Down Expand Up @@ -121,44 +120,57 @@ export class DatasetsRemoteSensingWorkflows extends connect(store)(PageViewEleme
<p>
Below are some example results for Ethiopia, using a tool that generates river width and depth for model calibration in ungauged hydrological basins using satellite imagery and machine learning. These “virtual gauges” are generated with a method that uses Sentinel-2 satellite imagery and deep learning. A detailed description of the method is shown at the bottom of this page.
</p>
<a target="_blank" href="http://umnlcc.cs.umn.edu/carto-test/"><wl-title level="4">
<a target="_blank" href="http://umnlcc.cs.umn.edu/river-width-demo-v2/"><wl-title level="4">
Ethiopia River Width Visualization
<wl-icon>open_in_new</wl-icon></wl-title></a>
<p>
Each dot represents a location on the river.
Size and color of the point changes based on the river depth as the slider is changed.
Each point on the map represents a river segment.
Click on the point to visualize the surface area changes of the river segment.
</p>
<div class="img-hover-zoom">
<img src="/images/thumbnails/ethiopia-river-width-visualization.png"></img>
<a target="_blank" href="http://umnlcc.cs.umn.edu/carto-test/">Open visualization <wl-icon>open_in_new</wl-icon></a>
<a target="_blank" href="http://umnlcc.cs.umn.edu/river-width-demo-v2/">Open visualization <wl-icon>open_in_new</wl-icon></a>
</div>
<wl-divider style="margin: 20px 0px;"></wl-divider>
<wl-title level="4">Virtual Gauge Videos</wl-title>
<wl-title level="4">
Virtual Gage Videos
</wl-title>
<video class="hidden" loop controls>
<source src="/videos/data-1050819440-658.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
<p>
This represents river width/depth variation for a single cross section. The background in this animation is SRTM based elevation.
The left panel shows the raw multi-spectral imagery from Sentinel-2, the middle panel shows the land/water mask created by our ML approach, and the right panel shows the land/water mask created using an existing algorithm (for comparison) that uses traditional remote sensing indices to classify land/water, and the bottom panel shows the surface area timeseries.
</p>
<div style="width: 90%; margin: 0px auto;">
<image-gallery .items="${items}"></image-gallery>
<p>
These area timeseries can be used to build relationships between ground observations of streamflow to complement ground observations for periods when they are not available. For example, the video below shows the comparison of surface area of a river segment (blue curve) with streamflow measurements from a nearby gage station (red curve). The high agreement suggests that this segment can be potentially used for model calibration.
</p>
<div style="display: flex; width:100%;">
<img src="/images/thumbnails/GageLocation.png" style="width:50%;"></img>
<video class="hidden" loop controls style="width:50%;">
<source src="/videos/data-1050883510-17704.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
<div style="clear:both"></div>
<wl-divider style="margin: 20px 0px;"></wl-divider>
<wl-title level="4">Method for Generating River Width and Depth for Model Calibration in
Ungauged Hydrological Basins using Satellite Imagery and Machine Learning:</wl-title>
<wl-title level="4">
Methodology for Generating Surface Area Variations for Model Calibration in Ungauged Hydrological Basins using Satellite Imagery and Machine Learning:
</wl-title>
<ul>
<li>Global dataset from Sentinel-2 satellite imagery at 10m resolution from 2016
<li>Training dataset
<ul>
<li>8434 predefined boxes around the globe
<ul><li>1805 in Ethiopia</li></ul>
<li>
~4,000 label image patches taken from different parts of the world.
</li>
<li>351888 Sentinel-2 image patches
<ul><li>~60k cloud free</li></ul>
</li>
<li>2976 labeled image patches taken from different parts of the world
<ul><li>created using visual inspection</li></ul>
<li>
~90,000 unlabeled (and cloud free) images from Ethiopia.
</li>
</ul>
</li>
Expand All @@ -171,7 +183,7 @@ export class DatasetsRemoteSensingWorkflows extends connect(store)(PageViewEleme
<ul>
<li>Autoencoder based unsupervised feature learning using large unlabeled data
<ul>
<li>Uses 9,000 unlabeled image patches to learn features that could
<li>Uses 9,0000 unlabeled image patches to learn features that could
reconstruct a wide variety of image patches</li>
<li>Clustering of 2-D compression of auto-encoder features show
effectiveness in grouping similar image patches</li>
Expand All @@ -189,43 +201,40 @@ export class DatasetsRemoteSensingWorkflows extends connect(store)(PageViewEleme
<li>Semantic segmentation-based classification to incorporate structural/shape constraints</li>
</ul>
</li>
<li>Identification of cross sections along the river segment by automatically identifying the
center line and cross sections at regular intervals on the center line
<ul>
<li>Create multi-temporal maps to create a fraction map
<ul><li>Used to identify the core region of the river segment</li></ul>
</li>
<li>Extract the center line using morphological operations on the core region</li>
<li>Perpendicular cross-sections are calculated automatically at regular intervals
along the center line</li>
<li>Cross sections along with elevation data are used to create river
depth hydrographs (next slide)</li>
</ul>
</li>
<li>Estimating river width/depth hydrograph along the cross-section, merging with
<ul>
<li>SRTM 30m elevation data to convert river width hydrograph to river depth hydrograph
<ul><li>Elevation profile along the cross section is smoothed and approximated to a
triangular river bed.</li></ul>
</li>
<li>Constrained by surface extent to exclude irrelevant minimas in the elevation profile</li>
<li>For a given cross section, river width at any date can be calculated using the
land/water mask on that date</li>
<li>Width variations are then converted to depth variations using the triangular river bed</li>
</ul>
</li>
</ol>
</li>
<li>Geospatial visualizations show river width, depth shown at select locations</li>
<li>Quality of the results is still being evaluated:
<li>
The quality of the ML approach to generate surface area variations is being evaluated, and will be
presented in a peer reviewed publication.
</li>
<li>
Data Specifications and Availability
<ul>
<li>The spatial resolution of the width is 10 meters</li>
<li>The quality of the depth is limited by the resolution (in meters) and
quality (not very good on a global scale) of the Digital Elevation Model (DEM)</li>
<li>
The spatial resolution of the land/water masks is 10m.
The temporal resolution is ~10 days (however, very cloudy images are not considered which impacts the temporal frequency of the land/water masks).
</li>
<li>
The surface area variations of river segments in Ethiopia (from Jan-2016 till May-2020) are available
<a targe="_blank" href="https://data-catalog.mint.isi.edu/datasets/da6b6d47-7672-4e6e-a455-7bbc7e7ceb99">
here in the MINT data catalog
</a>
</li>
</ul>
</li>
</ul>
<wl-title level="4">
Extraction of River Depth using Surface Area Variations and Digital Elevation Data
</wl-title>
<p>
If high quality bathymetric information is available for some river segments, it can be combined with surface area variations to derive changes in river depth over time. For example, videos below demonstrate the concept by combining area/width variations with SRTM elevation data at 30m resolution.
</p>
<div style="width: 90%; margin: 0px auto;">
<image-gallery .items="${items}"></image-gallery>
</div>
` : ''}
</div>`
}
Expand Down
38 changes: 33 additions & 5 deletions src/screens/modeling/pathway/mint-datasets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { customElement, html, property, css } from "lit-element";
import { connect } from "pwa-helpers/connect-mixin";
import { store, RootState } from "../../../app/store";
import datasets, { Dataset, ModelDatasets } from "../../datasets/reducers";
import ReactGA from 'react-ga';

import { DatasetMap, DataEnsembleMap, ModelEnsembleMap, ComparisonFeature, StepUpdateInformation, SubGoal } from "../reducers";
import { SharedStyles } from "../../../styles/shared-styles";
Expand Down Expand Up @@ -123,9 +124,6 @@ export class MintDatasets extends connect(store)(MintPathwayPage) {

let done = (getPathwayDatasetsStatus(this.pathway) == TASK_DONE);

console.log(this.pathway.models);
console.log(this._mcInputs);

// If models have been selected, go over each model
return html `
<p>
Expand Down Expand Up @@ -168,7 +166,32 @@ export class MintDatasets extends connect(store)(MintPathwayPage) {
html`No pre-selected datasets were needed for this model.`
: html`
Expert modeler has selected the following files:
${this._mcInputs[model.id] ? this._mcInputs[model.id] : ''}
<table class="pure-table pure-table-striped">
<thead>
<tr>
<th>Input</th>
<th>Selected File</th>
</tr>
</thead>
<tbody>
${fixed_inputs.map((input) => html`
<tr>
<td>${input.name}</td>
<td>
${input.value && input.value.resources ?
input.value.resources.map((r) =>
html`<a target="_blank" href="${r.url}">${r.name}</a>`)
: ""}
</td>
</tr>
`)}
</tbody>
</table>
<!-- TODO: This is a better way to do it, but theres no way to know if the resources
are in the model catalog:
{this._mcInputs[model.id] ? this._mcInputs[model.id] : ''}
-->
`}
</li>
</ul>
Expand Down Expand Up @@ -436,6 +459,7 @@ export class MintDatasets extends connect(store)(MintPathwayPage) {
<div style="margin-top: 10px; text-align: center;"><wl-progress-spinner></wl-progress-spinner></div>
`:'' }
</div>
<div slot="footer">
<wl-button @click="${this._closeResourceSelectionDialog}" inverted flat>Close</wl-button>
<wl-button @click="${this._submitDatasetResources}" class="submit">Submit</wl-button>
Expand Down Expand Up @@ -546,6 +570,10 @@ export class MintDatasets extends connect(store)(MintPathwayPage) {
}

_loadAndSelectPathwayDatasets() {
ReactGA.event({
category: 'Pathway',
action: 'Dataset continue',
});
let new_datasets = []
this._waiting = true;
Object.keys(this.pathway.models!).map((modelid) => {
Expand Down Expand Up @@ -715,7 +743,7 @@ export class MintDatasets extends connect(store)(MintPathwayPage) {
if (Object.keys(this._models).length > 0) {
Object.values(this._models).forEach((m:Model) => {
let fixed = m.input_files.filter((i) => !!i.value);
if (fixed.length > 0) {
if (false && fixed.length > 0) { //FIXME: not all inputs are in the catalog!
if (!this._mcInputs[m.id]) {
this._mcInputs[m.id] = new ModelCatalogDatasetSpecification();
this._mcInputs[m.id].inline = false;
Expand Down
Loading

0 comments on commit 8d02ff4

Please sign in to comment.