Wiki

Clone wiki

heatmaps / v2

This is new documentation for Heatmaps v2. For version one, click here

Table of contents

These documents outline, from a developer’s perspective, the Unity Analytics Heatmaps plugin.

#Sign Up As of May 2017, users can activate heatmaps via the Configure page on the Analytics dashboard.

Activate_heatmaps.png

DURING THE MONTH OF MAY ONLY, any user, regardless of license , can sign up!!! Go turn on heatmaps, people!

#Introduction Heatmaps are an incredibly useful (and rather beautiful) visualization of spatial events. Where do players die? Where do they score kills? Where do they get stuck? By collecting the data from hundreds or thousands of plays, you begin to assemble a large-scale picture of how your users experience your game. The patterns that emerge can help you tune the game and improve things like game economy, difficulty curve, and even good ol’ fashioned fun.

Example Heatmap

The Unity Analytics heatmap system is built on top of the Analytics Raw Data Export feature (Pro only). The system allows the recording, reading and rendering of spatial data via a three-step process.

  1. Track data using UnityAnalyticsHeatmap.HeatmapEvent.Send()
  2. Fetch and process raw event data using Raw Data Export and Raw Data Inspector.
  3. Render the heatmap with the Heatmapper Inspector.

Setting Up

Activate Analytics

If you haven't already done so, activate Unity Analytics for your project.

Sign up for Heatmaps

Again, if you haven't done so already, sign up for Heatmaps.

Download the installer...

Heatmaps_Installer.unitypackage

It will also soon be available on the Unity Asset Store.

...or Clone this repo

