Sisense Community logo
    • Community Feedback
    • Chapters
    • Events
    • Forums
      • Help and How To
      • Product Feedback Forum
      • Strategy & Use Cases
    • Blogs
    • KB Docs
      • KB Docs
      • Add-Ons & Plug-Ins
      • APIs
      • Best Practices
      • Blox
      • CDT
      • Cloud Managed Service
      • Data Models
      • Data Sources
      • Embedding Analytics
      • How-Tos & FAQs
      • Onboarding
      • PySisense
      • Security
      • Sisense Administration
      • Sisense Intelligence & AI
      • Troubleshooting
      • Widget & Dashboard Scripts
    • Support
    • Learning
      • Sisense Academy: Free Courses and Certifications
      • Official Developer Documentation
      • Official Product Documentation
      • Official Sisense Youtube Channel
      • Sisense Compose SDK Playground
      • Official Sisense Discord
    • Use Case Gallery
    Discussions
    •                    
    •                    
    •                    
    •                    
    •                    
    •                    
    •                    
    •                    
    •                    
    •                    
    •                    
    •                    
    •                    
    •                    
    •                    
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
    Discussions
    • TagsChevronRightIcon
    Customer Training
    • Blog banner
      • Widget & Dashboard ScriptsChevronRightIcon

      Programmatically Formatting Bar Chart Widget Value Labels in Sisense

                                                                                               

      Programmatically Formatting Bar Chart Widget Value Labels in Sisense This article outlines ways to programmatically format Sisense Bar Chart Widget Value labels via widget scripts , covering methods to prevent label overlap and apply consistent styling across all labels. Custom Styling for Data Labels The script below enables the formatting of Chart Widget Value labels by setting a custom background color, padding, and border-radius. Ensure the default data label UI option is disabled. Other CSS and Highcharts settings can be added as needed.         widget.on('render', function (se, ev) { ev.widget.queryResult.plotOptions.bar.dataLabels = { backgroundColor: '#f5d142', color: 'white', padding: 5, borderRadius: 5, enabled: true } })       Preventing Label Overlap The script below manually adjusts value label positioning to prevent overlap in densely populated bar chart widgets. The exact formulas for label positioning can be changed as needed.         widget.on('domready', function (se, ev) { var barWidth = $('.highcharts-series-group .highcharts-series rect', element).width(); $('.highcharts-data-labels .highcharts-label', element).each(function () { var labelWidth = $(this).find('rect').width(); var labelHeight = $(this).find('rect').height(); $(this).find('rect').attr('x', ($(this).find('rect').attr('x') + 2)); $(this).find('rect').attr('height', barWidth); $(this).find('rect').attr('y', ((labelHeight - barWidth) / 2)); }) })         Dynamically Increase Space for Labels If bar value labels overlap with the chart bars, you can dynamically adjust the maximum value on the y-axis to create additional space. A different formula, or a hard-coded value, can also be used as the y-axis maximum value.         widget.on('processresult', function (se, ev) { var maxValue = 0; var increasePercent = 0.2; ev.result.series.forEach(function (series) { series.data.forEach(function (dataItem) { if (dataItem.y > maxValue) maxValue = dataItem.y; }) ev.result.yAxis[0].max = maxValue + (increasePercent * maxValue); }) })       Conclusion These scripts enable customizing dynamically formatted and well-positioned data labels in your Sisense charts, enhancing readability and aesthetics beyond the default Sisense data bar data labels in bar chart widgets. For further discussion of these types of scripts, see the  Dynamically Formatted Data Labels article Example Of Custom Labels Added via Scripting   Y-Axis Maximum Set To a Very Large Value Check out this related content:  Academy Documentation

      Jeremy Friedel
      Jeremy FriedelPosted 1 year ago • Last reply 2 months ago
      1
               
    • Blog banner
      • APIsChevronRightIcon

      UserReplaceTool - Automating Dashboard Ownership Transfers - Useful for Deleting User Accounts

                                                                                                       

      Automating Dashboard Ownership Transfer in Sisense with UserReplaceTool Managing and deleting user accounts in Sisense can create manual processes when users leave an organization or change roles. A frequent issue is the reassignment of dashboard ownership to prevent losing Sisense dashboards when a given user account is deleted, as deleting a Sisense user will delete all dashboards owned by that user. The UserReplaceTool addresses this task by automating the transfer of dashboard ownership of all dashboards owned by a given user, ensuring continuity and data integrity. Overview UserReplaceTool is a Python-based, API-based Tool solution designed to seamlessly transfer the ownership of dashboards and data models from one user to another in Sisense. This tool simplifies and automates this process, allowing organizations to reassign dashboard ownership without manual processes or the risk of losing dashboards and widgets. All components are accomplished by using Sisense API endpoint requests. Key Features Automated Dashboard Transfer : Reassigns ownership of all dashboards from the current user to a designated replacement user. Data Model Sharing : Ensures that all data models accessible and editable by the previous user are shared with the replacement user. Batch User Processing : Capable of handling multiple user transfers to a replacement user in a single operation, enhancing efficiency. Complete Logging:  All dashboards and datasource transferred are logged both in the console and in a separate log file. Setup Instructions 1. Setting Up the Environment To run the tool within a Python virtual environment , follow these steps: Activate the Python Virtual Environment : source /venv/bin/activate Create a Virtual Environment (if not already present): python3 -m venv .venv Install Dependencies : pip3 install -r requirements.txt For manual installation, including without using a Python virtual environment: pip3 install urllib3 jsonpath_ng pyyaml requests colorama 2. Configuration Edit the settings.yaml file to configure the tool. Key parameters include: Sisense Domain and Port : Specify the URL and port of your Sisense server, which is used for making API requests. API Bearer Token : Provide an admin-level bearer token for API authentication. See the  Sisense API Bearer Token Documentation for instructions on generating and using Bearer Tokens. Users to Replace : List the user IDs to be replaced. User IDs can be retrieved via the Users API or using the console command prism .user._id. Replacement User : Specify the user ID of the new replacement owner of all dashboards. This should typically be an admin level user. Data Model Sharing : Enable or disable the sharing of data models with the Replacement user (True or False), usually True. Dashboard Ownership Transfer : Enable or disable the transfer of dashboard ownership (True or False), usually True. Unlike Dashboards, if a user is deleted, the datasources themselves are not deleted from the server, ownership is automatically transferred to the main System Admin of the Sisense server.  3. Running the Tool Run the tool with the following command:   python3 replaceUser.py Practical Considerations Admin and Network Access : Ensure you have admin-level API access to the Sisense instance. Python Environment : Python3 and pip should be installed on the machine running the tool. All dependencies can be installed using Pip, and a Python virtual environment can be used. Once a Python Virtual Environment folder is set up it can be shared with the Tool and run directly on all systems using the same OS, but it is not cross OS compatible. By automating the transfer of dashboard ownership, UserReplaceTool provides a reliable and efficient solution for managing user transitions in Sisense. This ensures that datasources and dashboards remain accessible and under the control of the appropriate users, maintaining the continuity of Sisense resources. For further customization and configuration details, refer to the attached full Python Tool, which includes a README file and modify the "settings.yaml" file as necessary.    

      Jeremy Friedel
      Jeremy FriedelPosted 1 year ago • Last reply 4 months ago
      3
               
    • Blog banner
      • How-Tos & FAQsChevronRightIcon

      Adding additional dimensions to the Scatter Map widget tooltip

                                                       

      Adding additional dimensions to the Scatter Map widget tooltip Additional dimensions can be added to the hover tooltip of the Scatter Map widget type, beyond the default limit of three, to include more information from other dimensions about a location in a Scatter Map widget. This can be accomplished by using a combination of the widget's before query event  to add additional dimension data for the hover tooltips and the  before datapoint tooltip event to incorporate these dimensions into the tooltip. This method of modifying the query using the "beforequery" event can also be applied to all other widget types   // Add extra parameters to be used in tooltips by modifying query widget.on('beforequery', function (se, ev) { // Initial number of widget metadata panels excluding filter panel widget.initialPanelSizeExcludingFilterPanel = ev.query.metadata.filter((panel) => { return panel.panel !== "scope" }).length; // Extra dimensions to show in tooltip, should return a single result, include as many as needed, just add to array // Jaql Objects can be copied from other widgets from the prism.activeWidget.metadata.panels via the browser console // Modify JAQL as needed, title of JAQL is used in tooltip and can be modified to any string widget.extraDimensionJAQL = [ { "jaql": { "table": "Category", "column": "Category ID", "dim": "[Category.Category ID]", "datatype": "numeric", "merged": true, "agg": "count", "title": "Unique Category ID" } }, { "jaql": { "table": "Country", "column": "Country ID", "dim": "[Country.Country ID]", "datatype": "numeric", "merged": true, "agg": "count", "title": "Unique Country ID" } }, ] // Add to default widget query the extra dimensions to be used in tooltips ev.query.metadata = ev.query.metadata.concat(widget.extraDimensionJAQL) }); // Add extra dimensions added with beforequery object to ScatterMap tooltip widget.on("beforedatapointtooltip", (event, params) => { // Convert query results to include only the additional dimensions, and formatted for tooltip template var onlyAdditionalDimensions = widget.queryResult.$$rows.map((withoutDefaultDimensionOnlyAdditional) => { // Remove the default dimensions, first part of row result array var withoutDefaultDimensionOnlyAdditional = withoutDefaultDimensionOnlyAdditional.slice(widget.initialPanelSizeExcludingFilterPanel) // Format for tooltip template, include title from JAQL var extraDimensionObj = withoutDefaultDimensionOnlyAdditional.map((extraDimensionValue, index) => { // Use extraDimensionJAQL for label in tooltip return { "text": extraDimensionValue.text, "title": widget.extraDimensionJAQL[index].jaql.title } }) return extraDimensionObj }); // Object to store extra dimensions params.context.marker.extraDimension = {}; // Use matching queryIndex for tooltip of additional dimensions params.context.marker.extraDimension.arr = onlyAdditionalDimensions[params.context.marker.queryIndex]; // Template for tooltip, modify as needed params.template = ` <div class='geo-text'>{{ model.marker.name }}</div> <div class='measure-holder' data-ng-if='model.measuresMetadata.sizeTitle'> <div class='measure-title slf-text-secondary'>{{ model.measuresMetadata.sizeTitle }}:</div> <div class='measure-value'>{{ model.marker.sizeObj.text }}</div> </div> <div class='measure-holder' data-ng-if='model.measuresMetadata.colorTitle'> <div class='measure-title slf-text-secondary'>{{ model.measuresMetadata.colorTitle }}:</div> <div class='measure-value'>{{ model.marker.colorObj.text }}</div> </div> <div class='measure-holder details-measure-holder' data-ng-if='model.measuresMetadata.detailsTitle'> <div class='measure-title slf-text-secondary'>{{ model.measuresMetadata.detailsTitle }}:</div> <div class='measure-value' data-ng-if="!model.marker.detailsObj.arr">{{ model.marker.detailsObj.text }}</div> <div class="details-wait" data-ng-if="model.marker.detailsObj.pendingDetails"></div> <div data-ng-if="model.marker.detailsObj.arr"> <div class="details-value" data-ng-repeat="a in model.marker.detailsObj.arr">{{a.text}}</div> <div class="details-counter" data-ng-if="model.marker.detailsObj.hasMore"> <div class="details-counter">...</div> <div class="details-counter"> {{'smap.ttip.firstres'|translate:(args={count:model.marker.detailsObj.arr.length})}}</div> </div> </div> </div> <div data-ng-if="model.marker.extraDimension.arr"> <div data-ng-if='model.measuresMetadata.colorTitle'> <div class='measure-holder' data-ng-repeat="a in model.marker.extraDimension.arr"> <div class='measure-title slf-text-secondary'>{{a.title}}:</div> <div class="measure-value extra-dimension-value">{{a.text}}</div> </div> </div> </div>`; });    The JAQL can be changed to any valid JAQL object , and the tooltip template can also be further modified.

      Jeremy Friedel
      Jeremy FriedelPosted 2 years ago • Last reply 7 months ago
      3
               
      • Sisense AdministrationChevronRightIcon

      Update and add new Highcharts modules for use in Sisense plugins

                                                                                                                       

      Update and add new Highcharts modules for use in Sisense plugins The JavaScript library framework Highcharts is natively included in Sisense and is utilized in many native Sisense widgets as well as in numerous Sisense plugins. Although Sisense typically does not alter the Sisense Highcharts library version with every release, the versions of Highcharts included in Sisense may change when upgrading to a new major version release. Highcharts can load additional chart types and other types of functionality via JS module files that contain code-adding features such as additional chart types, which can be used within plugins along with additional code to create additional widget types. If a plugin utilizes a Highcharts module, you can source the module directly in the "plugin.json" file's source parameter, as shown in this example:   "source": [ "HighchartModule.js", ],   To determine the current Highcharts version being used in your Sisense version, you can use the "Highcharts" command in the web console while viewing any page on your Sisense server. After identifying the current Highcharts version, you can find the corresponding module hosted on a Highcharts code hosting website using the following URL format: https://cdn.jsdelivr.net/npm/highcharts@${Highcharts_Version}/modules/${module_name}.js For example: https://cdn.jsdelivr.net/npm/highcharts@10.3.3/modules/heatmap.js You can save this module and upload it to the plugin folder or replace the older module JS file simply by copying and pasting the code directly. Be sure to update the "plugin.json" file to point to the new module file if the file name has changed or if this is the first time the module is included. Simply sourcing the module file in the "plugin.json" file is sufficient to load the module into Highcharts; no further code is required to load the module.

      Jeremy Friedel
      Jeremy FriedelPosted 2 years ago • Last reply 1 year ago
      2
               
    • Blog banner
      • Widget & Dashboard ScriptsChevronRightIcon

      Using Native Javascript Date Calculations To Modify Sisense Date Filters

                                                                                               

      Using Native Javascript Date Calculations To Modify Sisense Date Filters Sisense natively supports various types of date filter functionalities. However, there are instances where a dynamically updating date filter is desired based on dynamically changing conditions such as the current date. Such a filter may not precisely align with the filters provided in the Sisense UI. One approach to achieve this custom behavior of a dynamically updating filter is through the use of dashboard or widget scripting . A particular consideration when dealing with a date filter is that, in most cases, date filter calculations are best done using JavaScript date objects (which use Unix time ). Sisense date filters typically utilize dates in standard calendar-based string date formats. The following script exemplifies this functionality; It generates a date object based on the required custom date behavior, converts it into a string format compatible with Sisense, and then modifies the Sisense date filter with the formatted date string. JavaScript date objects offer numerous useful functions, enabling straightforward mathematical operations such as addition or subtraction to calculate dates based on desired formulas. This script example specifically identifies dates a set number of days ago (variables set at 60 and 10 days ago from today, respectively) and sets a date filter using these values in the "From" and "To" parameters of a date range filter.     // Programmatically modify Date dashboard filter "From" value to day to a set number of days ago, and the "To" date to different set number of days ago dashboard.on('initialized', function () { // Modify to match the relevant date filter title, date filter must already exist and be "From" and "To" date filter let filterModifiedName = "Date"; // Number of days ago to find date of from "From" date // Modify to days ago to calculate "From" date var daysAgo = 60 // Number of days ago to find date of from "To" date // Modify to days ago to calculate "To" date var offsetDate = 10 filterModifiedName = filterModifiedName.toLowerCase() // Variable containing the Dashboard filter modified by script let modifiedFilter = dashboard.filters.$$items.find(function (filterItem) { return !filterItem.isCascading && filterItem.jaql && filterItem.jaql.title && filterItem.jaql.title.toLowerCase() === filterModifiedName; }); // If relevant filter has from and to values selected, date filter must already exist and have from and to values if (modifiedFilter && modifiedFilter.jaql && modifiedFilter.jaql.filter && modifiedFilter.jaql.filter.from && modifiedFilter.jaql.filter.to && daysAgo && daysAgo >= 1) { // "From" date variable var fromDate = new Date // Time in MS of number of daysAgo var daysAgoInUnixTimeUnits = daysAgo * 24 * 60 * 60 * 1000; // Subtract daysAgo in MS to find date daysAgo ago var daysAgoDateUnixTime = fromDate.getTime() - daysAgoInUnixTimeUnits; // Set date object of date in unix time fromDate.setTime(daysAgoDateUnixTime) // Format date for Sisense date format var formattedFromDate = fromDate.toISOString().slice(0, 10) // Set date filter "From" value modifiedFilter.jaql.filter.from = formattedFromDate // "To" date variable var toDate = new Date // Time in MS of number of offsetDate var daysAgoInUnixTimeUnitsOffset = offsetDate * 24 * 60 * 60 * 1000; // Subtract offsetDate in MS to find date var daysAgoDateUnixTimeTo = toDate.getTime() - daysAgoInUnixTimeUnitsOffset; // Set date object of date in unix time toDate.setTime(daysAgoDateUnixTimeTo) // Format date for Sisense date format var formattedToDate = toDate.toISOString().slice(0, 10) // Set date filter "To" value modifiedFilter.jaql.filter.to = formattedToDate } });     This script is a slight variation that always sets the "To" date to the current date without offsetting this parameter:     // Programmatically modify Date dashboard filter "From" value to day to a set number of days ago, and the "To" date to current date dashboard.on('initialized', function () { // Modify to match the relevant date filter title, date filter must already exist and be "From" and "To" date filter let filterModifiedName = "Date"; // Number of days ago to find date of // Modify to days ago to calculate "From" date var daysAgo = 60 filterModifiedName = filterModifiedName.toLowerCase() // Variable containing the Dashboard filter modified by script let modifiedFilter = dashboard.filters.$$items.find(function (filterItem) { return !filterItem.isCascading && filterItem.jaql && filterItem.jaql.title && filterItem.jaql.title.toLowerCase() === filterModifiedName; }); // If relevant filter has from and to values selected, date filter must already exist and have from and to values if (modifiedFilter && modifiedFilter.jaql && modifiedFilter.jaql.filter && modifiedFilter.jaql.filter.from && modifiedFilter.jaql.filter.to && daysAgo && daysAgo >= 1) { // "From" date variable var fromDate = new Date // Time in MS of number of daysAgo var daysAgoInUnixTimeUnits = daysAgo * 24 * 60 * 60 * 1000; // Subtract daysAgo in MS to find date daysAgo ago var daysAgoDateUnixTime = fromDate.getTime() - daysAgoInUnixTimeUnits; // Set date object of date in unix time fromDate.setTime(daysAgoDateUnixTime) // Format date for Sisense date format var formattedFromDate = fromDate.toISOString().slice(0, 10) // Set date filter "From" value modifiedFilter.jaql.filter.from = formattedFromDate // "To" date variable var todayDate = new Date // Format date for Sisense date format var formattedToDate = todayDate.toISOString().slice(0, 10) // Set date filter "To" value modifiedFilter.jaql.filter.to = formattedToDate } });     Breaking down the script into parts, the initial step in modifying a filter (in this case, a dashboard filter, but applicable to a widget filter) is to find the correct filter object in the dashboard array of filter objects . This is achieved by checking for the filter object whose title matches a given variable in this example. It then checks whether the filter is a calendar range-type date filter.     filterModifiedName = filterModifiedName.toLowerCase() // Variable containing the Dashboard filter modified by script let modifiedFilter = dashboard.filters.$$items.find(function (filterItem) { return !filterItem.isCascading && filterItem.jaql && filterItem.jaql.title && filterItem.jaql.title.toLowerCase() === filterModifiedName; });     After a conditional check to ensure the date filter was found, the calculation of the date object is accomplished. First, a JS date object is created based on Unix time, defaulting to the current Unix time in UTC. The date is then modified mathematically by, in this case, subtracting from the current Unix time in milliseconds the set number of days to calculate. The days-to-MS calculation is performed using multiplication (hours in a day, minutes in an hour, seconds in a minute, MS in a second). This method can be easily modified to calculate values for years, months, or other time units as needed. Finally, the date object in MS is converted to an ISO format date string (a human-readable calendar string), and the part of the string containing details about units smaller than the day is removed by a straightforward string splice.     // "From" date variable var fromDate = new Date // Time in MS of number of daysAgo var daysAgoInUnixTimeUnits = daysAgo * 24 * 60 * 60 * 1000; // Subtract daysAgo in MS to find date daysAgo ago var daysAgoDateUnixTime = fromDate.getTime() - daysAgoInUnixTimeUnits; // Set date object of date in unix time fromDate.setTime(daysAgoDateUnixTime) // Format date for Sisense date format var formattedFromDate = fromDate.toISOString().slice(0, 10) // Set date filter "From" value modifiedFilter.jaql.filter.from = formattedFromDate // "To" date variable var todayDate = new Date // Format date for Sisense date format var formattedToDate = todayDate.toISOString().slice(0, 10) // Set date filter "To" value modifiedFilter.jaql.filter.to = formattedToDate     The filter object was already found in the previous step, so the filter object is modified by adjusting the JAQL filter "To" or "From" parameter of the filter object. No additional code is needed to modify the filter in this case; the filter is modified by directly adjusting the existing parameters of the filter JAQL object. In this example, the current date is used as the starting point, so the script applied by this filter will change based on the current date. Below is the result of this filter changing script, using the 60 days to 10 days ago from the current date values set as parameters. Simpler or more complex calculations or formulas could be applied as required to form the dates required for a particular use case. Any date calculation that is programmatically calculable can then be converted to a calendar date format and used to modify a date filter. Native Sisense allows many different types of data filters, and the JAQL syntax can also be used to create custom filters. However, programmatically setting filters allows for complete flexibility in types of dynamically changing date filters. The examples above use only the dashboard "initialized" event, and as such, only modify the set filter when the dashboard is first loaded. As a result, it remains possible to modify the filter normally; the script will only modify the filter again on a fresh load of the dashboard, allowing a user to adjust the filter temporarily as required. While the above example uses the native Sisense filter object, the filter object in Sisense.js is identical to the native Sisense filter object. Therefore, this code can also be used in code determining the date strings to apply with the Sisense.js applyFilter function. Similarly, this type of JS date object calculation can be used to determine the filters to use in a date filter in ComposeSDK, with only the final step of applying the filter differing.   Share your experience in the comments! 

      Jeremy Friedel
      Jeremy FriedelPosted 2 years ago • Last reply 1 year ago
      13
               
    • Blog banner
      • Widget & Dashboard ScriptsChevronRightIcon

      Customizing the Offset Size of Selected Categories in Sisense Pie Chart Widgets

                                                                                               

      Customizing 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 the  Highcharts settings of the widget using Sisense widget scripting capabilities. Understanding the Default Behavior When a slice in a Sisense pie chart is selected, it moves outward from the center by a medium-sized offset. The size of this move is set by the slicedOffset property in the Highcharts setting object , Highcharts is the JavaScript visualizing library that Sisense uses for rendering pie charts and many other common widget types.   Default Pie Chat Offset Default Donut Pie Chart Offset The Highcharts slicedOffset Property The slicedOffset property determines the distance, in pixels, that a slice is moved when it is selected or "sliced out." By modifying this property, it is possible to increase or decrease the offset to better fit the visualization requirements. The unit is always set in raw pixels as an integer and not any other unit. Accessing and Editing the Highcharts Options Object via Sisense Widget Scripting To customize the Highcharts settings object within a Sisense widget, the beforeviewloaded event in a widget script can be used. This specific widget event is triggered immediately before Highcharts is used to begin rendering the already fetched and processed data from the Sisense data source, allowing customization of the chart options before the chart is displayed. Implementation Steps   Add a Widget Script Navigate to the pie chart widget in question. Open the widget's script editor to add a custom script. Insert the Custom Script Use the following code as a template:     // Increase or decrease the size of the offset when a slice in the pie/donut chart is selected widget.on('beforeviewloaded', function (widget, env) { // Pixels to move the selected slice when selected var slicedOffset = 50; // Set the desired offset size here // Access Highcharts options for the widget var chartOptions = env.options; // Access pie chart specific Highcharts options var pieOptions = chartOptions.plotOptions.pie; // Set the offset of the selected slice pieOptions.slicedOffset = slicedOffset; });       Customize the Offset Value Modify the slicedOffset variable to the desired number of pixels. For example, to decrease the offset size, it might be set to 3, to increase it might be set to 50. Trial and error can be used to determine the best value for the use case.   Offset Increased to 50   Offset Increased to 50 in Donut Pie Chart   Save and Refresh Save the script and refresh the dashboard. The pie chart will now reflect the new offset size when a slice is selected. Important Considerations   Highcharts Version Compatibility Sisense uses a specific version of Highcharts that may differ between Sisense versions and might not always be the latest available version of Highcharts. To ensure compatibility:   Check the Highcharts Version : In the browser's console , enter Highcharts.version to display the current Highcharts version used by Sisense.   Consult Appropriate Documentation : Use the version number to refer to the correct Highcharts documentation in case any settings have changed between versions. Viewing Current Highcharts Settings For advanced customizations, it can be helpful to view the existing explicitly defined by Sisense Highcharts options for a widget:     widget.on('beforeviewloaded', function (widget, env) { console.log('Highchart Options: ', env.options); // Logs the current Highcharts options to the console });     By printing the env.options paramater, other customizable properties within the Highcharts configuration object can be viewed. Not all possible or relevant Highchart options are by default defined by Sisense when the default value is not being modified, for example, the slicedOffset parameter is not set directly by Sisense, it did not exist in the default Sisense Highchart Setting object before being defined in a script, the Highchart documentation contains the full list of possible Highcharts settings.   Extending Customizations The scripting customization method described here isn't limited to adjusting the slicedOffset property. Any Highcharts setting available for the chart type by altering the env.options object within the beforeviewloaded event. This allows extensive visual customization of Sisense widgets. Conclusion Customizing the offset size of selected slices in Sisense pie chart widgets can enhances the interactivity and readability of pie chart visualizations. By tapping into the Highcharts settings through the beforeviewloaded event, it is possible to have granular control over the chart's behavior and appearance. Other Highcharts settings can also be modified using this script template. References Highcharts Documentation : Highcharts Reference Sisense Documentation on Widget Scripts : Sisense Widget JavaScript Sisense Academy course on Widget Plugins and Scripts: Advanced Dashboards with Plug-ins and Scripts

      Jeremy Friedel
      Jeremy FriedelPosted 1 year ago
      0
               
    • Blog banner
      • News & UpdatesChevronRightIcon

      Using Dashboard Design Patterns To Increase User Engagement

                                       

      Using Dashboard Design Patterns To Increase User Engagement Defining and using consistent dashboard visualization Patterns will improve User understanding and engagement.  What do I mean by Patterns?  Simply put, Patterns are the layout (type and placement of widgets) on your dashboards.  Why do layout Patterns matter?  Consistent placement and sizing of widgets will help your users orient themselves more quickly when they open a dashboard.  As a result, they are more at ease and more likely to stay engaged with your dashboards.   There are no absolute rules for dashboard design patterns, but here are a few concepts that I have found to be helpful:   - Develop a few different layout patterns and use them repeatedly unless there is a strong reason to do otherwise.     - Use indicators at the top of the dashboard to show summary data if appropriate.   - Show your detailed data in the appropriate widget type below the indicators.  Widget-type selection is not in the scope of this post.  There are many resources available online to help you with this.  One I like that Sisense also recommends is by  Dr. Andrew Abela .     - Use colors consistently across your dashboards.   -  You should also strive for consistency (one or several Patterns) in your dashboard filters.  Present the same filters in the same order when practical.  With consistent filter choices, your users will know what to expect when they open the dashboard and how to use the filters presented. -  It is worthwhile to consider Dependent vs. Independent filters when establishing your filter patterns.  Dependent filters have the advantage of only showing selections that are valid for the parent filter choices.  Their disadvantage is that the child filters are reset each time a parent's choice is changed.  This can sometimes be annoying enough to the user to obviate their use.  Dependent filters also cannot be configured as Background filters.   Some concepts for layout Patterns are shown in the four enhanced wireframes below.        #1 - A top row of relevant indicators with detailed analysis below.  Note that the indicators are summaries of each line series in the chart.   #2 - A top row with a metric summary indicator.  A second indicator row with sub-summary metrics.  Details of these sub-summary metrics are presented in the stacked bar chart below. #3 - A top row with 2 indicators with further detail right.  A bottom row of related detailed analysis.   #4 - Stacked indicators on the left with related detailed analysis directly right.  Also shown is a dashboard filter pattern that was used consistently across this analytics system.   Sisense demo dashboards are also a good reference for dashboard layout.  You will notice a good bit of Pattern consistency across them.  In addition, there is an archived  Dashboard Design webinar  you may view on the Sisense website.    In a graphic design reference I used many years ago, the key principles for good graphic design (I think we can agree that dashboards improve with good graphic design) were presented as a mnemonic:  CRAP.  CRAP refers to consistency, repetition, alignment, and position.  Over time, while I'm not a graphic designer, these simple ideas have helped me with several different graphic design-related activities.  My adaption of the CRAP principle for dashboards is:   - Consistency:  Use consistent patterns on and across dashboards.   - Repetition:     Reuse the same layouts and widgets.   - Alignment:     Widgets that align are easier on the eye.   - Position:         Place similar widgets in the same position across dashboards. The good news is that Sisense's dashboard layout tools inherently support this approach.    Consistent dashboard Patterns will also help speed up the development of new dashboards.  Always start with one of your existing patterns and you'll quickly have something to show that looks familiar and engaging to your users.  If an existing Pattern doesn't work for a dashboard, it's time to create a new one.  

      Community_Admin
      Community_AdminPosted 1 year ago
      0
               
      • TroubleshootingChevronRightIcon

      Resolving Limited Column Retrieval in Sisense API Connection to Jira

                               

      Resolving Limited Column Retrieval in Sisense API Connection to Jira Summary This article addresses the issue where a Sisense API connection to Jira only retrieves native columns and does not include custom column fields. It provides a step-by-step solution to resolve this issue and ensure that custom field columns are retrieved. Main Content Step-by-Step Instructions to Resolve Limited Column Retrieval Identify the Connector : Ensure you are using the correct connector for your Jira data source. In this case, the CData Jira ServiceDesk connector is used. Check JDBC String Parameters : Verify that the JDBC string parameters are correctly set. Specifically, ensure that the IncludeCustomFields parameter is set to true to ensure that custom fields columns are retrieved. Example JDBC string: jdbc:cdata:jira:URL= https://your-jira-instance;IncludeCustomFields=true ; Review Connector Settings : Check the settings of the CData Jira ServiceDesk connector to ensure there are no configurations that limit the retrieval of custom columns. Refer to the CData documentation for more details: CData Jira JDBC Connection Verify Data Retrieval : After updating the JDBC string and reviewing the connector settings, re-run your data retrieval process to ensure that custom field columns are now being retrieved along with the native columns. Troubleshooting Tips Verify Connector Compatibility : Ensure that the connector you are using is compatible with the version of Jira and Sisense you are running. Check for Updates : Make sure that both Sisense and the CData connector are up to date to avoid any compatibility issues. Consult Documentation : Refer to the official documentation for both Sisense and the CData connector for any additional configuration settings that might affect column retrieval. Additional Information Community Resources : If you continue to experience issues, consider consulting the Sisense community forums or the CData support resources for further assistance. By following these steps, you should be able to resolve the issue of limited column retrieval in your Sisense API connection to Jira. If you have any further questions or encounter additional issues, please create a separate support ticket with detailed information about the problem.

      Vlad Solodkyi
      Vlad SolodkyiPosted 1 year ago
      0
               
    • Blog banner
      • News & UpdatesChevronRightIcon

      User Adoption: How to Meet Your Users Where They Are

                       

      User Adoption: How to Meet Your Users Where They Are One of the most complex parts of any project or implementation is gaining traction across your organization. If dashboards and data are not readily available and easily accessible, users will simply choose to remain on their legacy systems. Sisense can be deployed to give users access to dashboards and data directly within their workflow.   Expanding adoption isn’t just about access to a platform, however. For many stakeholders, the convenience of a specific method over another means that lack of access is not just about credentials but comfort as well. These different methods to interact with and view dashboards and their corresponding data are vital to consider when starting a new project and thinking about your stakeholders’ needs. How to Make Data More Accessible To help generate interest and speed up the rate of adoption for your implementation, offering multiple channels and methods to access data is vital. These are some of the ways you can let users view the visualizations and dashboards they need: Mobile Applications Most users spend as much time using smartphones on the go as they do on their computers. Employing mobile applications for both iOS and Android gives users the ability to remain connected and quickly check on specific data or KPIs remotely. Users can also personalize which dashboards they see to more easily access what they readily need. Automated Email Delivery Sisense allows users to automate schedules for data delivery. This lets you assert better control over information dissemination. More importantly, it lets you give a time-stamped set of metrics to users and empowers them to explore the data themselves. This passive access is vital for adoption as it increases the perception that data is available at their fingertips. Integration With Existing Tools Some stakeholders may prefer not to open a completely different program to view their dashboards or analytics. In these cases, the best course of action is to integrate these dashboards directly with the applications commonly being utilized. This is a productive strategy for increasing familiarity without forcing users into a completely new platform and allows stakeholders to gradually learn more about Sisense tools. Export Functionality Although Sisense is more than a reporting tool, some users may need quick access to specific data or dashboards without the drill-down functionality that a true BI tool offers. Users can manually export dashboards directly into Excel or download them as a PDF. Anyone can access data to add to a presentation or even manipulate themselves separately. This hands-on model encourages stakeholders to actively view dashboards and increases traction by clearly demonstrating value in terms of usability. Using Sisense Pulse to Automate Access You can also automate much of the data access process by integrating Sisense Pulse. This empowers you to automate KPIs and other reporting by simply notifying stakeholders of changes in KPIs. Instead of manual access and exploration, some users can simply receive a notice if something vital to their role changes or goes wrong, giving them a more focused view of a broad dashboard or dataset.     The biggest upsides of Pulse are building an organizational culture focused on data-driven decisions and normalizing data access across teams.

      Community_Admin
      Community_AdminPosted 1 year ago
      0
               
      • APIsChevronRightIcon

      Using the InternalHttp Function Within Scripts and Plugins

                                                                                                                               

      Using the InternalHttp Function Within Scripts and Plugins The InternalHttp function is a Sisense function within the Sisense internal Prism object. The prism object and the InternalHttp function are present on all Sisense pages and can be used in scripts and plugins, including when embedded with various forms of Sisense embedding . It facilitates custom additional API requests to the Sisense server by applying the same request headers used for internal Sisense requests to handle details of API requests such as authentication , CORS , and CSRF . Custom additional requests to Sisense API endpoints via custom scripts and plugins are often utilized to perform additional JAQL requests for fetching data from Sisense data models. This process is documented in this informative Sisense Community page . The Community page code remains current and includes an example of using the InternalHttp function for additional JAQL requests. Below is a simplified and shortened version of the example code:     widget.on('ready', function (se, ev) { function runHTTP(jaql) { // Use $internalHttp service if exists const $internalHttp = prism.$injector.get("base.factories.internalHttp"); const ajaxConfig = { url: "/api/datasources/x/jaql", method: "POST", data: JSON.stringify(jaql), contentType: "application/json", dataType: "json", async: false, }; const httpPromise = $internalHttp(ajaxConfig, true); // Return response values return httpPromise.responseJSON.values; } const jaqlObj = { "datasource": { "title": "Sample ECommerce", }, "metadata": [ { "jaql": { "dim": "[Category.Category]", } } ] }; console.log('JAQL Result Values are ', runHTTP(jaqlObj)); });     While InternalHttp is commonly used for JAQL API requests, it can be utilized for any Sisense endpoint, allowing custom requests to any Sisense API, not just those related to JAQL. The JAQL API is how Sisense requests data from Sisense data sources. The flexibility offered by custom API calls significantly enhances the capabilities of scripts, enabling developers to interact with the full range of Sisense functionalities. Notable Recent Resolved Scenarios and the InternalHttp Function CSRF Header Issue: A customer who previously did not use InternalHttp had various widget scripts making custom JAQL requests via the JAQL API endpoint. After modifying the CSRF setting, these scripts failed, and not only did not work, but viewing the widget logged the user out of Sisense immediately. The issue was due to missing CSRF header parameters in the request headers. This was most easily resolved by using InternalHttp in the widget scripts, which automatically includes the required CSRF header parameters. Unauthorized Errors with Sisense.js: A customer using Sisense embedded with Sisense.js on a third party domain and using WAT for authentication faced "Unauthorized" API errors for the custom widget script JAQL requests. Despite working outside of WAT , these requests failed within it. This issue is a known limitation with internalHttp. The workaround for this issue is demonstrated below:     widget.on('beforequery', function (se, ev) { function runHTTP(jaql) { // Use $internalHttp service if exists const $internalHttp = prism.$injector.has("base.factories.internalHttp") ? prism.$injector.get("base.factories.internalHttp") : null; const ajaxConfig = { url: "/api/datasources/x/jaql", method: "POST", data: JSON.stringify(jaql), contentType: "application/json", dataType: "json", async: false, xhrFields: { withCredentials: true, }, }; const httpPromise = $internalHttp ? $internalHttp(ajaxConfig, false) : $.ajax(ajaxConfig); // Return response return httpPromise; } const jaqlObj = { "datasource": { "title": "Sample ECommerce", }, "metadata": [ { "jaql": { "dim": "[Category.Category]", } } ] }; runHTTP(jaqlObj).then((API_Response) => { console.log('JAQL Result Values are ', API_Response.data.values); }); }); ​     In this workaround, the second parameter of the InternalHttp function is set to false, and the returned object is handled as a JavaScript promise. The InternalHttp function is designed to be updated along with Sisense, and to adapt to any changes, allowing for scripts written for one environment (in the native Sisense UI for example) to work in many others without issue (when embedded in a third-party domain for example). These scenarios highlight the value of InternalHttp and its potential applications. Leveraging this function allows developers to ensure their custom scripts remain robust and secure in all scenarios, including in environments with specific security requirements or complex authentication mechanisms. As Sisense continues to evolve and update, understanding and utilizing internal tools like internalHttp will be helpful for maximizing the platform's capabilities and maintaining seamless integration within various deployment and embedded contexts.

      Jeremy Friedel
      Jeremy FriedelPosted 1 year ago
      0