M.App Enterprise Discussions

Discuss topics with other M.App Enterprise Product pioneers and experts to get the most out of it.
Showing results for 
Search instead for 
Do you mean 
Reply
Highlighted
Contributor
Posts: 62
Registered: ‎05-30-2016

Feature Analyzer- selected date between start and end dates

Is it possible to make a date widget wich allows selecting a single date on a chart, where  the selected date will be analyzed against two fields in the dataset?  the filter should be define like selected date(in chart) is later than start_date and earlier than end_date in dataset.

How that behaviour can be achieved?

Regards

Gideon

 

Highlighted
Technical Evangelist
Posts: 818
Registered: ‎11-12-2015

Re: Feature Analyzer- selected date between start and end dates

Hi Gideon,

 

I dont quite understand the inquiry here unfortunately.

There is the ability to set a date range filter in the 'Date' widget, and it could be set in the slider to become a single day filter.

I suspect you are aware of that functionality already and it wont suffice in this case?

 

if so, can you explain further please your idea of the necessary 'filter' perhaps providing an illustration or example?

Highlighted
Contributor
Posts: 62
Registered: ‎05-30-2016

Re: Feature Analyzer- selected date between start and end dates

Let's say I have a dataset of coronavirus events with a field for diagnostic_date and a field for recovery_date if to be optimistic. This is a range in dataset. 

i would like to select a single date in the client and as a result only events which the range in database include the selected date will be displayed, hope it is clear now

Regards

gideon

 

Highlighted
Technical Evangelist
Posts: 26
Registered: ‎04-04-2018

Re: Feature Analyzer- selected date between start and end dates

Hi Gideon,

 

If I understand correctly, you're wanting to create a filter that shows active cases based on a date? E.g. given a start date and an end date, and given a point in time, show all records where that point in time falls between the start and end date?

 

Dave

Highlighted
Contributor
Posts: 62
Registered: ‎05-30-2016

Re: Feature Analyzer- selected date between start and end dates

Hi Dave

yes, exactly

 

Highlighted
Technical Evangelist
Posts: 26
Registered: ‎04-04-2018

Re: Feature Analyzer- selected date between start and end dates

[ Edited ]

Got it. This functionality currently isn't exposed as a built in chart, however, this is possible with the API. You'll need to use a HTML Chart and functional attribute to create your own custom widget. Providing example below but it will need to be modified to suit your needs. I've marked areas to update as "To Update:". Feel free to reach out if you run into any road blocks with this.

 

HTML Chart

  • Instead of a text field, maybe a combo box with a list of predefined dates to choose from.

Functional Attribute - Look for (To Update):

  • Update dimension to select your two date fields
  • Update custom filter function to do a basic - is my selected date in range of the two dates selected in the dimension. 

 

HTML Chart Template (Widget Name: Custom Chart)

<style type="text/css">
	
	.myButton {
		margin-left: 5px;
    	display: table;
        height:24px;
        font-size:1.1vmin;
	    width: 50px;
	}
	
</style>

<div style="font-size:1.4vmin;margin-top:10px;display:block">Current Filter (Only affected by other charts):</div>
<div style="width:100%;display:block;font-size:1.2vmin;margin:10px">
  <div id="cont" style="width:100%;display:block"></div>
</div>

<div style="width:100%;display:block">
  <div style="width:100%;display:inline-block">
    <div style="font-size:1.4vmin;display:block">Beat ID Filter (values range from 1 to 6 or empty to clear):</div>
	<input id="customBeatId" style="font-size:1.5vmin;color:black;width:100%;display:block" value="1"/>
  </div>  
<div>

<div style="margin-left:10px; margin-top:10px;float:right">	
	<div class="smallCommandButton myButton" onclick="applyCustomFilter();">
  	<span>Apply</span>
	</div>
</div>

Functional Attribute Template

