Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/piechart #168

Open
wants to merge 35 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e2280d1
Ajout class Pie
Tanguylo Jun 3, 2022
d83ec07
Start with piechart
Tanguylo Jun 7, 2022
d5b2e4b
feat(piechart): first piechart drawing
Tanguylo Jun 7, 2022
b4514ea
feat(piechart): add colors to piechart
Tanguylo Jun 8, 2022
e21e984
feat(piechart):add pie part surface coloring on mouse over
Tanguylo Jun 13, 2022
949df9c
feat(piechart):partial code cleaning
Tanguylo Jun 13, 2022
8427fef
feat(piechart):fix a git mistake with branches
Tanguylo Jun 13, 2022
e21259e
feat(piechart):fixing last diff in core.py
Tanguylo Jun 13, 2022
ad59106
feat(piechart):remove ' /' line 931
Tanguylo Jun 13, 2022
6c494e2
feat(piechart):add parts selection on click
Tanguylo Jun 14, 2022
9c83b56
feat(piechart):manage piepart paths as piepart attribute
Tanguylo Jun 14, 2022
38ebcb3
feat(piechart):initialize pieparts path when instantiating when crea…
Tanguylo Jun 14, 2022
1937904
feat(piechart):some code cleaning
Tanguylo Jun 17, 2022
4675ede
feat(piechart): fix mistakes following the first 6 comments on this p…
Tanguylo Jun 21, 2022
cd1864f
feat(piechart): fix the 5 following remarks of the PR
Tanguylo Jun 21, 2022
1f81acc
feat(piechart): fix the remaining remarks except the drawPieChart method
Tanguylo Jun 21, 2022
e3371ec
feat(piechart): take last PR remarks into account
Tanguylo Jun 21, 2022
84fe419
feat(piechart): change type of color_to_plot_data to map
Tanguylo Jun 22, 2022
8bf219a
feat(piechart): modifications following PR remarks
Tanguylo Jun 22, 2022
006de63
feat(piechart): Changes following the PR review
Tanguylo Jun 24, 2022
3cea6f1
feat(piechart): Put color:string='' in the constructor of PieParts fo…
Tanguylo Jun 24, 2022
174b386
feat(piechart_in_multiplot): Handle selection of piePart as expected
Tanguylo Jun 24, 2022
0413f2f
feat(piechart): add commit to branch and reset latest_selected_points…
Tanguylo Jun 27, 2022
87d5ef6
feat(piechart): Undo color_to_plot_data as a Map
Tanguylo Jun 27, 2022
10772ba
feat(piechart): Changes following second PR
Tanguylo Jun 27, 2022
34cdd69
feat(piechart): DataSample and DataSamples type definition and some c…
Tanguylo Jun 27, 2022
7a5f0e6
feat(piechart): Changes in drawPieChart
Tanguylo Jun 28, 2022
54091b1
feat(piechart): Change multiple_plot.py file
Tanguylo Jun 28, 2022
0ecc993
feat(piechart): Call definePieParts in PieChart constructor and not a…
Tanguylo Jun 28, 2022
5c7c296
feat(piechart): Write PR equivalent in CHANGELOG.md file
Tanguylo Jun 28, 2022
b4bc6e2
Merge branch 'dev' into feat/piechart
Tanguylo Feb 28, 2023
ce09723
merge since 6 months, possible fails
Tanguylo Feb 28, 2023
9896338
Merge branch 'dev' into feat/piechart
Tanguylo Feb 28, 2023
2187adf
feat(piechart): add tests
Tanguylo Feb 28, 2023
f8f4b8a
feat(piechart): pylint
Tanguylo Mar 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 1 addition & 35 deletions src/plot-data.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { heatmap_color, string_to_hex } from "./color_conversion";
import { Point2D, PrimitiveGroup, Contour2D, Circle2D, Dataset, Graph2D, Scatter, Heatmap, Wire, PieChart } from "./primitives";
import { Point2D, PrimitiveGroup, Contour2D, Circle2D, Dataset, Graph2D, Scatter, Heatmap, Wire } from "./primitives";
import { Attribute, PointFamily, Axis, Tooltip, Sort, permutator } from "./utils";
import { EdgeStyle } from "./style";
import { Shape, List, MyMath } from "./toolbox";
Expand Down Expand Up @@ -774,40 +774,6 @@ export abstract class PlotData {
}
}


