Jump to content

Kin How

Seeq Team
  • Posts

    27
  • Joined

  • Last visited

  • Days Won

    7

Posts posted by Kin How

  1. 16 hours ago, KantianKinetics said:

    Current Error:

    I'm now getting error on push: 

    Quote

    SPy Error: Error processing OFPOF: The parameter had multiple entries in the DataFrame Error found at line 1 in cell 171.

    Unsure why, since the Formula shouldn't care if the signal variable name is reused.  I was told the variables don't work globally, e.g. either of the following would work as long as they are tied appropriately to the formula parameter.  Is this not true?  

    ($OFCoC2 + $OFCoC3 + $OFCoC5 + $OFCoC6 + $OFCoC7) / 100 * $FaPOF

    ($a + $b + $c + $d +$e) / 100 * $g

    Yes, either of the formula parameter combinations will work for your case. 

    The error message you received, SPy Error, indicates that there were multiple entries of $OFPOF in the DataFrame. This suggests that there might be more than one match found in your df. To confirm this, could you please print df and check?

  2. 12 hours ago, KantianKinetics said:

     The "Formula Parameters" column contains a string of format below in the code snippet for each formula i want to generate.  I perform eval() on the string once its read into python to grab the ID of the search_results (now df) from SEEQ.  Obviously my SEEQ data is in the imported CSV file asset = 'advisor_elements_sOiltags_leastCleaned_v2_csv(import)':  

    {
    	'$OFCoC2':df[(df['Asset'] =='advisor_elements_sOiltags_leastCleaned_v2_csv(import)') & (df['Name'] == 'Olefin Feed Composition_online C3=')],
    	'$OFCoC3':df[(df['Asset'] =='advisor_elements_sOiltags_leastCleaned_v2_csv(import)') & (df['Name'] == 'Olefin Feed Composition_online C4=1')],
    	'$OFCoC5':df[(df['Asset'] =='advisor_elements_sOiltags_leastCleaned_v2_csv(import)') & (df['Name'] == 'Olefin Feed Composition_online C4=2c')],
    	'$OFCoC6':df[(df['Asset'] =='advisor_elements_sOiltags_leastCleaned_v2_csv(import)') & (df['Name'] == 'Olefin Feed Composition_online C4=2t')],
    	'$OFCoC7':df[(df['Asset'] =='advisor_elements_sOiltags_leastCleaned_v2_csv(import)') & (df['Name'] == 'Olefin Feed Composition_online C4=i')],
    	'$FaPOF':df[(df['Asset'] =='advisor_elements_sOiltags_leastCleaned_v2_csv(import)') & (df['Name'] == 'Feed and Products Olefin Feed+HYC')]
    }

    Your code should return the actual ID of the item after adding ['ID].iloc[0] to the end of each line. Please try the "Formula Parameter" below:

    {
    	'$OFCoC2':df[(df['Asset'] =='advisor_elements_sOiltags_leastCleaned_v2_csv(import)') & (df['Name'] == 'Olefin Feed Composition_online C3=')]['ID'].iloc[0],
    	'$OFCoC3':df[(df['Asset'] =='advisor_elements_sOiltags_leastCleaned_v2_csv(import)') & (df['Name'] == 'Olefin Feed Composition_online C4=1')]['ID'].iloc[0],
    	'$OFCoC5':df[(df['Asset'] =='advisor_elements_sOiltags_leastCleaned_v2_csv(import)') & (df['Name'] == 'Olefin Feed Composition_online C4=2c')]['ID'].iloc[0],
    	'$OFCoC6':df[(df['Asset'] =='advisor_elements_sOiltags_leastCleaned_v2_csv(import)') & (df['Name'] == 'Olefin Feed Composition_online C4=2t')]['ID'].iloc[0],
    	'$OFCoC7':df[(df['Asset'] =='advisor_elements_sOiltags_leastCleaned_v2_csv(import)') & (df['Name'] == 'Olefin Feed Composition_online C4=i')]['ID'].iloc[0],
    	'$FaPOF':df[(df['Asset'] =='advisor_elements_sOiltags_leastCleaned_v2_csv(import)') & (df['Name'] == 'Feed and Products Olefin Feed+HYC')]['ID'].iloc[0]
    }

    After that, the spy.push() should run without error. Let me know the outcome after trying it. 

  3. On 10/27/2023 at 4:37 AM, KantianKinetics said:

    As you can see in Row 1, The Formula Parameter array is empty for the signal $OFPOF.  This is the formula generated for the row above, Row 0.  This is because I haven't pushed it to SEEQ.  You can see the error in the image below.  Do I need to actually push each row to SEEQ and then search again to get this to work right?  I don't have a huge set of calculations, but it seems there should be a better way.  

     

    To ensure a successful metadata push, the Formula Parameter array must contain the actual ID of the item in Seeq. In your screenshot, row 0 failed to push because the Formula Parameter did not contain the actual ID for each item. You cannot proceed with just {'$OFCoC2'=['ID'], ...}. Instead, you need to specify the ID for each item, for example {$OFCoC2=['0EE76D39-3D08-FF40-BBFF-53255CCEB514'], ...}. You can use spy.search() to obtain the ID of each item in your formula and map those IDs to the corresponding Formula Parameter. Therefore, you need to push row 0 to Seeq to get the ID of the item and map the ID to row 1 before you can push row 1.

     

    On 10/27/2023 at 4:37 AM, KantianKinetics said:

    Once I sort through this error, I see that I will have troubles later since SEEQ automatically generates the signal variable name "$OFPOF".  Is there a way to override existing variable names and assign new calculations a variable name of my choice?

    When working with formulas, you are free to choose any variable name you prefer, as long as the correct ID is mapped under the Formula Parameter. For instance, for row 1, you can use $a/$b. The only requirement is that the ID of $a and $b is correctly set. For example, {'$a'='0EE76D39-3D08-FF40-BBFF-53255CCEB514', '$b'='0EE76D39-3D08-FF40-BBFF-53255CCEB55'}.

  4. Hi Edmund, 

    I have a suggestion that may be helpful. You can create separate conditions for each color threshold - Concern, Investigate, and Shutdown - and put them all in one lane. Then, place the signal under the same lane. By doing this, you can monitor the signal movement on the trend, and the condition color will be shown in the background of the trend. Please refer to the example screenshot below for a better understanding. Let me know your thoughts on this.

    image.png

  5. Hi Edmund, 

    Have you ever considered using Treemap for condition-based monitoring? With Treemap, you can prioritize the conditions you want to monitor and focus on high-priority events when you have lots of process parameters to keep track of. Plus, you can easily drill down and check out what happened with high-priority events over a trend view. For more information on Treemap, please refer to this article.

  6. Hi David, 

    You can use the iterrows() function to loop over your DataFrame and add the scalars. 

    Let's say I have a DataFrame with all PVHI and PVLO limits: 

    image.png

    I can apply iterrows() function to add these limits to my asset:

    for index, row in csv.iterrows():
        #add Hi/HiHi Limits
        my_csv_tree.insert(name = row['Limits 1 Name'], 
                           formula = str(row['Limits 1']), 
                           parent = row['Level 3'])
        
        #add Lo/LoLo Limits
        my_csv_tree.insert(name = row['Limits 2 Name'], 
                           formula = str(row['Limits 2']), 
                           parent = row['Level 3'])
        
    my_csv_tree.visualize()

    The asset tree will look like this:

    My CSV Tree
    |-- Cooling Tower 1
    |   |-- Area A
    |   |   |-- PVHIHI
    |   |   |-- PVLO
    |   |   |-- Temperature
    |   |-- Area B
    |       |-- PVHIHI
    |       |-- PVLO
    |       |-- Temperature
    |-- Cooling Tower 2
        |-- Area D
        |   |-- PVHI
        |   |-- PVLO
        |   |-- Temperature
        |-- Area E
            |-- PVHI
            |-- PVLO
            |-- Temperature

     

  7. Hi Robert, 

    After the spy.search and dropNA step, you can create a metadata to convert the unit of the selected signals and push it to Seeq workbench. 

    #Search for tags and dropNA
    search_df = spy.search({
        'Name': 'Area ?_Compressor Stage',
        'Datasource Name': 'Example Data'
    }, estimate_sample_period=dict(Start='2019-01-01', End='2019-01-30'))
    
    search_df = search_df.dropna(subset=['Estimated Sample Period'])
    
    # Create a copy of the search table so we can manipulate it
    formulas = search_df.copy()
    
    formulas
    
    #Create the metadata
    formulas['Name'] = formulas['Name'] + '_convertunit'
    formulas['Formula'] = '$signal.convertUnits(\'C\')' #For this example, I am converting the unit to DegC. 
    formulas['Formula Parameters'] = '$signal=' + formulas['ID']
    formulas.head()
    
    #Push the metadata to Seeq workbench
    spy.push(metadata = formulas[['Name', 'Formula', 'Formula Parameters']],
             worksheet='Unit Conversion')

     

  8. Hi Martin, 

    You will need the ID of the new tag to swap the tag using Seeq Data Lab. Please see the example below: 

    #Search for the calculated tag
    metadata_df = spy.search({'ID': 'your_calculated_tag_id'}, all_properties=True) #alternatively, you can search using the name of the tag
    metadata_df
    
    #read the formula parameter from the metadata_df
    metadata_df['Formula Parameters'][0][0] #you will see the id of the $a parameter for example 'a=F8E053D1-A4D5-4671-9969-1D5D7D4F27DD'
    
    #swap the id of $a in the 'Formula Parameter' of metadata_df with the new id
    metadata_df['Formula Parameters'][0][0] = 'a=4E9416E8-9C75-426A-8E0A-4D07432CAC5D'
    
    #push the metadata_df back to Seeq
    spy.push(metadata=metadata_df)

     

  9. Hi Manoel, 

    You can refer to this article for instructions on grabbing just the document template. However, pushing the document template to an existing organizer topic is currently not supported in Seeq Data Lab. To generate your report, I suggest adding a blank document to the topic and handle the HTML content. If the Python code is well-structured, spy.jobs will create the report based on your schedule. Let me know if you need help setting up the HTML content.

  10. Hi Manoel, 

    You can add one step to create a new document to the Organizer Topic you already created. Then, follow the steps suggested by Kristopher and Emilio here to set up the html of the new document. 

    #Search for topic
    topic_search=spy.workbooks.search({'ID':'your_organizer_topic_id'})
    
    #Pull the topic associated with that ID
    topic=spy.workbooks.pull(topic_search)
    
    #Add a new document/page to the topic object
    page = topic.document('February 2023')
    
    #Follow the steps suggested by Kristopher and Emilio

     

  11. Hi James, 

    On the details pane, change the samples to "Points only" or "Bar chart" to see the samples of the signal without interpolation. 

    Points only: 

    image.png

    Bar chart:

    image.png

    You can view the timestamp and value of the signal in Table view too. First, create a capsule for every sample of your signal using a Formula. 

    $signal.setMaxInterpolation(1s).isValid()

    Then, switch to "Condition Table" view -> click "Columns" -> select the totaliser signal -> select "Maximum". 

    image.png

    Now, you can see the timestamp and value of the samples in a Table. 

    image.png

     

  12. Hi Dano, 

    The removeLongerThan function only works on a Condition. In your screenshots, the selected $b (Making in 401, 402, 403) in your Formula is a Signal, and this is causing the error you encountered when executing the Formula. Kindly change the $b variable to the "Making 401, 402, 403" condition (the purple color condition in your screenshot) and re-execute the Formula. The symbol of Signal and Condition under the variable selection pane of the Formula tool is different and you can refer to the symbol to check the item type of each variable. 

    Regards, 

    Kin How

  13. A few weeks ago in Office Hours, a Seeq user asked how to perform iterative calculation in which the next value of the calculation relies on its previous values. This functionality is currently logged as a feature request. In the meantime, users can utilize Seeq Data Lab and push the calculated result from Seeq Data Lab to Seeq Workbench. Let's check out the example below:

    There are a total of 4 signals, Signal G, Signal H, Signal J, and Signal Y added to Seeq workbench. The aim is to calculate the value of Signal Y, under the selected
    period. 

    AMWts8B3my04_2dkDyhIs_0JzBJJC1y_cwlRtuwo

    AMWts8DPRfMBwUaJL_AKMpeBZGQ98NPu3Mp5okYi

     

    Step 1: Set the start date and end date of the calculation.

    #Set the start date and end date of calculation
    startdate = '2023-01-01'
    enddate = '2023-01-09'

     

    Step 2: Set the workbook URL and workbook ID.

    #Set the workbook URL and workbook ID
    workbook_url = 'workbook_url'
    workbook_id = 'workbook_id'

     

    Step 3: Retrieve all raw data points for the time interval specified in Step 1 using spy.pull().

    #Retrieve all raw data points for the time internal specified in Step 1:
    data = spy.pull(workbook_url, start = startdate, end = enddate, grid = None)
    data

    AMWts8AAGFvQ1qgO5HQHRtN-1Y8pDflFGutCsWLN

     

    Step 4: Calculate the value of Signal Y, (Yi = Gi * Y(i-1) + Hi * Ji)

    #Calculate the value of Signal Y (Yi = Gi * Y(i-1) + Hi * Ji)
    for n in range(len(data)-1):
        data['Signal Y'][n+1] = data['Signal G'][n+1] * data['Signal Y'][n] + data['Signal H'][n+1] * data['Signal J'][n+1]
    data

    AMWts8A987aqzQEJnOyTgnlFxS_sq0KmyQ_XTN3-

     

    Step 5: Push the calculated value of Signal Y to the source workbook using spy.push().

    #Push the calculated result of Signal Y to the source workbook
    spy.push(data = data[['Signal Y']], workbook = workbook_id)

    AMWts8AvSIOyFVONcGX4phtcJBldtYoMGDWHeop0

    • Like 4
    • Thanks 3
  14. On 11/18/2020 at 12:11 PM, Kin How Chong said:

    While building an asset tree using spy.assets, the display items of a worksheet can be defined under @Asset.Display(). The list below shows the options that can be set for each parameter of the display pane:

    • Color: str = any valid color hex for example #4055a3, #068c45, #9d248f. 
    • Line Style: str = {'Solid', 'Short Dash', 'Short Dash-Dot', 'Short Dash-Dot-Dot', 'Dot', 'Long Dash', 'Dash-Dot', 'Long Dash-Dot', 'Long Dash-Dot-Dot'} 

    display1.png

    • Line Width: float = {1, 1.5, 2, 2.5, ...9.5, 10}
    • Lane: int = {1, 2, ...}
    • Samples Display: str = {'Line', 'Line and Sample', 'Samples', 'Bars'}

    display1.png

    • Axis Auto Scale: bool
    • Axis Align: str = {'Left', 'Right'}
    • Axis Group: str = {'A', 'B', ...}
    • Axis Max: float
    • Axis Min: float

    One example of display items set using @Asset.Display():

    @Asset.Display()
    def Bar_Graph (self, metadata, analysis):
        worksheet = analysis.worksheet('BarGraph')
        workstep = worksheet.workstep('BarGraph')
        workstep.display_items = [{
            "Item": self.Signal_1(),
            "Axis Group": "A",
            "Axis Auto Scale": True,
            "Lane": 1,
            "Line Style": "Solid",
            "Line Width": 10,
            "Samples Display": "Bars",
            "Color": "#4055A3"
        }, {
            "Item": self.self.Signal_2(),
            "Axis Group": "B",
            "Axis Auto Scale": True,
            "Lane": 1,
            "Line Style": "Short Dash",
            "Line Width": 1,
            "Samples Display": "Line",
            "Color": "#9D248F"
        }, {
            "Item": self.self.Signal_3(),
            "Axis Group": "B",
            "Axis Auto Scale": True,
            "Lane": 1,
            "Line Style": "Solid",
            "Line Width": 1,
            "Samples Display": "Line and Sample",
            "Color": "#CE561B"
        }, {
            "Item": self.self.Signal_4(),
            "Axis Group": "C",
            "Axis Auto Scale": False,
            "Axis Align": "Right",
            "Axis Max": 100.5,
            "Axis Min": 10,
            "Lane": 1,
            "Line Style": "Solid",
            "Line Width": 1,
            "Samples Display": "Samples",
            "Color": "#00A2DD"
        }]
        workstep.display_range = {'Start': '2020-06-11T00:00:00', 'End': '2020-07-12T00:00:00'}
        workstep.view = 'Trend'
        return workstep

     

    There is a typo on the second item to the forth item of the workstep.display_items. The correct way to specify them is self.Signal() instead of self.self.Signal()

    • Like 1
×
×
  • Create New...