Automated scheduled reporting in Sisense
Struggling with Sisense's default reporting limitations? From complex Python scripts to evolving low-code platforms, we've explored it all. Discover how we went from custom coding to streamlined, user-friendly solutions that fit every need.1.8KViews9likes2CommentsAnalysing EC Builds
I was looking for a way to analyse EC Builds in an easy way to identify where potential bottlenecks within the buildprocess could be. I have created a python script which exports EC build logs (can only export latest build logs) to JSON and converts these into CSVs which can be imported into an ElastiCube. So I have created a simple dashboard and EC-model. Feel free to adjust to your own needs and perhaps share them so I can learn aswell 🙂 (Do not forget to change the folder in de CSV-connection to the folder where you saved your CSVs) Download ECmodel + Dashboard: LINK Download Python: LINK Configure the settings.yml file with your admin credentials and sisense url. I am not a python-king so adjust freely if you see something thats worth improving.3.6KViews7likes1CommentColumn chart to WordCloud
Here is a script to convert a Column chart to WordCloud chart Reference: https://www.binextlevel.com/post/wordcloud-from-column-chart Create a Column chart. It should contain only one field as category and one Value panel and apply below script. (function(m) { "object" === typeof module && module.exports ? module.exports = m : m(Highcharts) })(function(m) { var w = function() { return function(d) { var n = this, k = n.graphic, p = d.animate, m = d.attr, q = d.onComplete, z = d.css, r = d.group, v = d.renderer, D = d.shapeArgs; d = d.shapeType; n.shouldDraw() ? (k || (n.graphic = k = v[d](D).add(r)), k.css(z).attr(m).animate(p, void 0, q)) : k && k.animate(p, void 0, function() { n.graphic = k = k.destroy(); "function" === typeof q && q() }); k && k.addClass(n.getClassName(), !0) } }(); (function(d, n) { var k = d.each, p = d.extend, m = d.isArray, q = d.isNumber, z = d.isObject, r = d.Series, v = function(a, b) { return !(b.left > a.right || b.right < a.left || b.top > a.bottom || b.bottom < a.top) }, D = function(a, b) { var c = !1, g = a.rect, f; a.lastCollidedWith && (f = a.lastCollidedWith.rect, (c = v(g, f)) || delete a.lastCollidedWith); c || (c = !!d.find(b, function(b) { var c; f = b.rect; if (c = v(g, f)) a.lastCollidedWith = b; return c })); return c }, B = function(a) { var b = Math.ceil((Math.sqrt(a) - 1) / 2), c = 2 * b + 1, g = Math.pow(c, 2), f = !1, c = c - 1; 1E4 >= a && ("boolean" === typeof f && a >= g - c && (f = { x: b - (g - a), y: -b }), g -= c, "boolean" === typeof f && a >= g - c && (f = { x: -b, y: -b + (g - a) }), g -= c, "boolean" === typeof f && (f = a >= g - c ? { x: -b + (g - a), y: b } : { x: b, y: b - (g - a - c) }), f.x *= 5, f.y *= 5); return f }, w = function(a, b) { a /= b; return { width: 256 * a, height: 256, ratio: a } }, C = function(a, b, c) { return b + (c - b) / (a - 1) * Math.floor(Math.random() * a) }, G = function(a, b) { a = a.getBBox(); var c = b.width / 2, g = -(b.height / 2), f = b.height / 2; return !(-(b.width / 2) < a.x && c > a.x + a.width && g < a.y && f > a.y + a.height) }; d.seriesType("wordcloud", "column", { animation: { duration: 500 }, borderWidth: 0, clip: !1, colorByPoint: !0, placementStrategy: "center", rotation: { from: 0, orientations: 2, to: 90 }, showInLegend: !1, spiral: "rectangular", style: { fontFamily: "sans-serif", fontWeight: "900" }, tooltip: { followPointer: !0, pointFormat: '\x3cspan style\x3d"color:{point.color}"\x3e\u25cf\x3c/span\x3e {series.name}: \x3cb\x3e{point.weight}\x3c/b\x3e\x3cbr/\x3e' } }, { animate: r.prototype.animate, bindAxes: function() { var a = { endOnTick: !1, gridLineWidth: 0, lineWidth: 0, maxPadding: 0, startOnTick: !1, title: null, tickPositions: [] }; r.prototype.bindAxes.call(this); p(this.yAxis.options, a); p(this.xAxis.options, a) }, deriveFontSize: function(a) { return Math.floor(25 * a) }, drawPoints: function() { var a = this, b = a.hasRendered, c = a.xAxis, g = a.yAxis, f = a.group, d = a.options, m = d.animation, n = a.chart.renderer, A = n.text().add(f), r = [], v = a.placementStrategy[d.placementStrategy], B = a.spirals[d.spiral], C = d.rotation, H = a.points.map(function(a) { return a.weight }), I = Math.max.apply(null, H), t = w(c.len, g.len), E = a.points.sort(function(a, b) { return b.weight - a.weight }); k(E, function(c) { var g = p({ fontSize: a.deriveFontSize(1 / I * c.weight) + "px", fill: c.color }, d.style), l = v(c, { data: E, field: t, placed: r, rotation: C }), h = { align: "center", x: l.x, y: l.y, text: c.name, rotation: l.rotation }, k, x, e; A.css(g).attr(h); c.clientRect = e = p({}, A.element.getBoundingClientRect()); x = A; for (var w = t, F = 1, y = { x: 0, y: 0 }, u = c.rect = p({}, e); (D(c, r) || G(x, w)) && !1 !== y;) y = B(F, { field: w }), z(y) && (u.left = e.left + y.x, u.right = u.left + u.width, u.top = e.top + y.y, u.bottom = u.top + u.height), F++; x = y; if (z(x)) { h.x += x.x; h.y += x.y; p(l, { left: h.x - e.width / 2, right: h.x + e.width / 2, top: h.y - e.height / 2, bottom: h.y + e.height / 2 }); e = t; if (!q(e.left) || e.left > l.left) e.left = l.left; if (!q(e.right) || e.right < l.right) e.right = l.right; if (!q(e.top) || e.top > l.top) e.top = l.top; if (!q(e.bottom) || e.bottom < l.bottom) e.bottom = l.bottom; t = e; r.push(c); c.isNull = !1 } else c.isNull = !0; m && (k = { x: h.x, y: h.y }, b ? (delete h.x, delete h.y) : (h.x = 0, h.y = 0)); c.draw({ animate: k, attr: h, css: g, group: f, renderer: n, shapeArgs: void 0, shapeType: "text" }) }); A = A.destroy(); c = Math.min(1 / (2 * Math.max(Math.abs(t.left), Math.abs(t.right))) * c.len, 1 / (2 * Math.max(Math.abs(t.top), Math.abs(t.bottom))) * g.len); a.group.attr({ scaleX: c, scaleY: c }) }, hasData: function() { return z(this) && !0 === this.visible && m(this.points) && 0 < this.points.length }, placementStrategy: { random: function(a, b) { a = b.field; b = b.rotation; return { x: Math.round(a.width * (Math.random() + .5) / 2) - a.width / 2, y: Math.round(a.height * (Math.random() + .5) / 2) - a.height / 2, rotation: C(b.orientations, b.from, b.to) } }, center: function(a, b) { a = b.rotation; return { x: 0, y: 0, rotation: C(a.orientations, a.from, a.to) } } }, pointArrayMap: ["weight"], spirals: { archimedean: function(a, b) { var c = b.field; b = !1; var c = c.width * c.width + c.height * c.height, d = .2 * a; 1E4 >= a && (b = { x: d * Math.cos(d), y: d * Math.sin(d) }, Math.min(Math.abs(b.x), Math.abs(b.y)) < c || (b = !1)); return b }, rectangular: function(a, b) { a = B(a, b); b = b.field; a && (a.x *= b.ratio); return a }, square: B }, getPlotBox: function() { var a = this.chart, b = a.inverted, c = this[b ? "yAxis" : "xAxis"], b = this[b ? "xAxis" : "yAxis"]; return { translateX: (c ? c.left : a.plotLeft) + (c ? c.len : a.plotWidth) / 2, translateY: (b ? b.top : a.plotTop) + (b ? b.len : a.plotHeight) / 2, scaleX: 1, scaleY: 1 } } }, { draw: n, shouldDraw: function() { return !this.isNull } }) })(m, w) }); widget.on('processresult', function(widget,ev) { ev.result.chart.type = 'wordcloud' ev.result.plotOptions['wordcloud'] = ev.result.plotOptions['column'] delete ev.result.plotOptions['column'] ev.result.tooltip.enabled = true ev.result.plotOptions.wordcloud.rotation = {orientations:0} wordCloudArr = [] $.each(ev.result.series[0].data, function(index, value){ value.weight = value.y wordCloudArr.push({'name':value.selectionData[0], 'weight':value.y}) }) ev.result.series[0].data = wordCloudArr }) widget.on('beforedatapointtooltip', function(widget,ev) { ev.cancel = true }) -Hari4.9KViews6likes5CommentsDisplay widget in tooltip
By default values and labels are displayed in tooltip. Also its possible to add additional information to tooltip by using script . Sometimes it would be more helpful to display a widget as tooltip (Reference) Steps: Create base chart - the chart in which we need to add tooltip. Create a dashboard and add a widget that needs to be displayed as tooltip. Size of widget in this dashboard should be small enough to fit in to the tooltip. Add below script to base chart and update the variable 'dashboaardurl' with URL of dashboard we created for tooltip. var category widget.on('beforedatapointtooltip', function(se, ev){ dashboardurl = 'https://XXXX.sisense.com/app/main#/dashboards/6612346ac77683002ea37645' redrawYN = category != ev.context.category category = ev.context.category filterPanel = ev.widget.metadata.panels[0].items[0].jaql filterPanel.filter = { explicit: true, members: [category], multiSelection: true } filterjaql = {jaql: filterPanel} var filtersArray = [filterjaql]; var filterString = JSON.stringify(filtersArray); var uriEncoded = encodeURIComponent(filterString); ev.template = `<iframe width="100%" frameborder="0" src="${dashboardurl}?embed=true&r=false&filter=${uriEncoded}"></iframe>` if(redrawYN) se.redraw() }) Note: Supported widget - Line chart, Column chart, Bar chart, Pie chart Currently this script doesn't support widget with 'breakby' panel. Tooltip may take few seconds to load as it is actually a dashboard. -Hari4.7KViews6likes3CommentsJump to Dashboard arrow mark superimposed with widget title
Hi Team, I have created a Jump to Dashboard from a widget. However, I am seeing from couple of months that the arrow signal specifying the JTD widget is now superimposed with the title of the widget leaving it very clumsy. Any help regarding the same will be very helpful.2.8KViews5likes4CommentsBar Chart - Add Percentage to the Value Label
When creating a column chart you might want to add a percentage value next to the actual value Add the following script to your widget: widget.on('processresult', function(widget,result) { result.result.plotOptions.series.dataLabels.formatter = function() { total = 0 this.series.data.forEach(function(datapoint) { total += datapoint.y }) percent = (100 * this.y) / (total); percent = percent.toFixed(1); return this.y + '<br/>(' + percent + '%)' } }) Before After2.7KViews5likes3CommentsImplementing Self-Service BI with Sisense: Key Steps and Insights
Discover how our team transformed a backlog of data requests into a seamless self-serve BI platform using Sisense. From gathering requirements to ensuring robust data security, we share our journey and the key steps to empower stakeholders with easy access to the insights they need. Learn how to leverage Sisense for a more efficient and effective BI solution.2.2KViews5likes3CommentsThe Sisense Widgetscript Library
Hey Hey, There have been a lot of widgetscripts written to solve certain challenges in Sisense. It can sometimes be a hassle to find the right one and also know if they still work. For this reason I have created this post. This way we can create a nice overview of widget scripts 🙂 Things to keep in consideration Every script has a description, a link to the original post and a working with version X (to determine if it works for certain versions of Sisense) If you have a script you would like on this list, reply to this post with the name, description and a link to the original post (if it is your script or it does not exist, create a post) If you have a question regarding the script, please click the link to go to the original post and ask your question there. This way we can keep this post clean 🙂 Scripts: Title Description Link Works in version Filter buttons in widget A widgetscript that adds filter buttons to a widget for users to easily filter the chart Link L2024.2 Format pivot2 fonts A script to format pivot fonts (size, color etc) Link L2024.2 Using BloX To Dynamically Change A Dimension Using BloX To Dynamically Change A Dimension Link L2024.2 Flip Legend on Stacked Bar Chart Link L2024.2 Highlight Max and Min values in Line chart Sometimes line chart contains more value points and it wont be readable if we enable the value labels. But it would be a nice feature to highlight minimum and maximum value in the chart to get a better understanding of value range in it. Link L2024.2 Remove a pre-defined filter option from the list Link L2024.1972Views5likes0Comments