All Apps and Add-ons

Alternative D3 calendar heat map setup?

Builder

Hi

I want to add the following calendar view http://bl.ocks.org/KathyZ/c2d4694c953419e0509b to my app using D3 libraries. This calendar map needs to be populated with the events' timestamp ( field: _time). I am trying to follow the example presented here: [A simple example using the D3 third-party visualization library ][2] and the custom visualization app, but I have some doubts.

Edit:
I managed to get the calendar view but there is a message that says "Waiting for data.." that I cannot remove. I appreciate your help! Also I am having problem setting the mouse hover behavior. Please feel free to comment. I will update this answer if I fix the problem.

I am rewriting everything just to make more sense.
Please note that I am using Windows OS and I am using Django bindings.
Also, note that there are may be a better way to do this.
First, create a custom template tag. The template tag directory is apps/myappname/django/myappname/templatetags.

Here is the custom template tag. (It is important that the view has a unique name I used the word "calendario" which means calendar in Spanish).

from django import template
from splunkdj.templatetags.tagutils import component_context
register = template.Library()
@register.inclusion_tag('splunkdj:components/component.html', takes_context=True)
def calendario(context, id, *args, **kwargs):       # The template tag
    return component_context(
        context,
        "calendarioview",                           # The custom view's CSS class name
        id,
        "view",
        "myappname/calendarioview",             # Path to the JavaScript class/file for the view
        kwargs
    )

Second, restart Splunk.
Third, create your html page at apps/myappname/django/myappname/template/.
I called the html page calendarioview.html:

{% extends 'splunkdj:base_with_account_bar.html' %}

{% load splunkmvc %}

{% load calendarioview %}

{% block title %}{{your_app_name}}My Calendario{% endblock title %}

{% block content %}
    <h3>Mi calendario</h3>
    {% calendario
        id="chart"
        managerid="mysearch"
    width=900
    height=750
    cellSize=25
    %}
{% endblock content %}

{% block managers %}
    {% searchmanager
        id="mysearch"
        preview=True
        cache=True
        search='index=mod_jobevent earliest="1/1/2015:00:00:00" latest="9/23/2015:00:00:00" | bucket _time span=1day | stats count by _time'
    %}
{% endblock managers %}

Fourth, add the js wrapper. The wrapper is located at apps/myappname/django/myappname/static/myappname/.
*** Remember: The D3 js library must be saved in this directory too ***
calendarioview.js