if (rowId === 0) {
  
  // only for MAE - ping attributes so they are loaded
  currentRecord["borocode"]; // TO UPDATE: change to lower/start date attribute field name
  currentRecord["boroname"]; // TO UPDATE: change to the upper/end date attribute field name.
  
  let widgetName = "Custom Chart";  
  
  let stage = Analyzer.findStageModel();
  let widget = stage.widgets.find((widget) => {
    return widget.title === widgetName;
  });
  
  // Create something global where we can use/clean up.  
  window.widgetState = window.widgetState || {};
  
  // Build custom dimension, group
  stage.on("afterInitialize.this", () => {
    try {
      
      // Group by...    
      // TO UPDATE: Update to reflect date fields.
      // Also, the dates should be converted to standard javascript date objects and the getTime method used.
      // E.g. return [d[new Date(d["startDate"]).getTime(), d[new Date(d["endDate"]).getTime()]]];
      let dimension = stage.crossfilter.dimension((d) => {         
          return [d["borocode"], 
                  d["boroname"]];
      });

      // You can configure Analyzer to measure by a specific field name. Valid modes are: 
          // - average
          // - advanced
          // - featureCount
          // - none
          // - min
          // - max
          // - difference
          // - median
          // - variance
          // - stddev

      // All of these modes except for none and featureCount require a fieldName to measure by (fieldName param)

      //let group = Analyzer.measureHelper().generateDCObjects(window.customDimension, { mode: "sum", fieldName: "BeatId" });
      // Four each group (I.e. in this example ZONE, I want featureCount to be the measure)
      let group = Analyzer.measureHelper().generateDCObjects(dimension, { mode: "featureCount" });

      // Store this to use later when rendering the chart
      window.widgetState[widgetName] = {
        dimension: dimension,
        group: group,
        filter: (value) => {
          dimension.filter(value);
          stage.updateCharts();
          dc.redrawAll();
        }
      };
      
    }
    catch (err) {
      console.log(err);
    }
    
  });
  
  // This function will be called when either a chart in the system is filtered
  // Or, the chart is reopened from a closed state.
  let renderChart = () => {
        
    let state = window.widgetState[widgetName];
    if (!state) {
		$("#cont").html("Not Loaded");
    }
    else {      
      let helper = window.widgetState[widgetName].group;
      
      // A note on the group function - there are value and label accessor functions. These automatically apply the current measure/formatting to each value
      // Below is an example for displaying numerical data to the console.
      // You would potentially use the results of value accessor as input to some other math.
      let values = helper.group.all();
      values.forEach((groupValue) => {
        let value = helper.valueAccessor(groupValue);
        let label = helper.labelAccessor(value);
        console.log("Key:" + groupValue.key + ", Value: " + value + ", Label: " + label);
      });   
      
      $("#cont").html(JSON.stringify(values));
      
    }
  }
  
  // Clean up  
  stage.on("beforeDispose.this", () => {
    
    try {
      if (window.widgetState[widgetName]) {
		window.widgetState[widgetName].dimension.dispose();
      	window.widgetState[widgetName] = null;
      }    
    }
    catch (err) {
      console.log(err);
    }
    
  });
  
  // This will be called if any other chart in the system has been filtered.
  // This will allow you to get updated values from the group (or somewhere else) 
  // and build up a chart presentation for the user.
  stage.on("filtered.this", () => {
    try {
      renderChart();
    }
    catch(err) {
      console.log(err);
    }
  });
      
  window.applyCustomFilter = () => {
    let value = $("#customBeatId").val();    
    if (value === "")
      value = undefined;
    
    if (!value) {
      // Clear all Filters
      window.widgetState[widgetName].filter();
    }
    else {
      // Convert user selected date to a javascript date object.
      var dateValue = new Date(value).getTime();
      // TO UPDATE: Custom fulter function
      window.widgetState[widgetName].filter((value) => {
        return dateValue >= value[0] && dateValue < value[1];        
      });
    }
  }
  
  widget.on("onMounted.this", (widget) => {

    try {	
      // Render the chart.
      widget.getChart().preventRedraw(true);
      renderChart();      
    }
    catch (err) {
      console.log(err);
    }
    
  });
      
  
}