smart_arrays_plot_polyline 2.0.3 smart_arrays_plot_polyline: ^2.0.3 copied to clipboard
Plots small or big 1D arrays in form of polylines in the browser, optionally with axes and legend text. Many configuration options of the view are provided.
import 'dart:html';
import 'dart:svg';
import 'package:smart_arrays_plot_polyline/smart_arrays_plot_polyline.dart';
import 'dart:typed_data';
import 'dart:math' as math;
import 'sample_data.dart';
/// Demonstrates the usage of th package 'smart_arrays_plot_polyline' by displaying
/// two arrays (containing some periods of sin(x) and a sin(x)/x) as polylines
/// along with coordinate axes, a coordinate grid, a border and a legend.
/// This example can be directly executed via
/// 'https://smart.specpad.bplaced.net/smart_arrays_polyline/example.html'.
main() {
// Fill 2 arrays with a sinc and a sine function, to be displayed later
Float64List sinc = SampleData.genSinc(100.0, 0.0, 8, 2000, false)[1],
sine = SampleData.genSine(20.0, 0.0, 0.0, 8, 2000, false)[1];
// Set up the containers where the graphics is to be drawn
computeLayout();
// Compute the polylines for the graphical display of sinc and sine
Polyline plSinc = Polyline(sinc, 0, sinc.length - 1, dataAreaRect.width,
dataAreaRect.height, null, null, null, {PyA.YPOSITION_ZERO: "0.8"});
Polyline plSine = Polyline(sine, 0, sine.length - 1, dataAreaRect.width,
dataAreaRect.height, null, null, null, {
PyA.YPOSITION_ZERO: "0.8", // same vertical posisition as sinc
PyA.REFYMAX: "${plSinc.ymax}", // sine vertical scale is relative to sinc
PyA.STROKE: "red", // draw sine in a different color
});
// Compute x and y axis for the sinc function (sine will be relative to sinc)
computeAxes(plSinc);
// Set up a legend to be displayed in addition to the polylines
Legend legend = Legend({
LegA.TOP_TITLE: "Example for 'smart_arrays_plot_polyline'",
LegA.X: "45",
LegA.Y: "15"
}, 2);
legend.setText("1", " 20 * sin(x)", "red");
legend.setText("2", "100 * sin(x) / x", "blue");
// append sinc and sine polylines and the legend to the "data area" of the layout
dataArea.append(plSinc.polylineContainer);
dataArea.append(plSine.polylineContainer);
dataArea.append(legend.legendContainer);
// append x axis, y axis and axes grid to the "plot area" of the layout
plotArea.append(xaxis.labelsContainer);
plotArea.append(yaxis.labelsContainer);
plotArea.append(xaxis.xyGrid.gridContainer);
plotArea.append(yaxis.xyGrid.gridContainer);
}
/// These div html elements are defined in 'example.html'. [plotDiv], which is
/// embedded in [appDiv], will contain the entire graphics, taking all of the
/// remaining browser window space.
DivElement appDiv, plotDiv;
/// All graphics is drawn using SVG Scalable Vector Graphics. [plotArea] is
/// added to [plotDiv] and contains the entire plot. [dataArea] is added
/// to [plotArea] and contains the polylines and the legend. The axes are
/// drawn outside the [dataArea] but within the [plotArea].
SvgSvgElement plotArea, dataArea;
/// A frame around the 'dataArea'.
RectElement dataAreaBorder;
/// The coordinates with respect to their container
math.Rectangle<int> plotAreaRect,
dataAreaRect,
xaxisRect,
yaxisRect,
dataInsets;
/// The axes
Axis xaxis, yaxis;
/// Computes the plot layout: Sets up the graphics containers and their
/// relative coordinates and sizes.
void computeLayout() {
// get divs from 'example.html'
appDiv = (querySelector("#app_div") as DivElement);
plotDiv = (querySelector("#plot_div") as DivElement);
// the plot takes all available space
plotDiv.style
..width = "${appDiv.clientWidth}px"
..height = "${appDiv.clientHeight}px";
// Reserve space in pixels for the axes labels and a border around everthing.
int xaxAreaHeight = 70, yaxAreaWidth = 80, borderAreaSize = 15;
// will contain the entire plot
plotAreaRect = math.Rectangle<int>(
borderAreaSize,
borderAreaSize,
plotDiv.clientWidth - 2 * borderAreaSize,
plotDiv.clientHeight - 2 * borderAreaSize);
// all coordinates in the following rectangles are are relative to plotRect
dataInsets = math.Rectangle<int>(borderAreaSize, borderAreaSize, 0, 0);
// will contain the polylines and the legend
dataAreaRect = math.Rectangle<int>(
yaxAreaWidth,
dataInsets.top,
plotAreaRect.width - yaxAreaWidth - dataInsets.left,
plotAreaRect.height - xaxAreaHeight);
// will contain the x axis tic marks and text labels
xaxisRect = math.Rectangle<int>(
dataAreaRect.left,
dataAreaRect.top + dataAreaRect.height,
dataAreaRect.width,
xaxAreaHeight);
// will contain the y axis tic marks and text labels
yaxisRect = math.Rectangle<int>(dataAreaRect.left - yaxAreaWidth,
dataAreaRect.top, yaxAreaWidth, dataAreaRect.height);
// will contain all axes and the data area (polylines and legend)
plotArea = new SvgSvgElement();
SVG.setAttr(plotArea, {
SVG.WIDTH: "${plotAreaRect.width}",
SVG.HEIGHT: "${plotAreaRect.height}",
});
// will contain polylines and legend
dataArea = new SvgSvgElement();
SVG.setAttr(dataArea, {
SVG.X: "${dataAreaRect.left}",
SVG.Y: "${dataAreaRect.top}",
SVG.WIDTH: "${dataAreaRect.width}",
SVG.HEIGHT: "${dataAreaRect.height}",
});
// a border around the data area
dataAreaBorder = new RectElement();
SVG.setAttr(dataAreaBorder, {
SVG.X: "${dataAreaRect.left}",
SVG.Y: "${dataAreaRect.top}",
SVG.WIDTH: "${dataAreaRect.width}",
SVG.HEIGHT: "${dataAreaRect.height}",
SVG.FILL: "none",
SVG.STROKE: "darkgreen",
SVG.STROKE_WIDTH: "2"
});
// now stack the plot containers.
plotDiv.append(plotArea);
plotArea.append(dataArea);
plotArea.append(dataAreaBorder); // draw above dataArea
} // computeLayout()
/// Computes x and y axes for [polyline]
void computeAxes(Polyline polyline) {
// compute x axis
xaxis = Axis.coord(
polyline.array.length, // # points in the polyline's data array
polyline.xValues.first, // display the array from this index
polyline.xValues.last, // until this index
0, // physical unit of 1st point: we choose the point number here.
(polyline.array.length - 1).toDouble(), // phys. axis width, in points
true, // mode for converting point index to physical unit
null, // no extra calibration factor of axis labels
dataAreaRect.width, // axis length in pixels
xaxisRect.height, // height of axis area (reserves space for the labels)
dataAreaRect.height, // grid line length, needed if 'grid' chosen
"point number", // x axis legend text
"bg", // axis at "b" bottom of data area, with a "g" grid, not reversed
polyline.xphysToXscreen, // method converting physical to screen coord.
{
AxA.XYGRID_STROKE: "pink",
AxA.XYGRID_STROKE_OPACITY: "1.0",
AxA.XYGRID_STROKE_DASH: "10"
}, // x grid color different from default
null // no mouse or touch interaction in this example
);
// set the x axis container positions as computed by [computeLayout].
SVG.setAttr(xaxis.labelsContainer, {
SVG.X: "${xaxisRect.left - xaxis.extra_space_for_edge_labels_x}",
SVG.Y: "${xaxisRect.top}"
});
// set the x axis grid container positions as computed by [computeLayout].
SVG.setAttr(xaxis.xyGrid.gridContainer,
{SVG.X: "${dataAreaRect.left}", SVG.Y: "${dataAreaRect.top}"});
// compute y axis (intensity axis)
double firstY = polyline.yScreenToYphys(0);
double lastY = polyline.yScreenToYphys(dataAreaRect.height);
if (firstY == null) firstY = polyline.ymin;
if (lastY == null) lastY = polyline.ymax;
yaxis = Axis.intens(
firstY / polyline.yscale, // axis range, account for [PyA.YSCALE]
lastY / polyline.yscale,
null, // no rescaling of y axis
null, // like above, no rescaling of y axis
null, // would only relevant for reversed axis
dataAreaRect.height, // axis length in pixels
yaxisRect.width, // height of axis area (reserves space for the labels)
dataAreaRect.width, // grid line length, needed if 'grid' chosen
"function value",
"bg", // "b"=position left of data area, "g"= with a grid
polyline.yphysToYscreen, // method converting physical to screen coord.
null, // no extra axis attributes specfied here
null // no mouse or touch interaction in this example
);
// set the y axis container positions as computed by [computeLayout].
SVG.setAttr(yaxis.labelsContainer, {
SVG.X: "${yaxisRect.left}",
SVG.Y: "${yaxisRect.top - yaxis.extra_space_for_edge_labels_y}"
});
// set the y axis grid container positions as computed by [computeLayout].
SVG.setAttr(yaxis.xyGrid.gridContainer,
{SVG.X: "${dataAreaRect.left}", SVG.Y: "${dataAreaRect.top}"});
}
copied to clipboard