drawPiechart(d: PieChart, hidden: boolean, mvx: number, mvy: number): void {
const colorRatio: number = 360 / d.pieParts.length;
let colorRadius: number = 0;
this.context.lineWidth = 0.5;

for (let part of d.pieParts) {
colorRadius += colorRatio;

if (hidden) {
this.context.strokeStyle = part.hidden_color;
this.context.fillStyle = part.hidden_color;
} else {
if (part.clicked){
d.pieParts.forEach(piepart => piepart.clicked = false);
part.clicked = true;
}
if (part.clicked && this.select_on_mouse !== part) {
part.color = this.color_surface_on_click;

} else if (this.select_on_mouse === part) {
part.color = this.color_surface_on_mouse;

} else {
part.color = 'hsl('+ colorRadius +', 50%, 50%, 90%)';
}
this.context.fillStyle = part.color;
this.context.strokeStyle = part.color;
}
part.draw(this.context, mvx, mvy, this.scaleX, this.X, this.Y);
}
}


get_point_order() {
var point_order = [];
for (let i = 0; i < this.point_families.length; i++) {
Expand Down
61 changes: 37 additions & 24 deletions src/primitives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -934,7 +934,7 @@ export class PieChart {
pieParts: Array<PiePart>=[];

constructor(public slicingVariable: string,
public dataSamples: Map<string, any>,
public dataSamples: Array<Object>,
xavier-ferry marked this conversation as resolved.
Show resolved Hide resolved
public name: string
) {}

Expand All @@ -944,7 +944,7 @@ export class PieChart {
serialized['name']);
}

private computeTotalSample(): number {
private computeNormedRatio(): number {
xavier-ferry marked this conversation as resolved.
Show resolved Hide resolved
let sumSamples: number = 0;
let normedRatio: number = 2*Math.PI;

Expand All @@ -955,76 +955,89 @@ export class PieChart {
return normedRatio
}

definePieParts(center: [number, number], radius: number): PiePart[] {
definePieParts(radius: number): PiePart[] {
let initAngle: number = Math.PI/2;
let nextAngle: number = initAngle;
const colorRatio: number = 360 / this.dataSamples.length;
let colorRadius: number = 0;
let pieParts: PiePart[] = [];

let normedRatio = this.computeTotalSample();
let normedRatio = this.computeNormedRatio();
this.dataSamples.forEach(sample => {
colorRadius += colorRatio;
nextAngle -= sample[this.slicingVariable] * normedRatio;
pieParts.push(new PiePart(center[0], center[1], radius, initAngle, nextAngle, true));

let newPart = new PiePart(radius, initAngle, nextAngle);
newPart.color = 'hsl('+ colorRadius +', 50%, 50%, 90%)';
pieParts.push(newPart);

initAngle = nextAngle;
})
return pieParts
}
}


export class PiePart {
hidden_color: string = '';
isMouseOver: boolean = false;
isSelected: boolean = false;
path: Path2D;
clicked: boolean = false;
color: string = '';
readonly overfliedColor: string = string_to_hex('lightskyblue');
xavier-ferry marked this conversation as resolved.
Show resolved Hide resolved
readonly selectedColor: string = string_to_hex("red");
readonly center: [number, number] = [0, 0];
xavier-ferry marked this conversation as resolved.
Show resolved Hide resolved

/**
* @param centerX the center x coordinate
* @param centerY the center y coordinate
* @param center the center coordinates [x, y]
xavier-ferry marked this conversation as resolved.
Show resolved Hide resolved
* @param radius radius
* @param initAngle in radian
* @param endAngle in radian
* @param anticlockwise true or false whether you want the arc the be drawn anticlockwise or not.
*/
constructor(
public centerX: number,
public centerY: number,
public radius: number,
public initAngle: number, // Warning: canvas' angles are clockwise-oriented. For example: pi/2 rad is below -pi/2 rad.
public endAngle: number,
public anticlockwise: boolean = true,
public name: string = '')
public endAngle: number)
{
this.hidden_color = genColor();
this.path = this.buildPath();
}

private buildPath(): Path2D {
const path = new Path2D();
path.moveTo(this.centerX, this.centerY);
path.moveTo(this.center[0], this.center[1]);
path.arc(
this.centerX,
this.centerY,
this.center[0],
this.center[1],
this.radius,
this.initAngle,
this.endAngle,
this.anticlockwise);
true);
return path
}

draw(context: CanvasRenderingContext2D, mvx: number, mvy: number, scale: number, X: number, Y: number): void {
/**
* @param mvx x coordinate of the local frame in the canvas
* @param mvy y coordinate of the local frame in the canvas
* @param mvx x coordinate of the local frame in the canvas (center of the screen relatively to the canvas' high left corner)
* @param mvy y coordinate of the local frame in the canvas (center of the screen relatively to the canvas' high left corner)
* @param scale ratio applied on data coordinates to manage mouse scrolling
* @param X x coordinate of the absolute frame (the canvas' one)
* @param Y y coordinate of the absolute frame (the canvas' one)
* @param X x coordinate of the offset of the drawing zone (0 if not in multiplot)
* @param Y y coordinate of the offset of the drawing zone (0 if not in multiplot)
*/
const matrix = context.getTransform();
context.transform(scale, 0, 0, scale, mvx + X, mvy + Y);
xavier-ferry marked this conversation as resolved.
Show resolved Hide resolved
context.stroke(this.path);
context.fill(this.path);
context.setTransform(matrix);
}

assignColor(select_on_mouse: PiePart): string {
xavier-ferry marked this conversation as resolved.
Show resolved Hide resolved
let color: string = this.color;
if (this.clicked && select_on_mouse !== this) {
color = this.selectedColor;
} else if (this.clicked && select_on_mouse === this) {
color = this.selectedColor;
} else if (!this.clicked && select_on_mouse === this) {
color = this.overfliedColor;
}
return color
}
}
149 changes: 89 additions & 60 deletions src/subplots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,9 @@ export class PlotScatter extends PlotData {

/** A class that inherits from PlotData and is specific for drawing ScatterPlots and Graph2Ds
*/
export class PlotPieChart extends PlotData {
clickedParts: Array<boolean> = [];
canvas: HTMLCanvasElement = null;
readOnly: boolean = true;

export class PlotPieChart extends PlotData {
public constructor(
public data:any,
public data: Array<Object>,
public width: number,
public height: number,
public buttons_ON: boolean,
Expand All @@ -269,85 +265,118 @@ export class PlotPieChart extends PlotData {
this.selected_areas = [];
this.refresh_MinMax();
this.plotObject = PieChart.deserialize(data);
this.plotObject.pieParts = this.plotObject.definePieParts([0, 0], this.height * 0.475);
this.plotObject.pieParts = this.plotObject.definePieParts(this.height * 0.475);
this.color_to_plot_data = this.initHiddenColors()
}

private initHiddenColors(): Map<string,PiePart> {
let hiddenColorsList: Map<string,PiePart> = new Map();
this.plotObject.pieParts.forEach(
part => {hiddenColorsList.set(part.hidden_color, part);})
return hiddenColorsList
}

refresh_MinMax(): void {
this.minX = -this.width / 2;
this.maxX = this.width / 2;
this.minY = -this.height / 2;
this.maxY = this.height / 2;
}

private drawPiechart(d: PieChart, mvx: number, mvy: number): void {
this.context_hidden.lineWidth = 0.5 / this.scaleX;
this.context_show.lineWidth = 0.5 / this.scaleY;
for (let part of d.pieParts) {
if (part.clicked) {
xavier-ferry marked this conversation as resolved.
Show resolved Hide resolved
d.pieParts.forEach(piepart => piepart.clicked = false);
part.clicked = true;
}
this.context_show.fillStyle = part.assignColor(this.select_on_mouse);
this.context_show.strokeStyle = this.context_show.fillStyle
this.context_hidden.strokeStyle = part.hidden_color;
this.context_hidden.fillStyle = part.hidden_color;

part.draw(this.context_show, mvx, mvy, this.scaleX, this.X, this.Y);
part.draw(this.context_hidden, mvx, mvy, this.scaleX, this.X, this.Y);
}
}

draw(): void {
this.draw_from_context(false);
this.draw_from_context(true);
this.drawCanvas()
this.drawPiechart(this.plotObject, this.originX, this.originY);
this.drawSiders();
this.context_hidden.restore();
this.context_show.restore();
}

private initHiddenColors(): Map<string,PiePart> {
let hiddenColorsList: Map<string,PiePart> = new Map();
this.plotObject.pieParts.forEach(
part => {hiddenColorsList.set(part.hidden_color, part);})
return hiddenColorsList
private drawCanvas(): void {
for (let context of [this.context_show, this.context_hidden]) {
context.save()
this.draw_empty_canvas(context);
this.context = context;
if (this.settings_on) {
this.draw_settings_rect();
} else {
this.draw_rect();
}
context.beginPath();
context.rect(this.X-1, this.Y-1, this.width+2, this.height+2);
context.clip();
context.closePath();
}
}

draw_from_context(hidden: boolean): void {
this.define_context(hidden);
this.context.save();
this.draw_empty_canvas(this.context);
if (this.settings_on) {
this.draw_settings_rect();
} else {
this.draw_rect();
}
this.context.beginPath();
this.context.rect(this.X-1, this.Y-1, this.width+2, this.height+2);
this.context.clip();
this.context.closePath();
this.drawPiechart(this.plotObject, hidden, this.originX, this.originY);
if (this.permanent_window) {
this.draw_selection_rectangle();
}
if (this.zw_bool || (this.isSelecting && !this.permanent_window)) {
this.draw_zoom_rectangle();
private drawSiders(): void {
for (let context of [this.context_hidden, this.context_show]) {
this.context = context;
if (this.permanent_window) {
this.draw_selection_rectangle();
}
if (this.zw_bool || (this.isSelecting && !this.permanent_window)) {
this.draw_zoom_rectangle();
}
if ((this.buttons_ON) && (this.button_w > 20) && (this.button_h > 10)) {
this.drawButtons();
}
if (this.multiplot_manipulation) {
this.draw_manipulable_rect();
}
}
}

if ((this.buttons_ON) && (this.button_w > 20) && (this.button_h > 10)) {
this.refresh_buttons_coords();
private drawButtons(): void {
this.refresh_buttons_coords();
//Drawing the zooming button
Buttons.zoom_button(this.button_x, this.zoom_rect_y, this.button_w, this.button_h, this);

//Drawing the zooming button
Buttons.zoom_button(this.button_x, this.zoom_rect_y, this.button_w, this.button_h, this);
//Drawing the button for zooming window selection
Buttons.zoom_window_button(this.button_x,this.zw_y,this.button_w,this.button_h, this);

//Drawing the button for zooming window selection
Buttons.zoom_window_button(this.button_x,this.zw_y,this.button_w,this.button_h, this);
//Drawing the reset button
Buttons.reset_button(this.button_x, this.reset_rect_y, this.button_w, this.button_h, this);

//Drawing the reset button
Buttons.reset_button(this.button_x, this.reset_rect_y, this.button_w, this.button_h, this);
//Drawing the selection button
Buttons.selection_button(this.button_x, this.select_y, this.button_w, this.button_h, this);

//Drawing the selection button
Buttons.selection_button(this.button_x, this.select_y, this.button_w, this.button_h, this);
//Drawing the enable/disable graph button
Buttons.graph_buttons(this.graph1_button_y, this.graph1_button_w, this.graph1_button_h, '10px Arial', this);

//Drawing the enable/disable graph button
Buttons.graph_buttons(this.graph1_button_y, this.graph1_button_w, this.graph1_button_h, '10px Arial', this);
//draw permanent window button
Buttons.perm_window_button(this.button_x, this.perm_button_y, this.button_w, this.button_h, '10px Arial', this);

//draw permanent window button
Buttons.perm_window_button(this.button_x, this.perm_button_y, this.button_w, this.button_h, '10px Arial', this);
//draw clear point button
Buttons.clear_point_button(this.button_x, this.clear_point_button_y, this.button_w, this.button_h, '10px Arial', this);

//draw clear point button
Buttons.clear_point_button(this.button_x, this.clear_point_button_y, this.button_w, this.button_h, '10px Arial', this);
// Draw log scale buttons
Buttons.log_scale_buttons(this.button_x, this.xlog_button_y, this.ylog_button_y, this.button_w, this.button_h,
"10px Arial", this);

// Draw Heatmap button
Buttons.heatmap_button(this.button_x, this.heatmap_button_y, this.button_w, this.button_h, "10px Arial", this);
}

// Draw log scale buttons
Buttons.log_scale_buttons(this.button_x, this.xlog_button_y, this.ylog_button_y, this.button_w, this.button_h,
"10px Arial", this);

// Draw Heatmap button
Buttons.heatmap_button(this.button_x, this.heatmap_button_y, this.button_w, this.button_h, "10px Arial", this);
}
if (this.multiplot_manipulation) {
this.draw_manipulable_rect();
}
this.context.restore();
draw_from_context(hidden: any) {
xavier-ferry marked this conversation as resolved.
Show resolved Hide resolved
return
}
}

Expand Down