From 3d58c00fbeedee657ff1884719d4c247bd7a969d Mon Sep 17 00:00:00 2001 From: tsv2013 Date: Wed, 13 Mar 2024 09:34:16 +0300 Subject: [PATCH] Resolved #228 - Disable sorting for Histogram charts --- examples/histogram.js | 32 +++-- examples/summary.js | 2 +- src/histogram.ts | 45 ++++--- src/selectBase.ts | 12 +- tests/histogram.test.ts | 235 ++++++++++++++++++++------------- tests/plotly/histogram.test.ts | 6 +- 6 files changed, 196 insertions(+), 136 deletions(-) diff --git a/examples/histogram.js b/examples/histogram.js index d986e2992..6ef4d6bd7 100644 --- a/examples/histogram.js +++ b/examples/histogram.js @@ -18,7 +18,7 @@ var json = { { "type": "rating", "name": "question1", "rateValues": [{ "value": 1, "text": "15 minutes" }, { "value": 2, "text": "30 minutes" }, { "value": 3, "text": "1 hour" }] }, { "type": "text", - "name": "question1", + "name": "question2", "inputType": "number" } ] @@ -132,24 +132,32 @@ var data = [ date: "2030-10-13", age: 25 }, - { "question1": 3 } + { "question1": 3 }, + { "question1": 1 }, + { "question1": 3 }, ]; data = data.concat([ { -"question1": 15.1232432423 + "question2": 15.1232432423 }, { -"question1": 32.1435232232 - }, - { -"question1": 14.1232432423 + "question2": 32.1435232 }, { -"question1": 13.1435232232 - }, - { -"question1": 16.21000158 + "question2": 14.1232432423 + }, { + "question2": 13.1435232232 + }, { + "question2": 16.21 + }, { + "question2": 11.14352 + }, { + "question2": 11.1435232232 + }, { + "question2": 11.1435232232 + }, { + "question2": 15 }, { -"question1": 11.1435232232 + "question2": 44 }, ]); diff --git a/examples/summary.js b/examples/summary.js index 8502e99a7..7db42d897 100644 --- a/examples/summary.js +++ b/examples/summary.js @@ -59,7 +59,7 @@ var options = { // hideEmptyAnswers: true, // allowTopNAnswers: true, // showCorrectAnswers: true - // labelTruncateLength: 27, + // labelTruncateLength: 27, }; // SurveyAnalytics.WordCloudAdapter.drawOutOfBound = false; diff --git a/src/histogram.ts b/src/histogram.ts index 24b2136d8..0dc4aada6 100644 --- a/src/histogram.ts +++ b/src/histogram.ts @@ -112,19 +112,11 @@ export class HistogramModel extends SelectBase { } public getValues(): Array { - const continiousValues = this.getContiniousValues(); - if (this.hasCustomIntervals || continiousValues.length > HistogramModel.UseIntervalsFrom || this.needUseRateValues) { - return this.intervals.map(interval => interval.start); - } - return continiousValues.map(value => value.original); + return this.intervals.map(interval => interval.start); } public getLabels(): Array { - const continiousValues = this.getContiniousValues(); - if (this.hasCustomIntervals || continiousValues.length > HistogramModel.UseIntervalsFrom || this.needUseRateValues) { - return this.intervals.map(interval => interval.label); - } - return continiousValues.map(value => "" + value.original); + return this.intervals.map(interval => interval.label); } public get hasCustomIntervals() { @@ -133,16 +125,28 @@ export class HistogramModel extends SelectBase { public get intervals() { if (this.hasCustomIntervals) { - return this.questionOptions.intervals.reverse(); + return this.questionOptions.intervals; } - if (this.needUseRateValues) { - const rateValues = this.question["rateValues"] as ItemValue[]; - return rateValues.map((rateValue, i) => ({ - start: rateValue.value, - end: i < rateValues.length - 1 ? rateValues[i + 1].value : rateValue.value + 1, - label: rateValue.text - })).reverse(); + if(this.question.getType() == "rating") { + if (this.needUseRateValues) { + const rateValues = this.question["rateValues"] as ItemValue[]; + return rateValues.map((rateValue, i) => ({ + start: rateValue.value, + end: i < rateValues.length - 1 ? rateValues[i + 1].value : rateValue.value + 1, + label: rateValue.text + })); + } else { + const rateIntervals = []; + for(let i = (this.question["rateMin"] || 0); i <= (this.question["rateMax"] || (HistogramModel.IntervalsCount - 1)); i += (this.question["rateStep"] || 1)) { + rateIntervals.push({ + start: i, + end: i + 1, + label: "" + (!!this.question["rateMin"] && !!this.question["rateMax"] ? i : (i + "-" + (i+1))) + }); + } + return rateIntervals; + } } if (this._cachedIntervals === undefined) { @@ -159,7 +163,7 @@ export class HistogramModel extends SelectBase { const inext = this.toPrecision(next); this._cachedIntervals.push({ start: istart, - end: inext, + end: i < intervalsCount - 1 ? inext : inext + delta / 100, label: "" + this.getString(istart) + "-" + this.getString(inext) }); start = next; @@ -171,9 +175,6 @@ export class HistogramModel extends SelectBase { public getData() { const continiousValues = this.getContiniousValues(); - if (!this.hasCustomIntervals && continiousValues.length <= HistogramModel.UseIntervalsFrom) { - return super.getData(); - } const intervals = this.intervals; const statistics: Array> = []; const series = this.getSeriesValues(); diff --git a/src/selectBase.ts b/src/selectBase.ts index 48f77602a..8353be6f3 100644 --- a/src/selectBase.ts +++ b/src/selectBase.ts @@ -138,11 +138,7 @@ export class SelectBase return null; }); this.registerToolbarItem("changeAnswersOrder", () => { - if ( - (this.options.allowChangeAnswersOrder === undefined || - this.options.allowChangeAnswersOrder) && - this.getSeriesValues().length === 0 - ) { + if (this.isSupportAnswersOrder()) { this.choicesOrderSelector = DocumentHelper.createSelector( [ { text: localization.getString("defaultOrder"), value: "default" }, @@ -440,6 +436,12 @@ export class SelectBase this.stateChanged("topN", value); } + protected isSupportAnswersOrder(): boolean { + return (this.options.allowChangeAnswersOrder === undefined || + this.options.allowChangeAnswersOrder) && + this.getSeriesValues().length === 0; + } + protected isSupportMissingAnswers(): boolean { return true; } diff --git a/tests/histogram.test.ts b/tests/histogram.test.ts index a68d46cdb..8bcc4aff5 100644 --- a/tests/histogram.test.ts +++ b/tests/histogram.test.ts @@ -50,11 +50,12 @@ test("number default histogram", () => { const histData = number.getData(); expect(number["valueType"]).toBe("number"); - expect(histValues).toMatchObject([17, 25, 30, 40]); - expect(histLabels).toMatchObject(["17", "25", "30", "40"]); - expect(histData).toMatchObject([[3, 1, 2, 2]]); + expect(histValues).toMatchObject([17, 19.3, 21.6, 23.9, 26.2, 28.5, 30.8, 33.1, 35.4, 37.7]); + expect(histLabels).toMatchObject(["17-19.3", "19.3-21.6", "21.6-23.9", "23.9-26.2", "26.2-28.5", "28.5-30.8", "30.8-33.1", "33.1-35.4", "35.4-37.7", "37.7-40"]); + expect(histData).toMatchObject([[3, 0, 0, 1, 0, 2, 0, 0, 0, 2]]); expect(number["isSupportMissingAnswers"]()).toBeFalsy(); + expect(number["isSupportAnswersOrder"]()).toBeTruthy(); }); test("date default histogram", () => { @@ -67,11 +68,13 @@ test("date default histogram", () => { const date = new HistogramModel(question, data); const histValues = date.getValues(); + const histLabels = date.getLabels(); const histData = date.getData(); expect(date["valueType"]).toBe("date"); - expect(histValues).toMatchObject(["2004-10-13", "2011-10-13", "2016-10-13", "2021-10-13"]); - expect(histData).toMatchObject([[2, 2, 1, 3]]); + expect(histValues).toMatchObject([1097625600000, 1151271360000, 1204917120000, 1258562880000, 1312208640000, 1365854400000, 1419500160000, 1473145920000, 1526791680000, 1580437440000]); + expect(histLabels).toMatchObject(["13.10.2004-26.06.2006", "26.06.2006-07.03.2008", "07.03.2008-18.11.2009", "18.11.2009-01.08.2011", "01.08.2011-13.04.2013", "13.04.2013-25.12.2014", "25.12.2014-06.09.2016", "06.09.2016-20.05.2018", "20.05.2018-31.01.2020", "31.01.2020-13.10.2021"]); + expect(histData).toMatchObject([[2, 0, 0, 0, 2, 0, 0, 1, 0, 3]]); expect(date["isSupportMissingAnswers"]()).toBeFalsy(); }); @@ -195,19 +198,19 @@ test("number custom intervals", () => { expect(histIntervals.length).toBe(5); expect(histValues).toMatchObject([ - 70, - 19, - 14, - 7, 0, + 7, + 14, + 19, + 70 ]); expect(histData).toMatchObject([[ - 1, + 12, 11, 5, 11, - 12] - ]); + 1 + ]]); }); test("number custom intervals for small result sets", () => { @@ -235,13 +238,13 @@ test("number custom intervals for small result sets", () => { expect(histIntervals.length).toBe(5); expect(histValues).toMatchObject([ - 70, - 19, - 14, - 7, 0, + 7, + 14, + 19, + 70 ]); - expect(histData).toMatchObject([[0, 5, 3, 0, 0]]); + expect(histData).toMatchObject([[0, 0, 3, 5, 0]]); }); test("histogram series default algorithm data", () => { @@ -289,7 +292,13 @@ test("histogram series default algorithm data", () => { expect(number.getSeriesLabels()).toMatchObject(series); const chartData = number.getData(); - expect(chartData).toMatchObject([[1, 0, 0, 0], [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]); + expect(chartData).toMatchObject([ + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0, 0, 0], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 1] + ]); }); test("histogram series intervals data", () => { @@ -373,66 +382,11 @@ test("histogram series intervals data", () => { const chartData = number.getData(); expect(chartData).toMatchObject([ - [ - 1, - 0, - 0, - 1, - 0, - 0, - 1, - 0, - 0, - 0, - ], - [ - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 0, - 0, - ], - [ - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - 0, - ], - [ - 0, - 0, - 1, - 0, - 0, - 1, - 0, - 0, - 1, - 0, - ], - [ - 0, - 0, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 2, - ], + [1, 0, 0, 1, 0, 0, 1, 0, 0, 0], + [1, 0, 0, 0, 1, 0, 0, 1, 0, 0], + [1, 0, 0, 0, 1, 0, 0, 0, 1, 0], + [0, 0, 1, 0, 0, 1, 0, 0, 1, 0], + [0, 0, 1, 0, 0, 0, 1, 0, 0, 2], ]); }); @@ -451,10 +405,13 @@ test("histogram original data keep number original values", () => { getType: () => "rating", type: "rating", name: "question1", + rateMin: 1, + rateMax: 5, + rateStep: 1 }; const number = new HistogramModel(question, [{ "question2": "Yes", "question1": 3 }, { "question2": "It is going so well!!!", "question1": 5 }, { "question2": false, "question1": 5 }, { "question2": true, "question1": 1 }, { "question2": false, "question1": 5 }, { "question3": "item2", "question2": false, "question1": 5 }]); - expect(number.getValues()).toEqual([1, 3, 5]); - expect(number.getLabels()).toEqual(["1", "3", "5"]); + expect(number.getValues()).toEqual([1, 2, 3, 4, 5]); + expect(number.getLabels()).toEqual(["1", "2", "3", "4", "5"]); const selectedItem = number.getSelectedItemByText("5"); expect(selectedItem.value).toBe(5); @@ -471,9 +428,9 @@ test("histogram should use rate values", () => { const rating = new HistogramModel(survey.getAllQuestions()[0], [{ "question1": 3 }]); expect(rating.intervals).toEqual([ { - "end": 4, - "label": "1 hour", - "start": 3, + "end": 2, + "label": "15 minutes", + "start": 1, }, { "end": 3, @@ -481,18 +438,14 @@ test("histogram should use rate values", () => { "start": 2, }, { - "end": 2, - "label": "15 minutes", - "start": 1, + "end": 4, + "label": "1 hour", + "start": 3, }, ]); - expect(rating.getValues()).toEqual([3, 2, 1]); - expect(rating.getLabels()).toEqual(["1 hour", "30 minutes", "15 minutes"]); - expect(rating.getData()).toEqual([[ - 1, - 0, - 0, - ]]); + expect(rating.getValues()).toEqual([1, 2, 3]); + expect(rating.getLabels()).toEqual(["15 minutes", "30 minutes", "1 hour"]); + expect(rating.getData()).toEqual([[0, 0, 1]]); }); test("histogram intervals alignment and rounding", () => { @@ -604,7 +557,7 @@ test("histogram intervals alignment and rounding", () => { age: 25 }, { "question1": 3 } - ]; + ]; const question: any = { getType: () => "rating", type: "rating", @@ -614,3 +567,97 @@ test("histogram intervals alignment and rounding", () => { expect(number.getValues()).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); expect(number.getLabels()).toEqual(["0-1", "1-2", "2-3", "3-4", "4-5", "5-6", "6-7", "7-8", "8-9", "9-10"]); }); + +test("number histogram answers order", () => { + const question: any = { + getType: () => "text", + type: "text", + inputType: "number", + name: "question2", + }; + const number = new HistogramModel(question, [ + { + "question2": 15.1232432423 + }, { + "question2": 32.1435232 + }, { + "question2": 14.1232432423 + }, { + "question2": 13.1435232232 + }, { + "question2": 16.21 + }, { + "question2": 11.14352 + }, { + "question2": 11.1435232232 + }, { + "question2": 11.1435232232 + }, { + "question2": 15 + }, { + "question2": 44 + }, + ] as Array); + + const histValues = number.getValues(); + const histLabels = number.getLabels(); + + expect(number["valueType"]).toBe("number"); + expect(number.intervals).toEqual([ + { + "end": 14.43, + "label": "11.14-14.43", + "start": 11.14, + }, + { + "end": 17.71, + "label": "14.43-17.71", + "start": 14.43, + }, + { + "end": 21, + "label": "17.71-21", + "start": 17.71, + }, + { + "end": 24.29, + "label": "21-24.29", + "start": 21, + }, + { + "end": 27.57, + "label": "24.29-27.57", + "start": 24.29, + }, + { + "end": 30.86, + "label": "27.57-30.86", + "start": 27.57, + }, + { + "end": 34.14, + "label": "30.86-34.14", + "start": 30.86, + }, + { + "end": 37.43, + "label": "34.14-37.43", + "start": 34.14, + }, + { + "end": 40.71, + "label": "37.43-40.71", + "start": 37.43, + }, + { + "end": 44.03285648, + "label": "40.71-44", + "start": 40.71, + }, + ]); + expect(histValues).toMatchObject([11.14, 14.43, 17.71, 21, 24.29, 27.57, 30.86, 34.14, 37.43, 40.71]); + expect(histLabels).toMatchObject(["11.14-14.43", "14.43-17.71", "17.71-21", "21-24.29", "24.29-27.57", "27.57-30.86", "30.86-34.14", "34.14-37.43", "37.43-40.71", "40.71-44"]); + + const histData = number.getData(); + expect(histData).toMatchObject([[5, 3, 0, 0, 0, 0, 1, 0, 0, 1]]); +}); diff --git a/tests/plotly/histogram.test.ts b/tests/plotly/histogram.test.ts index d53c53e86..50c4e0707 100644 --- a/tests/plotly/histogram.test.ts +++ b/tests/plotly/histogram.test.ts @@ -42,7 +42,9 @@ test("getData", () => { }); const chartData = number.getData(); - expect(chartData).toMatchObject([[1, 0, 1, 0, 0], [0, 1, 0, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]]); + expect(chartData).toMatchObject([ + [1, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 1], + ]); }); test("getData - 2 rows", () => { @@ -86,5 +88,5 @@ test("getData - 2 rows", () => { }); const chartData = number.getData(); - expect(chartData).toMatchObject([[2, 0], [0, 1], [0, 1], [1, 0]]); + expect(chartData).toMatchObject([[2, 0], [0, 0], [0, 1], [0, 0], [0, 0], [0, 0], [0, 0], [0, 1], [0, 0], [1, 0]]); });