Skip to content

Releases: palantir/plottable

Scatterplot + Legend Symbols on IE

03 Apr 21:57
Compare
Choose a tag to compare
Pre-release

v0.51.0

Good afternoon,

Since non-scaling-stroke does not work on Internet Explorer, we had to change our approach to drawing symbols. A SymbolFactory now draws a particular symbol given a size; see below for what changes this causes to the API.

Bugfixes

API-Breaking Changes

  • The SymbolGenerators module has been renamed to SymbolFactories
  • A SymbolFactory is now a function with the following signature:
(symbolSize: number) => string

where symbolSize is the edge-length of a square drawn as a tight bound around the symbol.

  • Legends symbolGenerator API has been reworked into symbolFactoryAccessor which takes in an accessor function that returns a SymbolFactory. It has the following signature:
public symbolFactoryAccessor((datum: any, index: number) => SymbolFactory)

This allows selection of the SymbolFactory to use based on the Legend entry.

Upgrade Instructions

  • Instead of using the d3Symbol SymbolFactory, one of the following endpoints should be used instead:
Plottable.SymbolFactories.square();
Plottable.SymbolFactories.circle();
Plottable.SymbolFactories.diamond();
Plottable.SymbolFactories.cross();
Plottable.SymbolFactories.triangleUp();
Plottable.SymbolFactories.triangleDown();
  • project() calls for symbols have to be adjusted:
var squareGenerator = Plottable.SymbolFactories.square();
scatterplot.project("symbol", function(d, i) { return squareGenerator; });
  • To set the size of points on Plot.Scatter, project() on "size" instead of "r":
// before: project("r", 3);
scatterplot.project("size", 6); // size of square containing symbol, instead of radius of symbol

Release Song

Gold Rays -- Vinyl Pinups
https://www.youtube.com/watch?v=Izl8zFCWSjA

Interaction and API tweaks

27 Mar 22:53
Compare
Choose a tag to compare
Pre-release

v0.50.0

Features

component.above and component.below API

Before, there was a merge API that allowed users to place components into a component group for the sake of the components sharing the same cell in the Plottable table.

However, this merge API does not describe where the components will render in terms of which component will be on top and which component will be on bottom visually.

In fact, merge essentially placed the calling component below the argument component (even though this is not well described).

Thus, merge has been renamed to below and above has been created as its foil, where a.above(b) will place a on top of b and a.below(b) will place a below b.

The signatures of both API are as follows:

public above(c: AbstractComponent): Component.Group;
public below(c: AbstractComponent): Component.Group;

Bugfixes

  • If undefined points are handed to Plot.Scatter, those points are not rendered as consistent with previous behavior.
  • As consistent with other browsers, the stroke-width on symbols on Plot.Scatter does not scale with the transform by default.

API-Breaking Changes

  • Component.merge has been renamed into Component.below and Component.above now exists as its foil.

Typescript API-Breaking Changes

  • Interaction.DoubleClick no longer extends from Interaction.Click as we are modifying the architecture of Interaction.Click without disrupting the behavior of Interaction.DoubleClick

Other notes

  • Interaction.Hover has been deprecated due to Interaction.Pointer being released in the last release, which uses the new Interaction architecture / structure.

Upgrade Instructions

  • For those who want to keep existing functionality while using Component.merge, please replace all occurrences with Component.below. However, if a user wanted to place a component above another component instead while keeping the same code structure, replace Component.merge with Component.above appropriately.

Future Changes

Coming Shortly:

  • Interaction.Click
  • Interaction.Drag
  • Interaction.Pan + Interaction.Zoom

Release Song

"All the Small Things" --Blink 182
https://vimeo.com/32122929

Plot.Grid upgrades, Closest-Point methods, and Interaction upgrades

20 Mar 22:43
Compare
Choose a tag to compare

screen shot 2015-03-20 at 3 29 11 pm

Good afternoon,

This release features an improved Plot.Grid, a method for retrieving the closest PlotData from a Plot, a new Interaction, and an upgrade to Dispatcher.Mouse.

Features

The new Plot.Grid built on Plot.Rectangle

Plot.Rectangle is a new type of plot that draws rectangles given values for x1/x2 and y1/y2. We are going to be gradually migrating all rectangle-based plots to this; in the meantime, there probably won't be a need for you to use Plot.Rectangle directly unless you're doing some really crazy stuff (and if you are, we would love to hear about it!)

