Jump to content

Synchronizing Zoom Sliders Between Line Charts with Different Time Formats


PBR
Go to solution Solved by Jose Leviaguirre,

Recommended Posts

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 by PBR
Link to comment
Share on other sites

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

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 by Jose Leviaguirre
  • Like 1
Link to comment
Share on other sites

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:

image.thumb.jpeg.a90ac7849f3fc7ddfce8c2490c6fe87e.jpeg

Link to comment
Share on other sites

  • Solution

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


syncsliders.thumb.gif.5756958e5a698662f17a2d2af76d5122.gif

Test_Sync_Zoomslider_Jose.dxp

  • Like 1
Link to comment
Share on other sites

Hi Jose,

I tried method 2 and 3. 

I used method 2 when the zoom slider is on, and when I want to synch it manually.

However, I am using markings as well as it is much simpler as you mentioned, and I can limit both graphs to that marking.

Thank you

  • Like 1
Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...