PBR Posted August 29 Share Posted August 29 (edited) Hello, I am trying to synchronize the zoom sliders of two line charts based on their X-axes, so that when the zoom on the first chart changes, the second chart updates accordingly. However, I’m facing an issue because the time format in the two charts is different. In the first chart, the time is read directly from a column [Time]. In the second chart, the time is based on binning with <BinByDateTime([Time],"Year.Quarter.Month.DayOfMonth.Hour",4)>, which shows hourly, monthly, quarterly, and yearly averages. I am trying to adjust the code below to synchronize the zoom to the hourly average on the second chart, and then plan to extend this to other bins as well. Any help or suggestions would be appreciated. Thank you! from Spotfire.Dxp.Application.Visuals import AxisRange, LineChart from System import DateTime def round(dt): minutes = dt.Minute if minutes >= 30: dt = dt.AddHours(1) return DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, 0, 0) # visA and visB are scripting parameters LineA = visA.As[LineChart]() LineB = visB.As[LineChart]() zoomAX = LineA.XAxis.ZoomRange # Round the start and end times to the nearest hour rounded_low = round(zoomAX.Low) rounded_high = round(zoomAX.High) axisRangeX = AxisRange(rounded_low, rounded_high) LineB.XAxis.ZoomRange = axisRangeX Edited August 29 by PBR Link to comment Share on other sites More sharing options...
Gaia Paolini Posted August 29 Share Posted August 29 Would it not be so much easier to have a slider filter in a Text Area for the [Time] column, so that when you slide the filter both line charts react at the same time? Link to comment Share on other sites More sharing options...
PBR Posted August 29 Author Share Posted August 29 Hi Gaia, Using the filter leads to a sudden shift in visualizing the data. However, using the zoom sliders provides a smoother zooming experience. I tried using the filter, but it makes it difficult to track the specific time we are looking for. Link to comment Share on other sites More sharing options...
Gaia Paolini Posted August 29 Share Posted August 29 how do you want this to work? a) change the zoom on line chart 1 b) press the button c) zoom on line chart 2 is changed? Link to comment Share on other sites More sharing options...
PBR Posted August 29 Author Share Posted August 29 Yes, exactly. Link to comment Share on other sites More sharing options...
Jose Leviaguirre Posted August 29 Share Posted August 29 (edited) Looks like you are trying to do something like this. Here is the article found on the description of such video, but it might not work on different scales, so you might need to convert the raw time range from Chart A to the corresponding bin intervals in Chart B because Chart A uses raw time data, so the ZoomRange on the X-axis can be directly set and Chart B uses binned time data, which means the time axis is represented in intervals (e.g., hourly, daily). If you apply a ZoomRange based on raw time data to a binned time axis, the range may not align correctly with the bins. Try this code from Spotfire.Dxp.Application.Visuals import AxisRange, LineChart from System import DateTime # Helper function to round down to the nearest bin interval (e.g., hour) def round_down_to_bin(dt, binning_interval): if binning_interval == "Hour": return DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, 0, 0) elif binning_interval == "Day": return DateTime(dt.Year, dt.Month, dt.Day) # Add more intervals as needed else: return dt # No rounding for unsupported intervals # visA and visB are scripting parameters LineA = visA.As[LineChart]() LineB = visB.As[LineChart]() # Get the current zoom range of LineA zoomAX = LineA.XAxis.ZoomRange # Assume the binning interval in LineB is hourly (adjust as necessary) binning_interval = "Hour" # This should match the binning setup of LineB # Convert the start and end times to match the binning interval rounded_low = round_down_to_bin(zoomAX.Low, binning_interval) rounded_high = round_down_to_bin(zoomAX.High, binning_interval) # Set the new zoom range on LineB axisRangeX = AxisRange(rounded_low, rounded_high) LineB.XAxis.ZoomRange = axisRangeX Edited September 3 by Jose Leviaguirre 1 Link to comment Share on other sites More sharing options...
PBR Posted September 3 Author Share Posted September 3 Thank you Jose for your reply. When I print rounded_low or rounded_high, it is showing the right numbers. But it still cannot implement the binned dates on x-axis. The second line chart is updating like below: Link to comment Share on other sites More sharing options...
Jose Leviaguirre Posted September 3 Share Posted September 3 Do you have a dxp or script that you can share? Link to comment Share on other sites More sharing options...
PBR Posted September 3 Author Share Posted September 3 Thank you Jose This an example of my problem. It is based on some fake data. I don's see the similar issue as I see in my real case, but still it is not working. I hope to understand the issue to extend it to my real case. Test_Sync_Zoomslider.dxp Link to comment Share on other sites More sharing options...
Jose Leviaguirre Posted yesterday at 01:43 AM Share Posted yesterday at 01:43 AM Hello PBR, It seems that you are using a categorical scale on your second graph. When using the zoom range (AxisRange) with categorical data, the range is expressed with indices. The indices are integers, so you will need to calculate the indices. To understand a bit more the indices on the range when using categorial measures, If you make your first graph categorical and without any aggregation or binning, you will have 2000 indices from your 2K rows. For the second graph, you will have less indices depending on the binning. If your 2000 rows represents 5 days of data and you bin by day, then you will have 5 indices. Basic Example: #leaves out the first and last 10 data points from your 2,000 datapoints assuming you have a categorical axis without any binning or aggregations LineA.XAxis.ZoomRange = AxisRange(10, 1990) For your particular use case, you will need to determine the index number your data falls into, unless there is a property that reveals that, which I am not aware of. Here is a function that calculates the corresponding indices based on the difference in hours between given dates. Note that it will only work for day / hour binning: from Spotfire.Dxp.Application.Visuals import AxisRange, LineChart # visA and visB are scripting parameters LineA = visA.As[LineChart]() LineB = visB.As[LineChart]() #data table can be a script param. we need min and max values #dt = Document.ActiveDataTableReference # Get the current zoom range of LineA zoomAX = LineA.XAxis.ZoomRange def get_indices(min_date, max_date, date1, date2): # Calculate the total number of hours between min_date and max_date total_hours = int((max_date - min_date).TotalHours) # Calculate the index for date1 hours1 = int((date1 - min_date).TotalHours) index1 = hours1 + 1 # Adding 1 to make the index 1-based # Calculate the index for date2 hours2 = int((date2 - min_date).TotalHours) index2 = hours2 + 1 # Adding 1 to make the index 1-based return index1, index2 min_date = (dt.Columns["Time"].RowValues.GetMinValue()).Value max_date = (dt.Columns["Time"].RowValues.GetMaxValue()).Value date1 = LineA.XAxis.ZoomRange.Low date2 = LineA.XAxis.ZoomRange.High #get the indices for the month > hour use case min_index_b, max_index_b = get_indices(min_date, max_date, date1, date2) LineB.XAxis.ZoomRange = AxisRange(min_index_b, max_index_b) A work around that does not depend on the binning function that calculates the indices, is to use a separate filter scheme for your second graph, and set that second graph react to that second filter programmatically. It requires your first graph to have a continuous X Axis from Spotfire.Dxp.Application.Visuals import AxisRange, LineChart from Spotfire.Dxp.Application.Filters import RangeFilter, ValueRange #dt is script param # visA and visB are scripting parameters LineA = visA.As[LineChart]() LineB = visB.As[LineChart]() #get a hold of the second filtering scheme filt=Document.FilteringSchemes[1].Item[dt].Item[dt.Columns.Item["Time"]].As[RangeFilter]() #reset zoom LineB.XAxis.ManualZoom = False LineB.XAxis.ManualZoom = True # Get the current zoom range of LineA zoomAX = LineA.XAxis.ZoomRange #set second chart filter with min, max from fist_chart date1 = LineA.XAxis.ZoomRange.Low date2 = LineA.XAxis.ZoomRange.High filt.ValueRange = ValueRange(date1,date2) Another much simpler option that requires no coding is to limit by marking and hide the zoom range slider. Will that work? Attached is a sample with those 3 different options Test_Sync_Zoomslider_Jose.dxp Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now