Plot.Grid has been rearchitected to leverage Plot.Rectangle. As a consequence, Plot.Grid can now be used on both Category and Quantitative Scales. Plot.Grid is initialized with an xScale, a yScale, and a colorScale. Projections on Plot.Grid from various scales are as follows

  • Scale.Category - In order to project data onto a GridPlot using a Scale.Category, we need to project the x/y attribute on the xScale/yScale.
  • Quantitative Scales - In order to project data onto a GridPlot using a Quantitative Scale (could include Scale.Time, Scale.Linear, Scale.ModifiedLog), you have to project the lower bound as x/y and the upper bound as x2/y2.

Existing instances of Plot.Grid should continue to work with no modification needed; this feature simply added more functionality to the existing API points.

Examples of Plot.Grid with (1) a Scale.Time on the X-axis and a Scale.Linear on the Y-axis and (2) a Scale.Time on the X-axis and a Scale.Category on the Y-axis can be found at the following link: http://jsfiddle.net/L861y4s1/1/

getClosestPlotData() on Plots

Similar to how Plots have a getAllPlotData API, there is now a getClosestPlotData() API on Plots. The signature is

public getClosestPlotData(queryPoint: Point, withinDistance = Infinity, datasetKeys: string | string[] = this.datasetOrder())

As seen from the signature above, getClosestPlotData takes in a Point to find the PlotData closest to that point within the withinDistance for all Datasets listed in datasetKeys.

The calculation is done by looping through each of the pixelPoints from getAllPlotData(), finding the closest point, and reporting the appropriate selection / data information under the given circumstances.

This method treats all Plots as though their data values are represented by a single point (because it uses the pixelPoint property of the PlotData for computing distance); for example, it does not take the shape of the bars into account when finding the closest PlotData on Plot.Bar. getAllPlotData() can be used to implement alternative closest-point algorithms, in conjunction with generateProjectors() to account for additional shape information.

Interaction.Pointer

Interaction.Pointer has been added. This Interaction triggers callbacks when the user mouses into a Component, moves the mouse within the Component, or mouses out of the Component. Example usage:

var pointerInteraction = new Plottable.Interaction.Pointer();
pointerInteraction.onPointerMove(function(p) {
  // do something with the point p, maybe call getClosestPlotData()
});
pointerInteraction.onPointerExit(function(p) {
  // some code that cleans up
});
plot.registerInteraction(pointerInteraction);

onWheel() API on Dispatcher.Mouse

The onWheel() method has been added Dispatcher.Mouse. This method can be used to register callbacks to be called when the scroll-wheel on the mouse is activated. The signature is

public onWheel(key: any, callback: MouseCallback): Dispatcher.Mouse

Wheel data can be retrieved from the Event passed to the MouseCallback.

Bugfixes

  • Plot.Line used to return one <line> selection per datum in its PlotData, even though the line represents the entire Dataset. Now it returns only one <line> selection per Dataset.

Upgrade SVG Typewriter version

18 Mar 17:59
Compare
Choose a tag to compare
Pre-release

This brings the version of D3 used by SVG Typewriter in line with that used by Plottable.

Symbols, and Backgrounds, and Data, oh my!

13 Mar 22:34
Compare
Choose a tag to compare

v0.48.0

Features

SymbolGenerators

A SymbolGenerator is a function that, given a datum and index, returns a String representing the d attribute of an SVG <path> element:

type SymbolGenerator = (datum: any, index: number) => string;

The SymbolGenerator produces a path-string assuming the <path> has a 100px by 100px space in which to render.
Some default SymbolGenerators have been included under Plottable.SymbolGenerators.d3Symbol(); for example,

Plottable.SymbolGenerators.d3Symbol("square");

returns a SymbolGenerator that draws squares. The supported symbol types are "circle", "square", "cross", "diamond", "triangle-up", and "triangle-down".

Symbols on Plot.Scatter

Plot.Scatter now uses a SymbolGenerator to determine the type of symbol rendered, rather than always rendering circles. project()-ing on to the "symbol" property will change the type of symbol drawn. For example:

scatterPlot.project("symbol", Plottable.SymbolGenerators.d3Symbol("square"));

