Jump to content

Jose Leviaguirre

Spotfire Team
  • Posts

    208
  • Joined

  • Last visited

  • Days Won

    3

Jose Leviaguirre last won the day on May 16

Jose Leviaguirre had the most liked content!

3 Followers

Recent Profile Visitors

443 profile views

Jose Leviaguirre's Achievements

Community Regular

Community Regular (8/14)

  • Reacting Well Rare
  • Problem Solver Rare
  • Dedicated Rare
  • Week One Done
  • One Month Later

Recent Badges

10

Reputation

12

Community Answers

  1. Here are some more date expression functions Today [Date]=Date(DateTimeNow()) Last 30 Days [Date] >= dateadd('dd',-30,DateTimeNow()) This Week Week([Date]) = week(DateTimeNow()) and Year([Date]) = year(DateTimeNow()) This Month Month([Date]) = month(DateTimeNow()) and Year([Date]) = year(DateTimeNow()) Year to Date Year([Date]) = Year(DateTimeNow()) Last Month Last 12 Months Month([Date]) = Month(dateadd('mm',-1,DateTimeNow())) and Year([Date]) = Year(dateadd('mm',-1,DateTimeNow())) [Date] >= dateadd('mm',-12,DateTimeNow()) Q1 Quarter([Date]) = 1 and Year([Date]) = Year(DateTimeNow()) Q2 Quarter([Date]) = 2 and Year([Date]) = Year(DateTimeNow()) Q3 Quarter([Date]) = 3 and Year([Date]) = Year(DateTimeNow()) Q4 Quarter([Date]) = 4 and Year([Date]) = Year(DateTimeNow()) Begining of Month Date(Year(DateTimeNow()),Month(DateTimeNow()),1) End of Month DateAdd('day',-1,date(Year(DateTimeNow()),Month(DateAdd('month',1,DateTimeNow())),1)) End of Last Month DateAdd("day",-1,date(Year(DateTimeNow()),Month(DateTimeNow()),1)) End of Next Month DateAdd("day",-1,date(Year(DateTimeNow()),Month(DateAdd("month",2,DateTimeNow())),1)) First Weekending of the year Dateadd("day",6 - DayOfWeek(DATE(Year(DateTimeNow()),1,1)), DATE(year(DateTimeNow()),1,1)) Last Weekending (last saturday) DateAdd("week",Week(DateTimeNow()) - 2,Dateadd("day",6 - DayOfWeek(DATE(Year(DateTimeNow()),1,1)),DATE(year(DateTimeNow()),1,1))) End of this week DateAdd("week",Week(DateTimeNow()) - 1,Dateadd("day",6 - DayOfWeek(DATE(Year(DateTimeNow()),1,1)),DATE(year(DateTimeNow()),1,1))) End of next week Date(DateAdd("week",Week(DateTimeNow()),Dateadd("day",6 - DayOfWeek(DATE(Year(DateTimeNow()),1,1)),DATE(year(DateTimeNow()),1,1)))) Previous Quarter end date DateAdd("day",-1,DateAdd("quarter",Quarter(DateTimeNow()) - 1,Date(Year(DateTimeNow()),1,1)))
  2. This code provides a user-friendly way to confirm actions in Spotfire, preventing accidental executions and enhancing the user experience. The confirmation dialog ensures that users are certain before proceeding with the execution, while the friendly message upon cancellation maintains a positive interaction. html <div id="confirmExecute"> <SpotfireControl id="replace with Spotfire Action Control button" /> </div> <div id="actualExecute" style="position:fixed;top:-100px"> <SpotfireControl id="replace with Spotfire Action Control button" /> </div> confirmExecute: This <div> contains the Spotfire control that will display a confirmation dialog when interacted with. It triggers an IronPython script that does nothing (the script is empty, it's just a placeholder). The JavaScript takes cares of the popup confirmation dialog. actualExecute: This <div> contains the Spotfire control that performs the actual execution. It is positioned off-screen using the CSS position:fixed;top:-100px style to keep it hidden. It is linked to the actual IronPython, DataFunction or any other element the Spotfire Action Control can handle. JavaScript // Setup the first Spotfire control button (that does nothing) to show a confirm dialog document.querySelector("#confirmExecute input").onclick = function() { Spotfire.ConfirmDialog.showYesNoCancelDialog("Confirm Execution", "Do you really want to execute?", okClick, noClick, null); } // Programmatically click on Spotfire control when confirming okClick = function(x) { document.querySelector("#actualExecute input").click(); } // Display a friendly message if the user cancels noClick = function(x) { Spotfire.ConfirmDialog.showDialog("OK", "No worries!", []); } The first Spotfire control (#confirmExecute) is set up to show a confirmation dialog when clicked. The dialog has "Yes", "No", and "Cancel" options, triggering the corresponding functions: okClick for "Yes" and noClick for "No". The okClick Function: If the user confirms the execution by clicking "Yes", the okClick function is called, which programmatically clicks the hidden Spotfire control in the #actualExecute <div>, triggering the actual execution. The noClick Function: If the user clicks "No", the noClick function displays a friendly message dialog using Spotfire.ConfirmDialog.showDialog. Important Note: the Spotfire.ConfirmDialog.showDialog is not a public API that can change at any time and might not work on future versions of Spotfire. This is just to illustrate the concept. You could also use the confirm dialog instead or create your own confirmation dialog.
  3. The Dr. Spotfire Monthly Live Session for May is "Spotfire Authoring Session Part 2: Data Wrangling" will continue to showcase authoring capabilities in Spotfire. Other topics during this session might include data wrangling and preparation, data relationships, visualizations, tagging, bookmarks, and useful data functions. Watch on YouTube LinkedIn X (Twitter) Facebook
  4. To iterate through the columns of a specific table in Spotfire and print their names and data types, you can use the following code. This script iterates through the columns of a specified table and prints the column names along with their data types. # Replace with the actual table name table_name = "Data Table" # Get the table by name table = Document.Data.Tables[table_name] # Print the table name print("Table:", table_name) # Iterate through the columns and print their names and data types for column in table.Columns: print(f"{column.Name} ({column.Properties.DataType})") # Alternatively, iterate through all tables and their columns for t in Document.Data.Tables: print("Table:", t.Name) columnCollection = t.Columns for col in columnCollection: print("\t", col.Name, "(", col.Properties.DataType, ")") Here is an explanation of each part of the script: Get the Specific Table: table_name = "Data Table": Specify the name of the table you want to examine. table = Document.Data.Tables[table_name]: Get the table object by its name. Iterate Through the Columns of the Specified Table: for column in table.Columns:: Loop through each column in the specified table. print(f"{column.Name} ({column.Properties.DataType})"): Print the column name and its data type. Iterate Through All Tables and Their Columns: for t in Document.Data.Tables:: Loop through each table in the document. print("Table:", t.Name): Print the name of the table. columnCollection = t.Columns: Get the collection of columns for the current table. for col in columnCollection:: Loop through each column in the current table. print("\t", col.Name, "(", col.Properties.DataType, ")"): Print the column name and its data type with proper formatting. Sample output Table: Data Table Column1 (String) Column2 (Integer) Column3 (Real) Column4 (DateTime) Table: Data Table Column1 (String) Column2 (Integer) Column3 (Real) Column4 (DateTime) Table: Other Table ColumnA (String) ColumnB (Integer) ColumnC (Boolean)
  5. Introduction When working with complex Spotfire analyses, understanding how data tables are utilized across various visualizations can be crucial. This can help in optimizing the performance and ensuring that all data sources are being used effectively. Here’s a Python script that can help you identify which data tables are being used by the visualizations in your Spotfire document and where they are used. Understanding the Script The script provided below scans through the entire Spotfire document and lists all the data tables. It checks which tables are being utilized in visualizations and identifies their exact locations within the document. This can be particularly useful for cleaning up unused tables or for understanding the dependencies in your analysis. Key Features Identify Data Table Usage: The script identifies which data tables are being used by visualizations, except for those used in calculated values on text areas. Locate Dependencies: It details the locations (pages and visual titles) where each data table is used. Highlight Unused Tables: It lists tables that are not being used in any visualization, helping in cleanup and optimization efforts. #Find Data Table Dependencies in Document Visualizations #Shows what DataTables are being used by which visualization except those used in calculated values on text areas. #This scirpt does not detect what datatables rely on tables from current analysis from Spotfire.Dxp.Application.Visuals import VisualContent, VisualTypeIdentifiers tables={} for t in Document.Data.Tables: tables[t.Name]=False locations = "" for page in Document.Pages: for visual in page.Visuals: if visual.TypeId != VisualTypeIdentifiers.HtmlTextArea: vis = visual.As[VisualContent]() dtrtype = str(type(vis.Data.DataTableReference)) if(dtrtype)<>"<type 'NoneType'>": aTable = vis.Data.DataTableReference.Name aLocation = " -> ".join([aTable,page.Title,visual.Title]) tables[aTable]=True locations += "\n\t" + aLocation print "Tables not being used:" for t in sorted(tables): if not tables[t]:print "\t",t print "\nTables being used:" for t in sorted(tables): if tables[t]:print "\t",t print "\nTables in used by:" print locations How to Use the Script Copy and Paste: Copy the script and paste it into the Spotfire Script Editor. Run the Script: Execute the script to get a detailed report of the data table usage. Analyze the Output: Use the output to identify unused tables and understand where and how your data tables are being utilized. Sample Output Tables not being used: UnusedTable1 UnusedTable2 Tables being used: SalesData CustomerData ProductData InventoryData Tables in use by: SalesData -> Dashboard -> Sales Overview SalesData -> Dashboard -> Monthly Sales Trends CustomerData -> Customer Analysis -> Customer Demographics CustomerData -> Customer Analysis -> Customer Spending Patterns ProductData -> Product Performance -> Top Selling Products ProductData -> Product Performance -> Product Sales Trends InventoryData -> Inventory Management -> Current Stock Levels InventoryData -> Inventory Management -> Stock Replenishment Rates
  6. Introduction This article explains how to implement row level security in Spotfire using information links Requirements You need to have two data tables in your database, one which contains all of your data (AllData) and one which contains the security mapping which will be used to limit the data returned (SecurityMapping) as well as the corresponding Information Designer elements. For example: AllData Table MatchColumn ActualData Finance Finance Record 1 Finance Finance Record 2 Sales Sales Record 1 Sales SalesRecord 2 This is your data that must contain a way to identify records that can be mapped to a security mappings table SecurityMappings Table UserName MatchColumn User1 Finance User1 Sales User2 Sales User3 Finance This is your access table. User 1 has access to Finance and Sales records. User 2 has access only to Sales records and User 3 only has access to finance records Step by Step instructions Create column elements for AllData and SecurityMapping. Create a Filter element in Information Designer for "UserName" column in "SecurityMapping" table - Name it UserName_Filter. Change the expression to "%1=%CURRENT_USER%" . Make sure that %CURRENT_USER% and UserName are in the same format, e.g., "user@email.com" versus "user". note: You can verify this by running an information link and checking the SQL in sql.log. Create an Information link - AllData_IL . Add both columns (MatchColumn, ActualData) from AllData table. Create an Information link - SecurityMapping_IL . Add both columns (MatchColumn, UserName) from SecurityMapping table. Add filter created earlier - UserName_Filter . Add data table to your analysis. File >> Add Data Table >> Information Link >> AllData_IL . Insert columns from SecurityMapping information link. Insert >> Column >> Add Columns From >> Information Link >> SecurityMapping_IL >> Match on "MatchColumn" >> Inner Join (Rows matching in both original and new data only). Edit data table properties to exclude "SecurityMapping" from schedule updates so that it is loaded for each user. Edit >> Data Table Properties >> Schedule Updates >> Select the checkbox for SecurityMapping_IL (Reload the following data for each user). Now, if you want to use Scheduled Updates, they can be used together with personalized information links to achieve row level security using the "Reload the following data for each user" functionality. This has the performance benefits of caching the primary data table in Scheduled Updates as well as the security benefits of personalized information links so that each user sees only the data they are allowed to see. When User2 logs in, it will load AllData_IL from the WebPlayer cache since it is preloaded during schedule updates. It will do a fresh load of SecurityMapping_IL and will only load the 2nd row in above example (Finance, User 2). When doing an inner join between AllData_IL and SecurityMapping_IL, all rows with Finance in MatchColumn will be loaded. Reference: KB 42244
  7. Hello @Dario Solohaga I am sure you are referring to this article or QT Video regarding this example . Make sure you hace the min_lat_lon and max_lat_lon calibrated properly. That's all I did!
  8. That is a great Idea Renger. Please vote for it here A work around is to use a line connection by [sample] on your scatter plot. I've added a row for each row with a value of -1 and set the axis scale from 0 to automatic to hide the connecting markers . For the labels I used the [group] column If you don't want to change the axis scale range from 0 to auto and you want to avoid seeing double labels for the connecting markers, you can use something like "If([Value]>0,[Group])" expression to only shows top labels. If any of these out of the box solutions do not fit for purpose, you can always explore creating or modifying custom visualization (Visualization Mods). Are you aware of this? Remember that Spotfire is a platform and it has different ways to extend it (check the Visualization mods section here). For simple charts, you can also render visuals on text areas
  9. To get the image dimensions from an image layer on a Map visualization, just uncheck the marker layer or remove the Positioning markers (geocoding or coordinate columns) from the marker layer, go back to the image layer and hit the reset button
  10. This article explains how to extend Spotfire with JavaScript enhancing the user interface and user experience (UI/UX) by implementing smooth scrolling features, custom scroll buttons for improved navigation, and handling. Sometimes we want to keep a fixed height to create browser style analysis or prevent the visualizations to shrink too much by using the Page Layout Options, Locking visualization areas or using a fixed Canvas size to allow to fit more content without crumbling the visualizations together. This solution adds custom buttons on the side of the screen when the vertical scroll bars appear. These buttons allows to go to the end of the page or to the top with a single click. This is particularly useful when the screen is not big enough or you want to check out the contents of a page at a glance. First we add on any Text Area the following html code to add the buttons that are displayed at the right of the screen html <div id="scrollButtons" style="text-align:center;background:beige;border:1px solid;cursor:pointer; gray;padding:5px;position:fixed;right:30px;top:50vh;color:black;z-index:1"> <div id="sTop" title="scroll to top">▲</div> <div id="sBottom" title="scroll to bottom">▼</div> </div> Then we add this script that will hide the buttons when there is no scrolling to make, but are shown when it is needed. The script will add the required instructions to scroll up or down the page. JavaScript (not smooth) function scrollButtons() { const cssSelector = ".sf-element-visualization-area [style*='overflow: scroll'], .sf-element-visualization-area [style*='overflow: hidden scroll;']" function checkScrollbar() { const scrollableElement = document.querySelector(cssSelector); const scrollButtons = document.getElementById('scrollButtons'); if (scrollableElement && scrollableElement.scrollHeight > scrollableElement.clientHeight) { scrollButtons.style.display = 'block'; } else { scrollButtons.style.display = 'none'; } } // Call checkScrollbar on page load checkScrollbar(); // Call checkScrollbar whenever the window is resized window.addEventListener('resize', checkScrollbar); document.getElementById('sTop').addEventListener('click', function() { const scrollableElement = document.querySelector(cssSelector); if (scrollableElement) scrollableElement.scrollTop = 0; }); document.getElementById('sBottom').addEventListener('click', function() { const scrollableElement = document.querySelector(cssSelector); if (scrollableElement) scrollableElement.scrollTop = scrollableElement.scrollHeight; }); }; scrollButtons(); if you want to add smoothness to your scroll, then use this function JavaScript (with smooth scrolling) function scrollButtons() { const cssSelector = ".sf-element-visualization-area [style*='overflow: scroll'], .sf-element-visualization-area [style*='overflow: hidden scroll;']"; const scrollButtons = document.getElementById('scrollButtons'); let scrollableElement = null; function checkScrollbar() { scrollableElement = document.querySelector(cssSelector); if (scrollableElement && scrollableElement.scrollHeight > scrollableElement.clientHeight) { scrollButtons.style.display = 'block'; } else { scrollButtons.style.display = 'none'; } } // Call checkScrollbar on page load checkScrollbar(); // Call checkScrollbar whenever the window is resized window.addEventListener('resize', checkScrollbar); document.getElementById('sTop').addEventListener('click', function() { if (scrollableElement) smoothScroll(scrollableElement, 0, 500); }); document.getElementById('sBottom').addEventListener('click', function() { if (scrollableElement) smoothScroll(scrollableElement, scrollableElement.scrollHeight, 500); }); // Smooth scroll function function smoothScroll(element, target, duration) { let start = element.scrollTop; let change = target - start; let startTime = performance.now(); function animateScroll(currentTime) { let timeElapsed = currentTime - startTime; let progress = timeElapsed / duration; progress = Math.min(progress, 1); element.scrollTop = start + change * progress; if (progress < 1) { requestAnimationFrame(animateScroll); } } requestAnimationFrame(animateScroll); } } // Initialize the scrollButtons function scrollButtons();
  11. Hello Padmini You will need to create an Action Control on a Text Area and associate an IronPython script to it. The script will be something like: from Spotfire.Dxp.Application.Visuals import AxisRange, ScatterPlot # vis is a script parameter scatter = vis.As[ScatterPlot]() # update X zoom range axisRangeX = AxisRange(2000,3000) scatter.XAxis.ZoomRange = axisRangeX # update Y zoom range axisRangeY = AxisRange(400,500) scatter.YAxis.ZoomRange = axisRangeY Another option that requires no coding is to use bookmarks Check out these articles on how you can use IronPython to programatically set the zoom sliders to a specific position. https://community.spotfire.com/articles/spotfire/configuring-spotfire-zoom-sliders-scroll-bars-etc-using-ironpython/ https://community.spotfire.com/articles/spotfire/sync-scrollbars-between-visualizations/
  12. Hello Khushbu, Can you share your script? Did you submit a support ticket? Without knowing the details of your script, , this error typically occurs when the script takes too long to execute, exceeding the default timeout limit. This limit is usually set to prevent long-running scripts from causing performance issues or freezing the application. To resolve this issue, you can try the following: - Increase the script timeout limit in Spotfire settings- - Optimize the script for better performance - Break down the script into smaller, more efficient tasks - Check for any data or connection issues that may be causing the script to hang
  13. When a document property changes, it highlights a visual. This can be useful for data analysis to pay close attention to visuals that require attention. The way it works is that a text area holds a json structure with value pairs for each visualization title to highlight. If we take for example the Analyzing Stock Performance dashboard, we take the visualizations that we want to highlight: html (hard-coded) <pre id=docPropValues > { "Indexed price charter":"True", "Top holders by percent held":"False", "Historical data":"True", "Calendar quarter estimates":"False" } </pre> and then we add this script to see if those visualizations that are set to true are highlighted. The script monitors changes on the docPropValues tag and parses the json structure. When the value changes, it runs the scripts that changes the color of the visualization border. JavaScript //finds visuals in which title contains visualTitle (use *= for contains, ^= starts with, $= ends with or = exact match) elements = Array.from(document.querySelectorAll(".sf-element.sf-element-visual")); function highlighVisual(visualTitle){ //set background for those visuals found elementWithChild = elements.filter(element => element.querySelector("[title*='"+visualTitle+"']") !== null); //<-- change here for search operator elementWithChild.forEach(x=>x.style.background="red") } element = document.querySelector('#docPropValues'); observer = new MutationObserver(_ => { json = JSON.parse(element.innerText); //reset visual backgrounds elements.forEach(x=>{x.style.background=""}) Object.entries(json) .filter(([key, value]) => value === "True") .map(([key, value]) => key) .forEach(visualTitle => {highlighVisual(visualTitle)}); }); observer.observe(element, { childList: true, characterData: true, subtree: true }); Then we can replace the hardcoded values from with a calculated value or label document property to make it dynamic HML (Dynamic) <pre id=docPropValues > { "Indexed price charter":"<SpotfireControl id="boolean document property" />", "Top holders by percent held":"<SpotfireControl id="boolean document property" />", "Historical data":"<SpotfireControl id="boolean document property" />", "Calendar quarter estimates":"<SpotfireControl id="boolean document property" />" } </pre> Note: In the screen capture animation I used a calculated value that shows a Boolean document property that runs an IronPython script that toggles the value of the property when clicked.
×
×
  • Create New...