The Unity Analytics Heatmap repo contains a lot of stuff. The important items are:

  • Heatmaps: A Unity project containing all the plugin code, plus some examples (not all of which are included in the plugin)
    • Assets
      • Editor
        • Heatmaps (contains classes that operate the Heatmapper and the Raw Data Inspector)
      • Plugins
        • Heatmaps
          • Examples (contains examples of how you might implement HeatmapEvent.Send()
          • HeatmapEvent.cs - Use this class to send heatmap events to the Analytics server
          • Lib (contains MiniJSON.cs, for parsing. NB: We've had one report of a namespace clash with MiniJSON...presumably because more than one library is using it. Please let us know if you encounter the same issue.)
          • Renderer (contains classes for rendering the heatmap)
          • Shader (contains a shader used by the HeatmapMeshRenderer)
  • Heatmaps_Installer.unitypackage

Install

Double-click Heatmaps_Installer.unitypackage to install the plugin in your Project. This places the following directories:

  • Assets/Plugins/Heatmaps
  • Assets/Editor/Heatmaps

Using The Raw Data Inspector

Heatmaps comes with the Raw Data Inspector, a client for downloading your data. But the inspector has an important secondary purpose: creating test data. This can be useful while you're learning the system, especially as data gets generated instantly. This means you can begin to play with heatmaps right away, even before you implement any HeatmapEvents.

In fact, you might want to just set aside this wiki and go straight for the jugular of playing with the data (but if you do, read this section first!!!)

If you've installed the heatmaps project correctly, you should find the generator under Window > Unity Analytics > Raw Data.

Raw Data Inspector in the Windows Menu

Which brings you to the Raw Data Inspector.

Raw Data Inspector

Where to save your data?

By default, the 'Output path' of the Raw Data Inspector points to your Application.persistentDataPath. This is the same default location where the Heatmapper reads. While this is useful most of the time, when playing around you might prefer to put your data elsewhere. You can type in any path on your hard drive, so feel free to direct the data where you want it. Just make sure that the Heatmapper points to the same place (see Loading data into the heatmapper). Deleting the path will return you to the persistent data path.

You can open the Output Path folder by clicking'Open Folder'.

Modes

The Inspector has two basic modes: 'Fetch Data' and 'Generate Test Data'

Fetch Data

The primary use of the Raw Data Inspector is to fetch your data from the Unity Analytics Raw Data Export API. Once the data is downloaded, you can use it in the Heatmapper. This is designed to be a very simple — if not overly powerful — CURL client. To fully understand the Raw Data Export system, check out the documentation here.

Setting up for Raw Data Export

Raw Data Export is now a Pro-only feature. But older projects (those activated before June 22, 2016) have been grandfathered in.

Navigate to your project on the Analytics dashboard. Navigate to the Project Configure page. To get there from the Projects page, click the app you want to look at. Now find and click on the 'Configure' tab.

Getting to Configure.

You should see two important fields that look something like this:

Getting to Configure.

Copy the Project ID. Paste it into the UPID field in the Raw Data Inspector. Then copy the Raw Data Export API Key and paste it into the API Key field in the Raw Data Inspector.

Raw Data Inspector

Warning: This API Key is the secret key to your data. Keep it secure!

Once you've pasted for Project ID and API Key, you can use this window to create and retrieve your raw data.

Creating a job

Simply set the Start Date and End Date using yyyy-mm-dd (ISO 8601) format, pick the event type (for heatmaps, this is always 'custom'), then click 'Create Job'. This starts the creation process, which may take seconds or minutes. The display shows which jobs are still running, which jobs have failed, and which jobs are complete.

Downloading

Once a job has completed, a 'Download' button will appear, allowing you to download the relevant data. The Raw Data Inspector will inform you which jobs have been downloaded.

Once the data is downloaded, it can be used by the Heatmapper.

Continuing a job

If you want to get data that exactly pursues an existing job, click the 'Continue' button ('>') next to the job. This creates a new job, starting where the last job left off, continuing until the present (though there's a 30 day max, so be careful), and containing exactly the same event type.

Continue Job

Some notes about Raw Data Export usage

  • Generally, data builds into one-day increments, but it is possible to get partial day data for the current day. When this happens a later job can overwrite the current partial day.
  • Note that there is a throughput limit of 100GB per month. This is a lot of data, but it might be worth your while to avoid using that throughput carelessly. (We will include a metering visualization in a future update)
  • You can usually get the most efficient use of your data budget by using 'Continue Job' (see above).

Generate Test Data

Above, we discussed the first of the Raw Data Inspector's two modes. The second mode is 'Generate Test Data'. You can generate test data in three ways: Freeform Data, Random Heatmap Data, and Demo Data.

Freeform Data

In this mode, the data we generate is random and highly configurable. Mostly, this mode is included so you can create data to test your own tools (i.e., not heatmaps). You can add as many custom events as you want, configured with any allowable parameters. The Example Code section will show you the C# code required to generate what you enter.

Clicking 'Generate' will generate all this random data to the location specified in 'Output path'. You can (and indeed should) delete the generated data by clicking 'Purge'.

Random custom data

Random Heatmap Data

In this mode, we can generate entirely random heatmap data. You must include at least 'x' and 'y' coordinates. You may opt to additionally include a 'z' coordinate, as well as a great many other parameters: rotational information (rx, ry, rz), destination information (dx, dy, dz), time (t), level and fps. Note that 'level' and 'fps' are simply examples of arbitrary parameters...in the real world, you can send whatever parameters you like. You can also choose which event names to send, and how many users, sessions and events you want to simulate. There are even toggles so you can pretend events come from multiple platforms.

Random heatmap data

Whatever your settings, the 'Example code' section will generate C# code to help you do the same thing in real life.

Clicking 'Generate' will generate all this random data to the location specified in 'Output path'. You can delete the generated data by clicking 'Purge'.

Remember to 'Purge' your data each time you generate. Otherwise you're likely to get old and new data overlapping in less-than-helpful ways.

Demo Data

In Demo Data mode, the generated data is built by a set of fixed algorithms. Each Demo is designed to teach you some lesson about ways you can use heatmaps.

Demo Data

The current demos include:

  • Basic Functionality: Shows off a few key ideas, such as particle shapes, sizes, and colors.
  • Really Big Game - Demonstrates some important ideas about scale, direction, and time.
  • Maze 1: Multilevel Game - Shows how you can separate events by level or individual device.
  • Maze 2: FPS Dropoff - Explains how you can remap color in the map to another parameter...in this case, frames-per-second.
  • VR Lookat - Demonstrates how you can use destinations to see what players look at or shoot. Also shows off masking.
  • Speed Racer - An example of using destinations to visualize speed.

As in Random Data mode, you'll see example code at the bottom, and you click 'Generate' to create the data.

The Heatmapper

The Heatmapper Once you have data, you'll want to actually see it rendered. This is where the Heatmapper comes in!

Loading Data Into The Heatmapper

By default, the Raw Data Inspector places raw data into the application's persistent data path. And by default, the Heatmapper pulls its data from that same location. If you've changed the location in one, you need to change it in the other.

The Heatmapper has a checkbox under the 'Data' section — 'Use custom data path'. If unchecked, the Heatmapper will look for data in the persistent data path. Check this box and set a path if you want to override. In the 'Input path' field that appears, enter a path to a directory on your computer. A good one is ./ which places the data folder inside your Unity project.

What's key is that the 'Input Path' in the Heatmapper matches the 'Output path' in the Raw Data Inspector.

Match the paths

Set start and end dates in the format YYYY-MM-DD (ISO 8601) to determine which dates to include in your map.

If you've generated data and the paths and dates match, you should now have some heatmap data.

Working With Data

This step presumes you've already worked out how to load data. If you haven't, go back to Loading data into the Heatmapper.

Smoothing, separating, and remapping

Once data is downloaded, it is automatically aggregated. But you can aggregate it in many different ways. This section explains the possibilities.

Modify how the data is processed by trimming dates, by smoothing space, rotation or time, by separating a variety of fields, or by remapping color.

The Data Pane

Dates

Start Date and End Date are ISO-8601 (YYYY-MM-DD)dates that define where you want your heat map data to begin and end. Aggregation ignores info before or after these dates. By default, the Heatmapper picks the last five days.

Smooth

Smoothing options process in one of three ways: unionizing (union symbol), smoothing (# symbol), or none (strikeout symbol).

The Data Pane

Smooth uses the textfield value to specify a divisor for smoothing the relevant coordinates. For example, if space smooth is 10, all events from -5 to 5 will aggregate at 0. Events from 5 to 15 will aggregate at 10.

None will use the exact values reported, with no smoothing at all.

Unionize reduces all values to 0. This is useful for time and rotation (we don't allow you to unionize space...we're cruel like that), if you want to ignore those values. For example, if you want to know that an event occurred at a specific point in space without regard to when it happened in time, unionizing time gives you the answer. If time is smoothed (or 'None' is selected), events that happened at the same point in space but different points in time will render separately.

In the image below, time is unionized on the left, smoothed on the right.

Unionized versus non-unionized time

Position, rotation, and time are all candidates for smoothing controls.

Separate

You can choose to separate results into lists. This can be very helpful when trying to break data into discrete groups. The separated lists appear in the Render section.

You can separate on any of the following:

  • By user
  • By unique play session (roughly equivalent to individual plays)
  • By platform
  • Separate debug builds from non-debug
  • By one or more arbitrary fields (such as 'level')

Separating level

Remap color to field

By default, color represents data density. So in a green-red heatmap, red events are denser (more things happened there) than green events. When Remap color to field is checked, you can specify a numeric field with which to remap color. For example, the field name 'fps' could be used to display a particular color where frame rates are low.

Separating level

Remap Operations

What does a remap tell you? Well, it might tell you many different things. Are you looking for the first time something happened? The average? The median? The max? Use remap operations to specify what you want the color to tell you. Here are the options:

  • Display earliest point, i.e., the first point encountered
  • Display latest point, i.e., the last point encountered
  • Display highest value
  • Display lowest value
  • Incremental (adds 1 for each instance)
  • Additive (adds all values together)
  • Average
  • Percentile (0-100, Median = 50)

Process

When you've made your choices, click the Process button. Whenever any changes are made in the Data section, they will register in the heatmap only after processing.

#Rendering

So, you’ve sent a bunch of data (or generated it from the Raw Data Inspector, retrieved it, aggregated it. Here’s where the fun begins!

The Heatmapper inspector allows you to load, view, and manipulate heatmap data within Unity. It looks like this:

The Heatmapper

If you've followed everything so far, you should already be seeing a heatmap, which may look something like this (or it may not...the data in this image was generated from the Raw Data Inspector's random generation feature):

A typical heatmap

The heatmap is a Mesh, just like any other GameObject mesh. You can rotate around it, zoom in on it...even convert it to a prefab for use in a game!

OK, you’ve had your fun...back to work! Let’s look at all these controls to see how you can modify what you’re looking at.

Heatmapper Renderer Controls

The render pane

Option lists

Depending on exactly how you processed your data, you might see one or more dropdown lists at the top of the Render section. You should certainly see a list of one or more custom event names. If you've used any of the "Separate" options, you'll additionally see extra lists with additional options. Use these lists to see the various separated groupings of data.

Color Gradient

Color gradients

Individual events occurring at exactly the same location were aggregated in the previous step. What counts as "exactly" depends on some of the settings with which you aggregated. For example, setting the "Space Smooth" value to 100 in the inspector will aggregate the following events to the same place (all get smoothed to 0, 0, 0):

(x, y, z)

  • -49.9, -49.9, -49.9
  • 0, .2, 14.5
  • 48.2, 49.9, 49.9

You could re-run the process with the space value set to 1 or 1000 or .2 or 72.5. In each case, the space value indicates a unit divisor across all three dimensions for splitting up and smoothing your data.

The more often an event occurs at the same place, the higher its density, represented by d in the JSON. The inspector (and the renderer) displays a gradient to reflect this density. Colors on the right of the gradient are higher density. Those on the left are lower. Click the gradient to edit it. Gradients can be saved in the the Gradient Editor for later reuse.

We've found that tweaking colors is necessary to make your heatmap visible and useful within your unique environment.

While color represents density by default, note that color can be used to represent more complicated mathematical functions. See remap operations, above.

Particle controls

Size

A number to adjust the render size of each heatmap point. We find it often helps to set this at or near the value you set "Space Smooth" to when processing.

Shape

Set this to Cube, Square, Triangle, Point To Point or Arrow to change the display of each data point.

The Arrow shape is uniquely suited to displaying rotation.

A heatmap showing directional information

Point To Point is suited to displaying destination information (you can see an example below under 'Masking').

Billboard plane (visible only for square and triangle)

Set to YZ, XZ or XY. This is useful in 2D if you need to adjust the direction of the Square or Triangle particles.

Same data in three billboard planes

Masking

The masking controls allow you to "trim" data in the x, y, and z coordinates to isolate areas that you want to look at.

A great example of the utility of masking can be seen in Raw Data Inspector > Generate Test Data > Demo Data > VR Lookat. The initial data is pretty hard to interpret. With a little trimming, however, you can clearly find the data you're looking for.

VR LookAt without masking

Time

When you sent your original event information, you had the option of sending it with a time parameter. If you did so — and we hope you did — you can use these sliders to filter out early or late events, and you can drag the control to "scrub" through all the data (as you might do in a movie editor), which can reveal developing trends over time. Note that this won't work if you opted to unionize time when smoothing.

Time controls

The play controls allow you to view your heatmap as if it were a movie. Simply set your play speed, pick an end time, then click the Play button. You can tweak the play speed while the "movie" is running, or use the Rewind button to return to the start.

Points (displayed/total)

This is a simple fraction, indicating how many points are being displayed at present over the total number of points in the dataset. If the numerator is greater than 0 and you can't see anything, the likeliest reason is that the Particle Size is too small. If the demoninator is 0, there's a good chance something went wrong during data download/processing.

Points in set

Hot tips

Sometimes when looking at a heatmap it can be useful to see exactly what data generated a specific point on the heatmap. It is possible to do exactly this by checking the 'Hot tips' checkbox. With this turned on, you can mouse over the point and get information about it.

Hot tips

Some important things to note about Hot tips:

  • You must both check the box AND select the particle you want to see (technically, you're selecting the submap GameObject).
  • The MeshCollider that makes this bit of magic possible is EXPENSIVE. Turn it off when you don't need it!
  • The MeshCollider is one-sided. This means that the mouseover might not work on some shapes if you're on the wrong side of them. Cubes are naturally enclosed, so the tip should always work.

#HeatmapEvent API Of course working with demo data is easy, but what you really want to do is get the data about your own game.

In order to allow you to capture heatmap data simply, we’ve created an API specifically for heatmaps. Note that UnityAnalyticsHeatmap.HeatmapEvent.Send() is simply a typesafe adapter for the standard UnityAnalytics.CustomEvent() method, so you could choose to ignore HeatmapEvent.Send(). But the wrapper adds the advantages of simplicity and type-safety, meaning you’re less likely to send data that the post-processor can't interpret.

Send heatmap events in one of the following forms:

#!c#

    // Notes:
    // Vector2 implicitly converts to Vector3, so sending V2's is allowable.
    // All forms end with an optional Dictionary.
    // Custom Events currently support a maximum of 10 parameters (see below).

    // Simply send Vector3 position info
    UnityAnalyticsHeatmap.HeatmapEvent.Send(string eventName, Vector3 position, Dictionary<string, object> options = null);

    // Send Vector3 position plus time
    UnityAnalyticsHeatmap.HeatmapEvent.Send(string eventName, Vector3 position, float time, Dictionary<string, object> options = null);

    // Send Vector3 position plus time and X rotation (suitable for 2D)
    UnityAnalyticsHeatmap.HeatmapEvent.Send(string eventName, Vector3 position, float time, float rotation, Dictionary<string, object> options = null);

    // Send position plus rotation (no time)
    UnityAnalyticsHeatmap.HeatmapEvent.Send(string eventName, Transform transform, Dictionary<string, object> options = null);

    // Send Vector3 position, rotation and time
    UnityAnalyticsHeatmap.HeatmapEvent.Send(string eventName, Transform transform, float time, Dictionary<string, object> options = null);

    // Send the event with position, and destination
    Send(string eventName, Vector3 v, Vector3 v1, Dictionary<string, object> options = null)

    // Send the event with position, destination, and time.
    Send(string eventName, Vector3 v, Vector3 v1, float time, Dictionary<string, object> options = null)

Example:

#!c#
    using UnityAnalyticsHeatmap;

    //Send the position, rotation and time at the moment of player death
    HeatmapEvent.Send("PlayerDeath", transform, Time.time);

All heatmap events require an eventName to distinguish the specific spatial event you’re mapping. Note that the Send() method automatically prepends the word "Heatmap." to your event name, so "PlayerDeath" will be processed as "Heatmap.PlayerDeath". Vector2’s or Vector3’s may be used for position to map in two or three dimensions respectively (consider using Vector2’s both for 2D games and for mapping UI interactions). Including time allows you to render results based on when an event occurred during gameplay. Depending on your use case, you might want to use Time.time, Time.fixedTime, Time.realtimeSinceStartup, Time.timeSinceLevelLoad, or Time.unscaledTime. See UnityEngine.Time documentation for details.

'time' is arbitrary. If your game is turn-based, you could send the number of the turn (expressed as a float).

The following data can be sent with Heatmap events

  • x - World spatial coordinates
  • y
  • z
  • rx - World rotational components
  • ry
  • rz
  • dx - A second positional coordinate (used for drawing point-to-point)
  • dy
  • dz
  • t - An indicator for time

Adding arbitrary data

Custom Events are limited to 10 parameters. If you choose to add arbitrary parameters, ensure that you don't add any more than the Custom Event will support for the HeatmapEvent form you choose. Events with > 10 parameters are rejected by the Analytics SDK.

Example:

#!c#
    // We're sending seven parameters here (x,y,z,dx,dy,dz,t). Room for three more.
    HeatmapEvent.Send("EnemyKill", transform.position, enemyGameObject.transform.position, Time.time);

    // So we can do this...
    var dict = new Dictionary<string, object>(){{"fps", fps}, {"level", level}, {"weapon_used", weapon.type}};
    HeatmapEvent.Send("EnemyKill", transform.position, enemyGameObject.transform.position, Time.time, dict);


    // But if we did this...too many parameters!!!
    var dict = new Dictionary<string, object>(){{"fps", fps}, {"level", level}, {"weapon_used", weapon.type}, {"one_too_many":"sad trombone"}};
    HeatmapEvent.Send("EnemyKill", transform.position, enemyGameObject.transform.position, Time.time, dict);

About sending heatmap events

As you know, apps using Unity Analytics have a Custom Event limit of 100 events per hour per device. Heatmap events are just like any other custom event, but in order to make heatmap data useful to you, apps that sign up for heatmaps get this limit increased to 5000 events per hour per device. This allows you to send a bit more than one event/second...which is a lot of data.

PLEASE BE RESPECTFUL OF THIS PRIVILEGE. Your app should send heatmap data ONLY for development builds.

We're working on a mechanism to allow heatmaps for production use, but this is a non-trivial task, so bear with us.

#Optimization

Heatmap visualizations are naturally data-heavy, and you might find that rendering so many points in your scene creates a performance hit. With this in mind, we’ve provided a few optimization tricks that might help you get the most out of this feature.

Sending events

Only send what you need to send

If you only need x and y information, and don't care about time or rotation, use the form of the HeatmapEvent that sends the least data. This will minimize any potential impact on your game performance and yield smaller (and therefore faster) datasets when you download the raw data.

Only send when you need to send

We've upped your events/device limit to enable you to send a LOT of events, but resist the temptation to instrument every possible thing or try to send multiple Heatmap events every second. Critically examine what you're mapping and how often you need to map it. Too much data can be just as confusing as not enough data.

Processing

When processing, use the space, time, and rotation values to round out individual data points. Higher smoothing values tend to yield fewer individual points.

You can also use date trimming to limit the number of input events.

Rendering

The heatmapper uses a dynamically drawn mesh to render the data. It can render a theoretically infinite number of vertices, but at some point this is bound to affect performance. There are a couple render settings in the Heatmap Inspector that can help you render faster and with less performance impact.

Particle Shape

The Particle Shape drop-down allows you to pick a shape with which to render each data point. At present, the renderer supports five shapes: Cube, Square, Triangle, Arrow and Point-to-Point.

Not surprisingly, a triangle requires only 3 vertices. A square requires more, and cubes and arrows more still, so naturally they are heavier on rendering. If you finding performance lagging, try using triangles and see if that helps.

Time filtering

The Heatmap Inspector allows you to narrow the range of rendered points by game time (this is one good reason for using a form of HeatmapEvent.Send() that includes time).

Doing so can dramatically limit rendering impact, since Unity only needs to draw the points within the provided game time window.

Masking

The x, y, and z masking controls limit which particles are rendered by spatial position. As with time, filtering out areas of space lowers the rendering overhead.

Disable hot tips

Hot tips allow you to see the data underlying an individual heat point simply by mousing over it. But to do this requires the creation of a very complex Mesh Collider. This is very performance intensive. Keep it off unless you need it.

#Runtime Heatmaps

HeatmapMeshRenderer produces a mesh, just like any other mesh, so the easiest way to get a runtime heatmap is simply to save the editor-time mesh as a prefab and just plain use it!

But let's say you wanted to display your heatmap — live and able to update — to your players. To do this, you'd want to use the actual HeatmapMeshRenderer at runtime, and it's pretty easy to create a runtime controller class make that happen. In fact, we've included a simple one in the repo for you to peruse (Heatmaps/Assets/Plugins/Heatmaps/Renderer/HeatmapController.cs). This isn't an all-singing, all-dancing controller, but it gives you everything you'd need to understand how to use the HeatmapMeshRender at runtime.

To use HeatmapController, complete these steps:

  1. If you don’t have a Resources folder, create one.
  2. In the Resources folder, place a copy of the aggregation output (i.e., a JSON file generated via the Heatmapper).
  3. In your game, create an empty GameObject. Name it 'MyRuntimeHeatmap'.
  4. Add the HeatmapController MonoBehaviour to 'MyRuntimeHeatmap'.
  5. Look at the Inspector for 'MyRuntimeHeatmap'. Under Heatmap Controller, find the Data Path field.
  6. Type in the name of your JSON file.
  7. Hit Play!

Now, to really make this work the way we described — to update the heat map on-the-fly for your players — you'd have to build in a bit more infrastructure. Specifically, you'd collect your raw data and aggregate it on a server, then allow your controller to fetch that server-side JSON file. It's outside the purview of this document to explain that process, but hopefully the idea is clear enough.

Writing A Custom Renderer

The provided renderer uses a mesh to display the heatmap data. We've experimented with other approaches, such as using the Shuriken particle system. You don't need to understand the renderer in order to use the system, but you might want to learn about it, especially if you're thinking about attempting an alternate rendering solution.

IHeatmapRenderer

HeatmapMeshRenderer was written with the presumption that developers might want to write their own custom renderers. With this in mind, we created the IHeatmapRenderer interface. By default, the HeatmapInspector starts up with an instance of HeatmapMeshRenderer, but if you want, you can swap in a custom renderer to override the display. Any MonoBehaviour that implements IHeatmapRenderer is permissible, and the only line you need to change (outside of your custom renderer, of course) is this one in Heatmapper (currently on line 187):

//Change this to add your custom renderer
heatMapInstance.AddComponent<HeatmapMeshRenderer> ();

Here’s the required API for an implementor of IHeatmapRenderer:

UpdatePointData sets an array of heatmap data. See HeatPoint below. maxDensity is the highest d value in your data set.

void UpdatePointData(HeatPoint[] data, float maxDensity);

UpdateGradient defines the gradient that colors the heatmap.

void UpdateGradient(Gradient gradient);

UpdateRenderMask defines the min/max coordinate space that will be rendered.

void UpdateRenderMask(float lowX, float highX, float lowY, float highY, float lowZ, float highZ);

UpdateTimeLimits allows the user to limit the display of data by game time.

void UpdateTimeLimits(float startTime, float endTime);

RenderHeatmap tells the renderer to perform a new render.

void RenderHeatmap();

UpdateRenderStyle allows the user to set a type of rendering. At the moment, the allowed styles are RenderShape.Cube, RenderShape.Square, RenderShape.Arrow, RenderShape.Triangle and RenderShape.PointToPoint together with directions RenderDirection.YZ, RenderDirection.XZ, and RenderDirection.XY.

void UpdateRenderStyle(RenderShape style, RenderDirection direction);

pointSize is a getter/setter for the size of individual data points.

float pointSize { get; set; }

allowRender, when true, permits the renderer to operate. When false, rendering is suppressed.

bool allowRender { get; set; }

activateTips, when true, permits the user to mouseOver individual data points. When false, tips are suppressed.

bool activateTips { get; set; }

currentPoints gets the number of points currently being rendered (Getter only).

int currentPoints { get; }

totalPoints gets the total number of points in the current data set (Getter only).

int totalPoints { get; }

HeatPoint

The HeatmapRenderer uses a struct called HeatPoint, which is simply a holder for all the relevant data for a sample point:

public Vector3 position;
public Vector3 rotation;
public Vector3 destination;
public float density;
public float time;

Note that in cases where only 2 dimensions of data are sent (i.e., data was sent using Vector2), the HeatPoint still renders using Vector3, with only the x and y coordinates specified. In this case, the z ordinate is 0.

FAQ

Q: Do I need to sign up with Unity Analytics to use heatmaps?

A: Yes, but... Heatmaps operates using raw data collected from the Unity Analytics service.

But you can try it out with or without signing up by downloading the installer and trying it with the Raw Data Inspector.

Q: I don't see my heatmap.

There can be many causes for this. Let's walk through a few possibilities, working backwards from the moment you clicked "Process".

What are your renderer settings?

One common reason for not seeing the heatmap is simply visual: how big is your Particle Size? Are you rendering a shape and color that assist you in seeing your map against your game? Try fiddling with the render settings to see if anything appears. Also, in the hierarchy, try typing the word "heatmap". Not only does this isolate the heatmap GameObject, it grays back and makes transparent everything else. This can help if, say, your heatmap is hiding behind another GameObject.

Do you have any data?

At the very bottom of the Heatmapper you should see "Points (displayed/total)". If the denominator is "0", there's no actual data to display.

Are you loading data correctly?

Are you using the default persistent data path in BOTH the Raw Data Inspector and the Heatmapper? If not, have you matched the 'Output path' in the Raw Data Inspector to the 'Custom data path' in the Heatmapper?

Are you actually downloading data correctly?

Return to the Raw Data Inspector. Click 'Get Jobs'. In the generated list, you should see some greenlit jobs, and some or all of these should say 'Downloaded'. The date ranges of downloaded jobs should match the dates you're trying to view in the Heatmapper.

If you're not downloading data...

...are you sure there's data to download? Raw data can take anywhere from seconds to many minutes to be available, depending on a variety of factors. While you're waiting, check the validator on your app's dashboard to ensure that the events are being received. If you see them in the validator, they'll eventually show up in your raw data export. If you don't see them there, it probably means that you haven't implemented the HeatmapEvent properly.

Q: Is there any way to save my raw/processed data?

There is. The raw and processed data are by default stored in your persistent data path. As of Heatmaps 2, you can actually choose to store it anywhere on your drive you want, though the persistent data path is still the default. If you go to this location, you can copy the data from there to wherever you like.

Q: I'd like to make a feature request or file a bug report.

Please create an issue here.

Where can I see version history?

Click here.

Updated