will cause the Plot.Scatter to draw squares. As usual, the projector can be data-dependent:

var upVsDown = Plottable.SymbolGenerators.d3Symbol(function(d, i) {
  if (d.y > 0) {
    return "triangle-up";
  } else {
    return "triangle-down";
  }
});
scatterPlot.project("symbol", upVsDown);

The above code will cause different types of symbols to be shown depending on the y property of each datum:
screen shot 2015-03-13 at 2 00 40 pm

Plot.Scatter will use a circle as the default symbol if one is not specified.

Symbols on Legend

screen shot 2015-03-13 at 2 19 34 pm

Similarly, Legends now take a SymbolGenerator:

legend.symbolGenerator(Plottable.SymbolGenerators.d3Symbol.d3Symbol("square"));

Will cause the Legend to display squares instead of circles. The SymbolGenerator is passed the Legend entries as arguments, allowing different symbols to be displayed for different entries:

colorScale.domain(["good", "neutral", "bad"]);
var legend = new Plottable.Component.Legend(colorScale);
var nameToSymbol = {
  "good": "triangle-up",
  "neutral": "square",
  "bad": "triangle-down"
};
var generator = Plottable.SymbolGenerators.d3symbol(function(entryName, i) {
  return nameToSymbol[entryName];
});
legend.symbolGenerator(generator);

Symbols on Legend are marked with the legend-symbol CSS class if users want to style them.

background-fill on Components

Components now feature a <rect> in their background container that allows their background to be colored. For example, this CSS

.plottable .plot .background-fill {
  fill: pink;
}

Will color the background of all Plots pink:
screen shot 2015-03-12 at 8 47 36 pm

If multiple Plots are in a Group, a more specific rule needs to be used to color only the background-fill of the Group:

.plottable .component-group > .background-container background-fill {
  fill: pink;
}

content() accessor

Components now have a content() method that retrieves the D3.Selection that they draw in, in the event that users want to use D3 to manipulate elements the Component has drawn. See below for an example use case.

Legends no longer apply CSS classes based on entry names

Legends no longer apply the name of the entry as a CSS class to the entry's <g>. To restore this behavior, add the following code:

legend.content().selectAll("." + Plottable.Component.Legend.LEGEND_ENTRY_CLASS)
                .each(function(d) {
                  d3.select(this).classed(mySanitizingFunction(d), true);
                });

This allows users to specify their preferred CSS sanitizing function (for removing spaces from the applied names, for example).

Exclude argument in getAllSelections()

plot.getAllSelections() now takes an exclude argument:

public getAllSelections(datasetKeys?: string | string[], exclude = false): D3.Selection

The optional exclude argument that defaults to false. If exclude is set to true, then all Datasets in the Plot will be queried except the ones specified by the datasetKeys argument.

getAllPlotData()

plot.getAllPlotData() returns a PlotData object containing all of the data, pixelPoints, and the selections for the specified Dataset(s):

export type PlotData = {
  data: any[];
  pixelPoints: Point[];
  selection: D3.Selection;
}

The pixelPoints property will depend on the type of Plot. For example, the returned Points will be in the center of the symbols on a Plot.Scatter, but on a Plot.Bar the Points in the center-top of the bars (or center-bottom if the bar has a negative value).

generateProjectors()

When a user passes projector information through plot.project, Plottable stores this "projector" information to render those attributes on the plot (along with defaults if those attributes have not been set). Users now have access to this information through the generateProjectors() call. This API point allow access to the "projected" information the plot uses, such as the x and y pixel values corresponding to the positions of data points, without having to inspect the rendered <svg>.

The signature is:

public generateProjectors(datasetKey: string): AttributeToAppliedProjector

An AttributeToAppliedProjector is an object maps attribute strings to a projector, which is a function that takes in a datum and an index that returns an arbitrary value:

type AttributeToAppliedProjector = { [attrToSet: string]: AppliedProjector; };
type AppliedProjector = (datum: any, index: number) => any;

An example usage:

var projectors = linePlot.generateProjectors(datasetKey);
var xProjector = projectors["x"];
var yProjector = projectors["y"];
var pixelPositions = linePlotData.map(function(datum, index) {
  return {
    x: xProjector(datum, index),
    y: yProjector(datum, index)
  };
});
// use the pixelPositions to calculate a closest point or something...