// calendario view 
define(function(require, exports, module) {
    var _ = require('underscore');
    var mvc = require('splunkjs/mvc');
    var SimpleSplunkView = require('splunkjs/mvc/simplesplunkview');
        require('css!./css_calendarioview.css');
    var d3 = require('myappname/d3');
    var CalendarioView = SimpleSplunkView.extend({
        className: "calendarioview",

        // Change the value of the "data" property
        options: {
            data: "results"
        },

        // Override this method to format your data in a specific way
        formatData: function(data) {
            // Display the data object to the console
            var new_object = new Object();

            // Format each row of results as an HTML list
            _.each(data, function(row, index, list){
                new_object[row[0].slice(0,10)] = row[1];
            });
            return new_object;
        },

        // Override this method to configure your view
        createView: function() {
            return this;
        },

        // Override this method to put the Splunk data into the view
        updateView: function(viz, data) {
            var width = this.settings.get("width");
            var height = this.settings.get("height");
            var cellSize = this.settings.get("cellSize");

            var no_months_in_a_row = Math.floor(width / (cellSize * 7 + 50));
            var shift_up = cellSize * 3;

            var day = d3.time.format("%w"), // day of the week
                day_of_month = d3.time.format("%e"), // day of the month
                day_of_year = d3.time.format("%j"),
                week = d3.time.format("%U"), // week number of the year
                month = d3.time.format("%m"), // month number
                year = d3.time.format("%Y"),
                percent = d3.format(".1%"),
                format = d3.time.format("%Y-%m-%d");    

            var color = d3.scale.quantize()
                .domain([0, 1000])
                .range(d3.range(11).map(function(d) { return "q" + d + "-11"; }));

            var svg = d3.select("#chart").selectAll("svg")
                .data(d3.range(2015, 2016))
            .enter().append("svg")
                .attr("width", width)
                .attr("height", height)
                .attr("class", "RdYlGn")
            .append("g");


            var rect = svg.selectAll(".day")
                .data(function(d) { 
                return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1));
            })
            .enter().append("rect")
                .attr("class", "day")
                .attr("width", cellSize)
                .attr("height", cellSize)
                .attr("x", function(d) {
                    var month_padding = 1.2 * cellSize*7 * ((month(d)-1) % (no_months_in_a_row));
                    return day(d) * cellSize + month_padding; 
                })
                .attr("y", function(d) { 
                    var week_diff = week(d) - week(new Date(year(d), month(d)-1, 1) );
                    var row_level = Math.ceil(month(d) / (no_months_in_a_row));
                    return (week_diff*cellSize) + row_level*cellSize*8 - cellSize/2 - shift_up;
                })
                .datum(format);

            var month_titles = svg.selectAll(".month-title")  // Jan, Feb, Mar and the whatnot
                .data(function(d) { 
                    return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
            .enter().append("text")
                .text(monthTitle)
                .attr("x", function(d, i) {
                    var month_padding = 1.2 * cellSize*7* ((month(d)-1) % (no_months_in_a_row));
                    return month_padding;
                })
                .attr("y", function(d, i) {
                    var week_diff = week(d) - week(new Date(year(d), month(d)-1, 1) );
                    var row_level = Math.ceil(month(d) / (no_months_in_a_row));
                    return (week_diff*cellSize) + row_level*cellSize*8 - cellSize - shift_up;
                })
                .attr("class", "month-title")
                .attr("d", monthTitle);

            var year_titles = svg.selectAll(".year-title")  // Jan, Feb, Mar and the whatnot
                .data(function(d) { 
                    return d3.time.years(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
            .enter().append("text")
                .text(yearTitle)
                .attr("x", function(d, i) { return width/2 - 100; })
                .attr("y", function(d, i) { return cellSize*5.5 - shift_up; })
                .attr("class", "year-title")
                .attr("d", yearTitle);  


            //  Tooltip Object
            var tooltip = d3.select("body")
            .append("div").attr("id", "tooltip")
                .style("position", "absolute")
                .style("z-index", "10")
                .style("visibility", "hidden")
                .text("a simple tooltip");  

            rect.filter(function(d) { return d in data; })
                .attr("class", function(d) { return "day " + color(data[d]); })
                .select("title")
                .text(function(d) { return d + ": " + percent(data[d]); }); 

            function mouseout (d) {
                tooltip.transition()        
                    .duration(500)      
                    .style("opacity", 0); 
                var $tooltip = $("#tooltip");
                $tooltip.empty();
            }

            function dayTitle (t0) {
                return t0.toString().split(" ")[2];
            }
            function monthTitle (t0) {
                return t0.toLocaleString("en-us", { month: "long" });
            }
            function yearTitle (t0) {
                return t0.toString().split(" ")[3];
            }   
        }
    });
    return CalendarioView;
});
1 Solution

Builder

Well, I am still solving some issue, but in general terms the D3 calendar heat map is there.

View solution in original post

0 Karma

Splunk Employee
Splunk Employee

If you haven’t seen it yet, you might want to check out the Splunk reference app with associated developer guidance that was built by a Splunk dev team. The current version covers app development topics from getting your data into Splunk Enterprise to building custom reporting through testing and packaging your app. There’s code and tests you can use and the development process is fully documented. The guidance is available in both paperback and Mobi from Amazon.

This is an ongoing dev effort by the team so check back often to see what’s been added. Also, feel free to post requests for future improvements and even contribute by reporting bugs or submitting pull requests.

0 Karma

Builder

Well, I am still solving some issue, but in general terms the D3 calendar heat map is there.

View solution in original post

0 Karma
State of Splunk Careers

Access the Splunk Careers Report to see real data that shows how Splunk mastery increases your value and job satisfaction.

Find out what your skills are worth!