Custom sort for Bar and Column Chart
Custom sort for Bar and Column Chart Question: I have seen several posts of people asking if there is a simple way to apply custom sorts for car and column charts, and until recently, I have been using the community customBarColumnChart Plugin, which is not supported anymore, and also not working correctly in the latest version of Sisense cloud. Not sure why this cannot become a standard feature within the system, as there seem to be a lot of requests for this functionality. Answer: The following widget scripts will allow you to sort categories in a bar/column chart. You can change the order of items in sortOrder to change the order. They cater to when you want to sort by a Break By, or when you want to sort by Categories with no Break By. BREAK BY: widget.on('processresult', (w, args) => { var sortOrder = ['Yellow', 'Black', 'Red', 'Blue ', 'Gold', 'Silver'] args.result.series.sort(function (a, b) { return sortOrder.indexOf(a.name) - sortOrder.indexOf(b.name) }) }) The configuration is also attached in a screenshot below: ALT Text: A bar chart displaying total order quantities by region. Two regions are represented: Europe and USA. Each region has bars segmented by color: yellow, blue, black, gold, red, and silver. The chart highlights comparisons in order quantities between the two regions, with specific quantities not indicated in the image. CATEGORIES: If you're aiming to sort by the Categories directly, then you can use the following instead: widget.on('processresult', (w, args) => { var sortOrder = ['USA', 'Europe'] args.result.series[0].data.sort(function (a, b) { return sortOrder.indexOf(a.selectionData[0]) - sortOrder.indexOf(b.selectionData[0]) }) args.result.xAxis.categories.sort(function (a, b) { return sortOrder.indexOf(a) - sortOrder.indexOf(b) }) }) This configuration looks like this: ALT text: Bar chart comparing total order quantity between the USA and Europe. The USA has a higher total order quantity than Europe, with both categories represented in dark blue bars on a white background. This was tested using Sample Retail. Let me know how it goes for you in the comments! Check out this related content: Academy Documentation2.2KViews3likes4CommentsInteractive Time Period Comparison with BloX & Custom Actions
Here is a use case on how to leverage BloX widgets in Sisense to create an interactive dashboard for comparing any KPI between two different time periods. This solution allows users to select two months (or any two time periods) and dynamically calculates the percentage change in the KPI between these selected months.11KViews3likes4CommentsExploring the Potential of Sisense Jump to Dashboard Filter Configurations
Sisense Jump to Dashboard offers a powerful way to enhance the user experience and streamline data exploration with the help of different filter configurations. By default, all the filters from the parent dashboard, measured values, and widget filters are passed and replaced in the drill dashboard. This guide explains and provides examples of how you can customize the way filters impact the drill dashboard. We'll delve into multiple filter configuration options and provide a step-by-step guide on how to implement them effectively.2.1KViews3likes2CommentsPlugin - Enable Multicolor Legend Items for Conditional and Range
Overview Legend items come with colored boxes that represent the data points in the chart. The color of each box matches the bar/column/bubble in the chart, as long as the measure is set to a single color, and not conditional or range. When conditional or range is used, the legend item's box becomes grey (or the palette's default color for Scatter Charts), because the box cannot natively accommodate multiple colors. This plugin solves this limitation by: splitting the box into smaller strips to accommodate multiple colors, for conditional, or creating a gradient of two colors in the box, for range. Limitations This plugin is only relevant to Bar Charts, Column Charts, and Scatter Charts. Other chart types either do not support conditional/range or have their own version of legends (e.g., Area Map). If there are too many legend items, wider boxes might affect spacing and cause certain items to be cut off. See the Configuration section below for more details. Installation Instructions Download and unzip the plugin zip file. Extract the files directly (do not extract into a new folder); the plugin files are already organized within a folder in the zip file. Upload the multiColorLegendItems folder to the plugins directory on your Sisense server (/opt/sisense/storage/plugins). Check the Add-ons page in the Admin tab (under Server & Hardware) and make sure the new plugin is listed and enabled. Modify the config file as needed (this can be done before of after the upload). Configurations This plugin comes with a configuration file that can be updated as needed. The four configuration settings in the file are: numberOfColorsForWiderBoxes . If there are too many conditions, the box may be too small to accommodate all colors, so the width may need to be increased. In this case, specify the threshold for the number of colors. For example, a threshold of 5 means the box width will be increased if there are five or more colors assigned to it. Otherwise, the original width will be kept. Note: Wider boxes might affect spacing and cause certain legend items to be cut off if there are too many of them. To work around this, the verticalLayout setting can be set to true. The default value is 5. widthMultiplierForConditional . For wider boxes, specify the multiplier. For example, a multiplier of 1.5 means the new width will be 1.5 times the original width for boxes that have more colors than the numberOfColorsForWiderBoxes threshold. The default value is 1.5. widthMultiplierForGradient . If wider boxes are needed for range as well, specify the multiplier. Otherwise, leave the default value of 1. The original width is generally sufficient for range. verticalLayout . Specify whether legend items should be laid out vertically. This is useful when wider boxes are needed and there are too many legend items to fit correctly horizontally. The default value is false. Examples 1. Conditional with 4 colors (less than the numberOfColorsForWiderBoxes threshold) [ALT Text: A comparison of two column charts labeled "Before" and "After," displaying sales and costs data by sales associates. The "Before" chart shows the "Sales" legend item box in grey despite conditional formatting being applied, while the "After" chart correctly displays the four conditional colors.] 2. Conditional with 11 colors (greater than the numberOfColorsForWiderBoxes threshold, the legend item box width is increased) [ALT Text: A comparison of two scatter charts labeled "Before" and "After," displaying sales and costs data by sales associates. The "Before" chart shows the "Sales" legend item box in blue (the palette's default color) despite conditional formatting being applied, while the "After" chart correctly displays all eleven conditional colors, with a wider box to fit them.] 3. Range Auto (both the min and max colors are auto-selected) [ALT Text: A comparison of bar scatter charts labeled "Before" and "After," displaying sales and costs data by sales associates. The "Before" chart shows the "Sales" legend item box in grey despite automatic range (gradient) being applied, while the "After" chart correctly displays a gradient between the automatically selected minimum and maximum colors.] 4. Range Manual with Min Max range type (both the min and max colors are manually selected) [ALT Text: A comparison of bar scatter charts labeled "Before" and "After," displaying sales and costs data by sales associates. The "Before" chart shows the "Sales" legend item box in grey despite manual range (gradient) with Min/Max mode being applied, while the "After" chart correctly displays a gradient between the user-selected minimum and maximum colors.] 5. Range Manual with Min range type (only the min color is manually selected) [ALT Text: A comparison of bar scatter charts labeled "Before" and "After," displaying sales and costs data by sales associates. The "Before" chart shows the "Sales" legend item box in grey despite manual range (gradient) with Min mode being applied, while the "After" chart correctly displays a gradient between the user-selected minimum color and the automatically selected maximum color.] 6. Range Manual with Max range type (only the max color is manually selected) [ALT Text: A comparison of bar scatter charts labeled "Before" and "After," displaying sales and costs data by sales associates. The "Before" chart shows the "Sales" legend item box in grey despite manual range (gradient) with Max mode being applied, while the "After" chart correctly displays a gradient between the automatically selected minimum color and the user-selected maximum color.]317Views2likes0CommentsHow to Implement Linkable Text in a Widget (Linux)
How to Implement Linkable Text in a Widget (Linux) Introduction This article provides a guide on implementing linkable text to navigate to another dashboard in Sisense. The goal is to enable users to access a linked dashboard by clicking on a text element rather than interacting with a widget. This serves as a workaround for the default functionality, which typically requires a widget click (using Jump to Dashboard with native widgets). Step-by-Step Guide Using Text Widget: Use the direct link to the desired dashboard. This method allows users to be redirected directly to the dashboard upon clicking the text link. For example, you can add a hyperlink to the Text Widget. Prefer refer to this guide: Text Widget Documentation. Using BloX: Utilize the BloX widget to create a button that simulates the appearance and position of text within your design using the Action Button feature. This approach enables users to open the dashboard by clicking the button. Please follow this guide for reference: Creating Action Buttons. If you need to apply filters, configure the BloX widget to perform the Jump to Dashboard (JTD) action. For further instructions on setting up BloX with JTD, refer to this community article on using Jump to Dashboard in a BloX widget. Conclusion Implementing linkable text in a widget provides a seamless navigation experience in Sisense, bypassing the need for widget interactions. Whether using a Text Widget for direct links or leveraging BloX for more customization, these methods allow users to efficiently jump between dashboards. References/ Related Content How to Use Jump to Dashboard in a BloX Widget Creating Action Buttons Text Widget Documentation Jump to Dashboard509Views2likes0CommentsCustom error notification image
Custom error notification image This article explains how to develop the plugin to replace the default error image. Of course, in ideal world there are no errors, but who does live in the ideal one? As a result of this article’s implementation, we will accomplish the following: ALT Text: A comparison table with two columns titled "Original" and "Custom." Each column contains the same message about an error querying a data model, mentioning a specific dimension related to healthcare. The "Original" message features a yellow warning icon, while the "Custom" message has a red explosion icon. Both messages prompt the user to "Try again." To accomplish this we will develop a new plugin. For more details about plugin development please check this article: https://community.sisense.com/t5/knowledge-base/plugin-dev-tutorial/ta-p/9087 To create a new plugin we will need to do the following: Use file manager to navigate to the folder ‘plugins’; In the folder ‘plugins’ create a new folder and name it ‘updateErrorLogo’; Open the newly created folder and create two files: main.6.js; plugin.json. Open the file ‘plugin.json’ and paste there the following content: { "name": "updateErrorLogo", "source": [ "main.6.js" ], "lastUpdate": "2025-01-10T22:36:03.764Z", "folderName": "updateErrorLogo", "isEnabled": true, "version": "1.0.0", "skipCompilation": true, "pluginInfraVersion": 2 } 5. Open the file `main.6.js’ and paste there the following code: //Import your image. Value of the variable newErrorSvg is internal URL to the image import newErrorSvg from './newErrorSvg.svg'; //Subscription at the loading directive slfQueryErrorBrand mod.directive('slfQueryErrorBrand', [ () => { return { restrict: 'C', link: async($scope, lmnt, attrs) => { $(lmnt).hide(); //Hiding default logo await fetch(newErrorSvg).then((response) => { //Load SVG return response.text().then(svgContent => { //Convert response into text lmnt[0].innerHTML = svgContent; //Replace default content with our custom one }); }).catch((error) => { console.error('Error loading SVG:', error); }).finally(() => { $(lmnt).show(); //Show logo }); } }; } ]); 6. Place an image with the name ‘newErrorSvg.svg’ you want to be shown instead of the default. Now, after the plugins rebuild you will see your new image instead of the default one. Enjoy your customized error image. In the attachment, you can find the completed plugin.586Views2likes0CommentsCustomizing the Offset Size of Selected Categories in Sisense Pie Chart Widgets
In Sisense, pie chart widgets, including the various pie chart style options such as donut charts, are a common way to visualize data. By default, when a user selects a category within a pie chart, that slice "pops out" to highlight the selection. This article explains how to customize the offset size of selected categories in Sisense pie chart widgets by leveraging Highcharts settings of the widget using Sisense widget scripting capabilities.490Views2likes0CommentsAutomating Plugin Management in Sisense: A Bash Script Solution
Automating Plugin Management in Sisense: A Bash Script Solution Introduction: This solution is applicable for Sisense on Linux on-premise installations. Managing plugins in Sisense, particularly in scenarios where multiple plugins need to be updated or reverted, can be a time-consuming task. However, by leveraging bash scripting, this process can be automated to save time and ensure consistency across plugins. In this article, we'll provide two bash scripts designed to update and revert changes to plugin configurations in Sisense - particularly changing the enabled/disabled state. These scripts are intended to be executed in the `/opt/sisense/storage/plugins` folder, where all plugins(add-ons) and their subfolders reside. Prerequisites: Before using the provided scripts, ensure you have the following: 1. Access to the Sisense server and permission to create, modify and execute files in /opt/sisense/storage/plugins (Sisense for Linux On-Prem installations). 2. Basic understanding of bash scripting. 3. Familiarity with JSON file structure. Script Overview: The provided scripts consist of two parts: 1. Search and Update Script: This script searches for `plugin.json` files within subfolders of the `/opt/sisense/storage/plugins` directory. It updates the `isEnabled` key to `false` if it's `true` and logs the corresponding folder names in a separate file. #!/bin/bash # Clean the file before writing to it > updated_plugin_names.txt # Function to search for plugin.json and update "isEnabled" value search_and_update() { # Loop through subfolders for dir in */; do if [ -f "$dir/plugin.json" ]; then # Extract folder name folderName=$(jq -r '.folderName' "$dir/plugin.json") # Store name in separate file isEnabled=$(jq -r '.isEnabled' "$dir/plugin.json") if [ "$isEnabled" == "true" ]; then # Update "isEnabled" to false jq '.isEnabled = false' "$dir/plugin.json" > temp.json && mv temp.json "$dir/plugin.json" # Log name only for updated plugin.json echo "\"folderName\": \"$folderName\"" >> updated_plugin_names.txt fi fi done } search_and_update 2. Revert Changes Script: This script reverts the changes made by the first script. It reads the folder names from the log file generated by the first script and sets the `isEnabled` key back to `true` for the corresponding plugins. #!/bin/bash # Function to revert changes made by the first script revert_changes() { # Read plugin names from file while IFS= read -r folderName; do # Remove quotes and extract folder name folderName=$(echo "$folderName" | sed 's/"folderName": "\(.*\)"/\1/') # Find plugin directory by name dir=$(find . -maxdepth 1 -type d -name "*$folderName*") if [ -n "$dir" ]; then # Check if plugin.json exists and set "isEnabled" to true if [ -f "$dir/plugin.json" ]; then jq '.isEnabled = true' "$dir/plugin.json" > temp.json && mv temp.json "$dir/plugin.json" fi fi done < updated_plugin_names.txt } revert_changes Using the Scripts: Follow these steps to use the scripts: Copy Scripts to the Sisense Plugins Directory: Place both scripts (`search_and_update.sh` and `revert_changes.sh`) in the `/opt/sisense/storage/plugins` directory. Make Scripts Executable: Ensure that both scripts have execute permissions. You can set execute permissions using the `chmod` command: chmod +x search_and_update.sh chmod +x revert_changes.sh Execute the Search and Update Script: Run the `search_and_update.sh` script to update the `plugin.json` files: ./search_and_update.sh This script will update the `isEnabled` key to `false` for plugins with the corresponding folders and log the folder names in `updated_plugin_names.txt`. Execute the Revert Changes Script (if needed): If you need to revert the changes made by the first script, run the `revert_changes.sh` script: ./revert_changes.sh This script will read the folder names from `updated_plugin_names.txt` and set the `isEnabled` key back to `true` for the corresponding plugins. Conclusion: By utilizing bash scripting, managing Sisense plugins becomes more efficient and less error-prone. These scripts automate the process of updating and reverting plugin configurations, saving time and ensuring consistency across your Sisense environment. Make sure to test these scripts in a safe environment before applying them to a production environment. Disclaimer: Please note, that this blog post contains one possible custom workaround solution for users with similar use cases. We cannot guarantee that the custom code solution described in this post will work in every scenario or with every Sisense software version. As such, we strongly advise users to test solutions in their own environment prior to deploying them to ensure that the solutions proffered function as desired in their environment. For the avoidance of doubt, the content of this blog post is provided to you “as-is” and without warranty of any kind, express, implied or otherwise, including without limitation any warranty of security and or fitness for a particular purpose. The workaround solution described in this post incorporates custom coding which is outside the Sisense product development environment and is therefore not covered by not covered by Sisense warranty and support services.586Views2likes0CommentsExtend The Functionality Of A Dashboard
Introduction This post describes the process for creating a new plugin that extends the functionality of the dashboard user interface. There are several different aspects that you can modify, this document will focus on the most common use cases. Use Cases Here we will explain how to do it in detailed steps. OPTION 1 - ADDING NEW OPTIONS TO MENUS This is a fairly common use case, where new functionality needs to be added in to existing context menus. at the dashboard level. This post will show the details of one of our plugins to show how this is possible. This plugin adds in the option to add/edit the custom JavaScript of each widget on a dashboard. There are only two files included with this plugin, plugin.json and addEditScriptToWidgetDashboardMenu.js. The plugin.json file just contains the name of this plugin and the name of the JavaScript file that we need to add. This just tells Sisense to load a plugin named addEditScriptToWidgetDashboardMenu and that it includes a file named addEditScriptToWidgetDashboardMenu.js. { name: "addEditScriptToWidgetDashboardMenu", source: [ "addEditScriptToWidgetDashboardMenu.js" ], style: [] } The next file uses the prism.on(eventname,function) code to attach a function to a specific event. The beforewidgetindashboardmenu event fires whenever a user clicks on a menu icon on a widget in a dashboard. A full list of dashboard-level events can be found in our documentation here. So whenever a user clicks on a widget's settings menu, it runs this function which adds in a new menu item (and separator line). var beforewidgetindashboardmenuAddItem = function(ev,args){ 'use strict'; var scope = {widget:args.widget}, // initialize scope activity = prism.$injector.get('base.services.$activity'), // get activity service command = { // initialize edit script command command: prism.$command.create('dashboard.commands.editWidgetScript', { $scope: scope, $activity: activity }) }, separator = {type:"separator"}; // initialize separator // add items to menu args.items.push( separator, command ); }; prism.on("beforewidgetindashboardmenu",beforewidgetindashboardmenuAddItem); When creating new menu items, we typically add separators to group buttons based on functionality and they are simply object with a type property of "separator'. Menu items can be individual commands, such as the example above, or can display a sub-menu with additional menu items. When creating a single menu item with your own functions, see the reference below. { caption: "my label", // (required for all but separators) the text to display in the menu type: "option", // (optional) The following types are supported // "option" - a radio button (clicking does not close the menu) // "check" - check box // "header" - header text // "separator" - a divider line execute: myFunction, // (optional) attach a function to run whenever this menu item is clicked // This action is called before the menu gets closed, so it may be beneficial to // run this asynchronously using the setTimeout function checked: false, // (optional) either true or false to determine whether to show a checkbox // This works for radio buttons, as well items: [array of submenu items], // (optional) an array of menu items, which will show up in a sub-menu disabled: false // (optional) will hide the menu item when true hidden: false // (optional) will hide the menu item when true classes: "myClassName" // (optional) adds a CSS class to the menu item confirm: false // (optional) when true, adds a confirmation prompt on click // If you supply an object in the format of { critical:true, message:"some message"} // you can override the confirmation dialog closing: false // (optional) when true, the menu closes on click for radio buttons change: onChangeFunction // (optional) callback function for radio buttons, whenever the selection is changed customProperty1: "my value" // (optional) add your own custom properties that get stored with each menu item } The plugin described here leveraged a specific event to ensure it only fires when a user clicks on a widget menu in a dashboard, but if you wanted to attach an event to a specific menu you can just use the generic beforemenu event and check the HTML element's parent to figure out which menu was clicked. You should be able to identify it based on the classname or div id. OPTION 2 - ADDING NEW LINKS/BUTTONS TO YOUR DASHBOARD We currently have a few plugins in our support forums that demonstrate this (links below), but this post will walk through the process of creating a plugin that adds links to your dashboard. Like all plugins, we need to have a plugin.json file that specifies the plugin name and all JavaScript/CSS files that need to be loaded. If we look at the code, there is an object that has a name (of the plugin), a source property (an array of all the javascript files required), and a style property (an array of all CSS files required). In this case, two JavaScript files are required, buttons.js and addButtons.js. { name: "addButtons", source: [ "buttons.js", "addButtons.js" ], style: [] } Looking at the buttons.js file, this is where an admin can configure what new links to add to the system. This file was separated out, to differentiate between configuration files and code files. We need a place to store any extra buttons to add, so they are placed within a new property of the prism object. This is just a way to store configuration settings, so that they can be referenced later. // Add an array to the prism object for additional links prism.extraButtons = [ { link: "http://www.google.com", label: "Google" } ]; The addButtons.js file is where the links actually get created. In order to run a function within the context of Sisense, we use prism.run( [ ] ). The only thing added here is a function that waits for the dashboard to finish loading, then loop through all the buttons specified in buttons.js and add them as links. There is a function createButton that takes in a url and a label, which is what a user configures in buttons.js. We load the buttons stored in prism.extraButtons, and run this function for each one. The function creates HTML for each button that's identical to the HTML used in the existing links. Once the new buttons are created, we look for the container object (which has a class of main-nav) and append the new button to that container. Since we create the HTML identical to the existing buttons, the styling will match the CSS used by the dashboard. prism.run([ function() { // Wait for the dashboard to load setTimeout( function() { // Create Button Function var createButton = function (url, label) { // Create container div var buttonDiv = $('<div class="nav-item"></div>'); // Create Anchor var buttonAnchor = $('<a href="' + url + '">' + label + '</a>'); // Create Divider Line var buttonDivider = $('<div class="line"></div>'); // Put everything together buttonDiv.append(buttonAnchor); buttonDiv.append(buttonDivider); // Find navigation menu var navMenu = $('#main-nav'); // Append the new button navMenu.append(buttonDiv); }; // Add the new button $.each(prism.extraButtons, function() { // For each button createButton(this.link, this.label); }); }, 1000); } ]); Relevant plugin: Add Additional Links to your Dashboard1.3KViews1like0Comments