API-Breaking Changes

  • Scale.Ordinal has been renamed to Scale.Category because its function deviates from the vanilla D3 ordinal scale (#1210).
  • The animators on Plot.Scatter have been renamed from "circles"/"circles-reset" to "symbols"/"symbols-reset" as Plot.Scatter now renders symbols instead of circles.

Other notes

  • Plottable has upgraded D3 to v3.5.5.

Restoring Interaction.Hover on mobile

04 Mar 01:55
Compare
Choose a tag to compare
Pre-release

This release fixes a regression caused in our last release, where Interaction.Hover stopped responding to Touch events as we switched from using D3 to writing our own implementation. We wrote Dispatcher.Touch to solve this problem. Mobile functionality for Interaction.Hover should now resemble functionality from v0.45.0 and before.

This release is occurring off-schedule in order to supply a fix for the regression as soon as possible. Note the version number change, which reflects the addition of new API points (see below).

v0.47.0

Features

Dispatcher.Touch

Dispatcher.Touch has been added. This Dispatcher reports the first touch position relative to the <svg> on touchstart, touchmove, and touchend events. Example usage:

var touchDispatcher = Plottable.Dispatcher.Touch.getDispatcher(svgElement);
touchDispatcher.onTouchStart("dispatcherKey", touchStartCallback);
touchDispatcher.onTouchMove("dispatcherKey", touchMoveCallback);
touchDispatcher.onTouchEnd("dispatcherKey", touchEndCallback);

Events passed to Dispatcher callbacks.

Dispatcher callbacks are now passed the original Event object, to allow for more customization of behavior. One example might be to call preventDefault() to suppress text-selection or other behavior.

Bugfixes

  • Interaction.Hover now responds to touchstart events. Initiating the touch event will have the same effect as moving the mouse to that position.
  • Scale.Time no longer locks up if both ends of the domain are set to the same value (#1689).

Upgrade Instructions:

Typescript Users: Please add the touch-events type definitions to your project.

Progress towards Improved Interactions

28 Feb 01:18
Compare
Choose a tag to compare
Pre-release

v0.46.0

Features

onMouseDown() and onMouseUp() added to Dispatcher.Mouse

Users can now register callbacks to Dispatcher.Mouse to be called when mousedown and mouseup events occur, using onMouseDown() and onMouseUp():

var md = Plottable.Dispatcher.Mouse.getDispatcher(svgElement);
var downCallback = function(point) {
  // do something with the point on mousedown
};
var upCallback = function(point) {
  // do something with the point on mouseup
};
md.onMouseDown("callbackKey", downCallback);
md.onMouseUp("callbackKey", upCallback);
...
md.onMouseDown("callbackKey", null); // to remove the callback
md.onMouseUp("callbackKey", null); // to remove the callback

Bugfixes

  • When Axis.Category labels are rotated, the text wrapping that is applied is far less aggressive than before. (#1526).
  • Right oriented Axis.Category respects tick marks now. (#1646).
  • Scale.Time no longer locks up if both ends of the domain are set to the same value (#1689). This fix was mistakenly not merged into v0.46.0. It will be included in v0.47.0.

Other notes

The new Dispatcher.Mouse doesn't trigger events correctly on mobile devices. We expect a fix in 1-2 weeks.

Future

This week we began work on:

  • Interaction.Dragbox
  • an API endpoint which will return the closest data point to any position on the graph.

Expect to see these soon!

Hotfix for Axis.Category

27 Feb 21:32
Compare
Choose a tag to compare
Pre-release

Category Y-Axes were doing incorrect space calculations when next to an empty cell. This caused the text to not show up in certain cases.

Hotfix for Dispatcher.Mouse

25 Feb 23:09
Compare
Choose a tag to compare
Pre-release

Good afternoon,

This release includes a hotfix for Dispatcher.Mouse. The measure-rect it uses to compute the mouse position has been styled to visibility: hidden, to prevent accidental selection of text arising from clicking on the measure-rect.

Dispatchers, getAllSelections, and Flipped Axes

20 Feb 23:17
Compare
Choose a tag to compare

TL;WR

  • You can now use getAllSelections to get just one dataset, instead of all data associated with a plot.
  • Hover (Dispatcher.Mouse) and Key (Dispatcher.Key) interactions now work correctly even when a Component or Plot is scaled with CSS.
  • Axis.Numeric now supports reversed scales.

v0.45.0

Features

getAllSelections()

  • Plot.getAllSelections now take in a string or an array of strings as arguments to the API endpoint. The input should be the dataset key(s) that allow the plot to retrieve the selections associated with that dataset. If no input is given, then all selections will be retrieved as per previous behavior. If a single string is given, then only that dataset will be retrieved. If an array is given, all specified datasets will be retrieved. Invalid dataset keys are ignored.
  • areaPlot.getAllSelections now retrieves the line path elements on an areaPlot as well as the area path elements.

Dispatchers

A number of major changes have occurred on Dispatchers:

General

  • Dispatchers now use a factory pattern. Instead of invoking the constructor directly, use the static getDispatcher() method of the class.
  • Dispatchers no longer have to be connect()ed and disconnect()ed manually.

Dispatcher.Mouse

  • Dispatcher.Mouse now uses a different method of computing the mouse position. A given Dispatcher.Mouse is associated with a particular <svg> and will now account for CSS transform: scale() effects applied to that <svg> (or one of its ancestor nodes).
  • Dispatcher.Mouse will report the new mouse position relative to its <svg> every time the mouse position changes. It is up to users to confirm that this position is inside a Component of interest, using the Component's width(), height(), and originToSVG() methods.

Dispatcher.Key

  • Dispatcher.Keypress has been refactored as Dispatcher.Key.
  • Dispatcher.Key now reports keydown events that occur anywhere on the page. It can be used in conjunction with focus-testing or Dispatcher.Mouse to implement more complex behaviors.

NumericAxis

  • NumericAxis now handles inverted domains. For example, if a NumericAxis is constructed with a LinearScale with domain set as scale.domain([6, 0]), the axis will be rendered from 6 to 0, left to right.

Bugfixes

  • When Axis.Category does its space calculation, it used to report that it would only want more space if the labels did fit and would not want more space if labels did not fit... This has been corrected such that when labels that do not fit, Axis.Category will try to get more space.
  • Ticks are now only rendered on a valid domain (#1578)

API-Breaking Changes

  • There are a number of breaking changes related to Dispatchers; please see the "Upgrade Instructions" for more details:
    • constructors should no longer be invoked directly
    • connect() and disconnect() calls removed
    • mouseover(), mousemove(), and mouseout() calls removed in favor of onMouseMove() (Dispatcher.Mouse)
    • Dispatcher.Keypress renamed to Dispatcher.Key, onKeyDown now takes different arguments.
  • ResizeBroadcaster has been removed, and the resize() method of AbstractComponent has been renamed redraw(). We find that the user often has a better sense of when to redraw, and with an exposed API point for redraws, users should be able to write this implementation themselves. For example, the following is a way to replicate the original ResizeBroadcaster behavior on a pie chart that occupies the entire screen:
var plot = new Plottable.Plot.Pie().addDataset(data).project("value", "value").renderTo(svg);
window.addEventListener('resize', function(event) {
    plot.redraw();
});
  • Broadcaster now passes correctly arguments to its callbacks one at a time, rather than as an array of any[]s (#1583).

Upgrade Instructions

  • Here is the new way to use a Dispatcher.Mouse:
svgElement = d3.select("#mySVG").node(); // get the <svg>
var md = Plottable.Dispatcher.Mouse.getDispatcher(svgElement);
var callback = function(point) {
  // do something with the point
};
md.onMouseMove("callbackKey", callback);
...
md.onMouseMove("callbackKey", null); // to remove the callback
  • Here is the new way to use a Dispatcher.Key:
var kd = Plottable.Dispatcher.Key.getDispatcher();
var callback = function(keyCode) {
  if (keyCode === keyCodeOfInterest) {
    // do something;
  }
}
kd.onKeyDown("callbackKey", callback);
...
kd.onKeyDown("callbackKey", null); // to remove the callback
  • ResizeBroadcaster has been removed. An example of how to replicate its behavior:
var plot = new Plottable.Plot.Pie().addDataset(data).project("value", "value").renderTo(svg);
window.addEventListener('resize', function(event) {
    plot.redraw();
});