Posts by retug (34)

RAM to RevitĀ® - R2R - (part 2)

Link to trial the tool.

Above is the finished beta release R2R tool. It seems to work for large projects and should be a huge time saver and QA/QC tool as compared to manually checking RAM beams to Revit beams.

If you want to be a beta tester for this tool, please either leave a comment/reach out to me. I would be happy to share with you. Please be aware, the tool is still unstable in many conditions, be sure to save a local RAM model and Revit that you do not care about.

How It Works - Screen 1

Screen 1 is where you mostly focus on selection, coordinate system transformation and selection of RAM beams and Revit beams to be mapped. 

The Inputs

Select RAM File

This one is self explanatory, select the .rss file you want to inspect. Be sure that ALL RAM products are closed before doing this, the program will crash if you have RAM open. I need to add some code to catch this error and ask the user to close RAM.

Gather RAM Levels

This button gathers the RAM levels in the project from the selected RAM model. NOTE: the grids will only be imported if you set a max and min in the RAM grid definition.

Select Level

This button will load in the RAM grids into the canvas below and will select the RAM beams at that level to be compared to Revit.

Gather Revit Grids

Button will plot all Revit grids in the Revit canvas. 

Select Revit Beams

Button prompts the user to select revit beams to map, ensure your mapping window for selection is already in your current view. The revit project becomes "locked" when starting up the addin and you are not able to interact with the revit model once you have started up the app. I will work on fixing this in the future. From here, window over any objects you want to map, the selection is filtered down to only select the beams.

With the grids in the mapping window, you can select (2) corresponding grids from the revit model and the ram model and click "Calc X Y and Rotation". This function is rough and not perfect but it attempts to calculate the X Y and Rotation parameter between the RAM and Revit model. Lots of times our RAM models do not align with our Revit models and this function attempts to automate this once manual step.

With the X Y and rotation parameters set, you can save the file path of your .rss file and mapping parameters to .json file. 

Once you are happy with your mapping properties, be sure to hit save so you do not have to do this again. Clicking import brings in these settings and you can mostly skip the import screen save a few buttons:

  • RAM level, select your ram level and beams
  • Selecting your Revit beams.

Sample of the R2R_Json file created:

How it Works - Screen 2

Screen two is pretty simple, you will be greeted with your ram and revit beams being plotted on the canvas in front of you. You can check the RAM or Revit beams on or off as well as control their transparency. Then, click on map the beams and the mapping algorithm will go to town checking all beams in the models. 

A datagrid is populated on the left and discrepancies are highlighted in yellow in the datagrid. You can select the data grid row and it will highlight the selected beam in the mapping panel. The colors are a bit gross right now, but I will work to make the UI a bit more manageable moving forward.

I plan on making a youtube channel to record a video going over all the inputs, typing this all out is tedious and a video would likely be much easier for me and the end user.

The Code

I am pleasantly surprised by how quickly the mapping algorithm works. On the screen at the beginning of the post the algorithm was able to make it through ~1000 revit and ram beams in under 1 second!!! Crazy fast. The algorithm works by taking one RAM beam and then comparing its end point to every Revit beam in the project until the beam is either mapped into the Revit space or is does not find a mate. Let's try to do some quick mental math on the number of calculations performed in this process.

  • 1000 RAM beams, call a distance function on each end point of each Revit beam, assume that a match is found at about the half distance of the Revit Beam list.

  • The first beam in this list would run the distance function 500*2 times = 1000 times, next beam would then 499*2 times = 998 times
  • I thought this was 500!*2, but this seems likely impossible for even a computer to crunch in ~1 second. Google can't even give me an awesome for something over 100! Can someone smarter at math point out where I am wrong? (Edit 2024-01-08, I found my problem, it is the summation of 500*2, not 500!, 125250*2 = 250,500 calculations in ~1 second.)

Developing in C Sharp is starting to become more and more natural, I am really liking the experience now that I am more knowledgeable. At one point, I really liked Python due to it's dynamically typed nature, but type hints in the Revit API are so valuable to know what a function expects to act on. Another fun one, while you are in the visual studio debugger, you can actually make changes to your code while you are debugging and see how your changes affect the code. I had to do this a bunch in my mapping algorithm implementation, ever so slightly tweaking the code as I go. In the code below, tweaking startPoint.Y +/- was really cool while debugging.

As always, ChatGPT is truly a game changer for coding. This project was developed sooooo much quicker becuase of ChatGPT. One small example, in order to make my rows highlight in yellow if the beams between revit and ram did not match seemed like quite a difficult task. XAML does not have a does not equal expression, !=, similiar to that of python/C#, so you have a to write a "Converter" class for XAML and C #. 

I asked chatGPT to do this for me and the code worked perfectly.

Feedback

I have heard a few comments asking how this tool is different from the RAM ISM connection tool. Given that I have not used the RAM ISM connection tool, I cannot answer this. If you have used the connection tool, can you let me know if R2R is the same, does a different task, worse or better the ISM Digital twin product that Bentley seems to offer. 

The Future

Distribution

I am exploring a few different ways to get this tool distributed to a wider mass of structural engineers. If you have experience in dealing with Autodesk, please reach out to me, I would love to pick your brain on this topic.

Work on all levels in the RAM model at once? Expand to check camber, studs, etc.

This would be super cool, maybe there would be a way to check all levels at once with this tool. The tool could be pretty easily expanded to check camber studs, beam end reactions etc. The possibilities are endless, if you have any requests, please let me know. Hopefully this tool allows structural engineers to focus on the more important items in design and less on back checks!.

Fix pan, zoom, other graphics issues, clean up code, focus on DRY coding

Dry coding, do not repeat yourself, was not implemented in this code. I have (3) differing pan zoom and mouse over functions for the RAM and Revit canvas on screen 1, and another pan zoom and mouse over function for screen 2. This leads to lots of repetition and chances for mistakes. I would like to come back to this and make the code more DRY. In addition, the pan function only works if you select an element in the canvas, like a line or text. If you select the big empty white space, the pan function does not work? I need to dig into why. The zoom function in the canvas's are also super whack, with zooming only partially work and zoom into weird spots, not centered on the current mouse position. 

Next steps, I look forward to supporting this product and incorporating any feedback you may have. Again, leave a comment/message me if you want to test the tool out or want additional features. 

For the next part of the site, I want to focus on getting back to structural engineering and less coding. Some examples on non-linear concrete shearwalls, dynamic analysis, rubber isolators and all of that fun stuff. I am excited to get away from coding for a bit.

I also have an itch to dig into machine learning/AI, what is it besides these fun buzz words we hear all the time? I want to explore pytorch/tensorflow and really learn what it means to train a model. How do I create the input nodes for a neural network? I still have no idea how this could relate to structural engineering, but it would be fun to dig and explore the space. 

 

 

SAP2000 API Example

This blog is finally starting to pay off, people are emailing with programming questions and problems. Making programming a little more accessible has always been the goal with the site. Programming can be intimidating to get started!

Foad Kondori emailed me awhile back trying to make a SAP2000 plugin to access frame reactions in SAP2000. I had never written a plugin for SAP2000, but I had written some python code awhile back to access ETABs frame force reactions in Python. I was able to send him my code and he was able to do the rest of the magic to translate the python code to C#. 

The code he wrote is really cool and I appreciate that he allowed me to share this code on github and the blog. Sample shown below retrieving selected frame object type and name

There was one small bug he had in his program and I was able to trouble shoot the culprit, moving the data source out of the for loop did the trick.

His example also provided me some insight on better ways to manage if the SAP/ETABs model has run. 

 bool isModelRunning = _SapModel.GetModelIsLocked();
            if (isModelRunning)
            {

                //get Frame Force

else
            {
                DialogResult result_2 = MessageBox.Show("the model is not run, Do you want Run the model ?"
, "Run Analysis", MessageBoxButtons.YesNo, MessageBoxIcon.Information);

                if (result_2 == DialogResult.Yes)
                {
                    _SapModel.Analyze.RunAnalysis();
                }
            }
        }

These are things I need to implement in the section cutter tool to prevent time consuming re-runs.

Also, I need to dig in and understand why the section cutter ETABs plugin does not work in SAP2000. The APIs between the two program look very similar, but the section cutter plugin does not work in SAP 2000. Foad's example will be a good place to start when trying to troubleshoot.

To CSI, can we improve the SAP OAPi documentation? It only appears to be written for VBA, maybe it could be updated to match that of ETABs, with samples provided for multiple languages?

Feel free to reach out anytime if you are running into programming trouble, I'll try to help if I have the time.

RAM to Revit (R2R) Part 1

The Tool

For a long time I’ve wanted a quick way to spot check if structural beams in our analysis models like RAM or ETABs matched our Revit model. The gif above shows the beginning of bringing this idea to life. The tool will be a plugin for Revit that will allow users to import their RAM structural model into an in-between file that will interact with RAM and Revit.

I'm a little sad that I am not developing this tool for ETABs, as this is my daily structural analysis driver, but our office is much more of RAM office than ETABs office. Gotta do what the people want and will (hopefully) use.

How It Works

The initial screen is split between a RAM Structural side (left) and a Revit side (right). After pointing the program to the location of the RAM SS model, the user will collect the levels and select the level of interest in the combo box. From here, the program will gather the structural grids in the RAM SS model and plot them onto the RAM canvas. A similar process occurs on the Revit side to plot all of the grids in the Revit model.

From here, the user will be promoted to select two interesting gridlines that will share the same coordinates in both the RAM model and Revit model. This intersection will be use in future to generate the global coordinate system for the project as a whole, allowing for the RAM and Revit model to have differing coordinate systems and still map into each other.

Next Steps

The mapping algorithm. The way the project is currently constructed, the program will determine the x and y offset by calculating the intersection point of the selected RAM and Revit grids.

From here, I will work on a function to determine the rotation parameter. This might be a bit tricky to determine, given that a rotation parameter could either be positive or negative, I might prompt the user to select the rotation parameter.

With the x, y and rotation parameters set, I can set up the local coordinate system for the RAM beams and map them in the global coordinate system of the revit project.

Fun Parts of the Coding Experience

It’s funny how many pieces of my previous coding experience came into play making this.

  • Canvas and graphics
    • A lot of the lessons I learned in javascript and threejs from the concrete design tool were able to be applied to the plotting performed in this script.
    • Do not forget that the default canvas is coordinates have the y coordinate being negative. This threw me for a loop for a bit trying to trouble shoot why the grid plots were always upside down
  • Intricate point class
    • The r2rPoint class is on the upper end of my ability to understand classes in C#. There are some very complicated properties and methods used in the class and it is a big improvement from the point class utilized in the section cutter tool. It allows the point to be defined in either the global (GCS) or local coordinate system (LCS)
    • This came in handy when pulling grid data out RAM structural due to the grid system definition. Essentially each grid system in RAM structural has its own local coordinate system that the r2rPoint class can handle quite elegantly. The way a point is defined as global or local is through the isGlobal Boolean.
    //Initialize the point class in either the global or local coordinate system thru isGlobal Flag

        public r2rPoint(double X, double Y, double Z)
        {
            this.X = X;
            this.Y = Y;
            this.Z = Z;
            isGlobal = true;
        }

        public r2rPoint(double U, double V, double W, bool isGlobal = false)
        {
            this.U = U;
            this.V = V;
            this.W = W;
            this.isGlobal = isGlobal;
        }

        public void Convert_To_Local(GlobalCoordinateSystem gcs)
        {
            double[] part1 = new double[] { X - gcs.RefPnt[0], Y - gcs.RefPnt[1], Z - gcs.RefPnt[2] };


            //the class will now have new attribute of local coordinates point.LocalCoords[0] = the X local coordinate system
            LocalCoords = new List<double>() { gcs.R_Inv[0, 0] * part1[0] + gcs.R_Inv[0, 1] * part1[1] + gcs.R_Inv[0, 2] * part1[2] ,
            gcs.R_Inv[1, 0] * part1[0] + gcs.R_Inv[1, 1] * part1[1] + gcs.R_Inv[1, 2] * part1[2],
            gcs.R_Inv[2, 0] * part1[0] + gcs.R_Inv[2, 1] * part1[1] + gcs.R_Inv[2, 2] * part1[2]};


            this.U = LocalCoords[0];
            this.V = LocalCoords[1];
            this.W = LocalCoords[2];
        }

        public void Convert_To_Global(GlobalCoordinateSystem gcs)
        {
            //this is the ref point
            double[] part1 = new double[] { U, V, W };


            //the class will now have new attribute of local coordinates point.LocalCoords[0] = the X local coordinate system
            GlobalCoords = new List<double>() { (gcs.R[0, 0] * U + gcs.R[0, 1] * V + gcs.R[0, 2] * W) + gcs.RefPnt[0],
            (gcs.R[1, 0] * U + gcs.R[1, 1] * V + gcs.R[1, 2] * W) + gcs.RefPnt[1],
            (gcs.R[2, 0] * U + gcs.R[2, 1] * V + gcs.R[2, 2] * W) + 0}; //unsure why this the way to do this. review in the future. should be the line below, without the 0
            //(globalCoords.R[2, 0] * X + globalCoords.R[2, 1] * Y + globalCoords.R[2, 2] * Z) + globalCoords.RefPnt[2]};

            this.X = GlobalCoords[0];
            this.Y = GlobalCoords[1];
            this.Z = GlobalCoords[2];
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

Each grid system in RAM structural has it's own local corodinate system:

  • Xaml and Html Similarities
    • This is the first time I have used XAML and WPF (Note, someday I dream of experiencing less "first"s in programming. The programming world seems so large and ever expanding compared to that of structural engineering where it is the same old stuff day in and day). Xaml looks very similar to Html, Maybe Xaml stole some ideas from Html? </> formats are familiar from brief experience in web development and getting this website up and running. It did not take too long to make the Xaml work, which I attribute to having some background in Html. 
      • I learned from some previous coworkers that Xaml and WPF is a more "modern" approach to UI development compared to winforms which was used to make the sectioncutter ui. Personally, I find winforms super easy to get up and running, but for more complicated projects like this one, maybe xalm and WPF will pay off.
  • ChatGPT Skills
    • I am continually amazed by ChatGPT and it’s ability to get thing up and running quickly
    • 90% of my canvas events were written by ChatGPT and it’s really impressive how quickly ChatGPT was able to take me from an idea to a functional example, allowing me to fill in the blanks
    • I originally went down the route of using LiveCharts2 to do the interactive plotting, which I wasted a lot of time exploring. ChatGPT could not help me due to the fact that LiveCharts2 was not released until 2022. ChatGPT was really good at making up stuff that used to work in the original LiveCharts and that would not work in LiveCharts2. I eventually gave up and went to the old fanshioned canvas to handle events and plotting needs.
    • I wrote the concrete design tool before ChatGPT and I would estimate that it took me about 3 solid weeks of coding and internet forum conversations to get a workable zoom, pan and selection function to work with the canvas. ChatGPT was able to write these functions in the better part of a 20 min interaction with it. Super impressive.
    • I find myself having to thank the robot overlord all the time for the work that it does for me : ), I am not sure if others do this as well.
Me: I get an error that Ellipse does not contain a definition for child

ChatGPT: I apologize for the confusion. My previous response contained incorrect information. Ellipse does not have a direct Child property to add text inside it. Instead, you can achieve this by placing both the Ellipse and TextBlock inside a container like a Grid. Here's how you can do it:

csharp
Copy code
private void AddCircleWithText(double x, double y, string text)
{
    Grid container = new Grid();

    Ellipse circle = new Ellipse
    {
        Width = 10, // Diameter = 2 * Radius
        Height = 10, // Diameter = 2 * Radius
        Fill = Brushes.Red,
        Stroke = Brushes.Black,
        StrokeThickness = 1,
    };

    TextBlock textBlock = new TextBlock
    {
        Text = text,
        Foreground = Brushes.White,
        HorizontalAlignment = HorizontalAlignment.Center,
        VerticalAlignment = VerticalAlignment.Center
    };

    container.Children.Add(circle);
    container.Children.Add(textBlock);

    // Position the container at (x, y)
    Canvas.SetLeft(container, x - 5); // Adjust for the radius
    Canvas.SetTop(container, y - 5); // Adjust for the radius

    canvas.Children.Add(container);
}

Now, each circle and text combination is enclosed in a Grid, which allows you to display text inside the circle on the canvas. You can use the AddCircleWithText function with the (x, y) coordinates for the center of the circle and the desired text to place inside it.

Me: This looks great thank you! How can I make it so that the elements in the canvas are larger on my screen via scrolling in and out?

Another oddity about the code, when accessing the RAM structural API, I needed to add a reference to the Microfsoft.CSharp .dll. I had never had to do this before in my previous experience following Marcello’s examples, but the binding functions and casting functions would not work without import the CSharp reference. After some confusion and googling, I was able to resolve this error.

Please note that this code is not DRY (do not repeat yourself), I would like to come back in the future and make it more DRY, many of the canvas functions are duplicated, one with ramZoom or revitZoom. I bet there is a way to make this work without repetitive canvas events.

Future Work

  • Keep going on point mapping algorithm
  • Add a save and read functionality to store the mapping parameters
    • I have not done save and read before in my programming experience so this should be a good learning experience.
  • Address radial grids
    • Both RAM and Revit
  • Address that RAM grids only work with a max and min parameter set.
  • Add zoom to fit function
    • Right now the grids are not centered in the canvas. Maybe add a double middle mouse button click to zoom extents.

Section Cutter - ETABs Plugin

Install

https://www.youtube.com/watch?v=CUDt8zJYAoc

How to use

https://www.youtube.com/watch?v=L_XXPHafNQQ

A major upgrade to the section cutter tool, section cuts are now centered on the first and last location where they pass through constituent area geometry. An astute engineer in our office noticed that if the section cuts were not centered on the constituent area geometry, moment results could be quite skewed as ETABs reports moments about the center of the section cut, not the center of the cut geometry. Let's dig into the algorithm and code.

A new github repo has been created for the section cutter tool. This project has become big enough that it deserves it's own repo. The readme page also has install instructions.

The "Smart Sections Algorithm"

The algorithm to make "smart" sections was easy to do on paper, a bit harder to do by painstakingly describing every step to a computer. Let's get some visual aids to assist in outlining the algorithm.

 Step 1 - Gather User Areas and Input Node. Example will be a simple square.

Note, I think the input node could be omitted, but it has remained in the section cutter tool for now.

Step 2 - Setup Local Coordinate System (LCS) based on input vector and starting point.

Here the LCS is rotated 45 degrees as shown by the blue rotated grid lines. Convert all constituent area geometry to the LCS. LCS coordinates in Red.

 

Step 3 - Generate an array lines in the LCS.

The previous section cutter tool would stop at this point. These results would be incorrect for buildings with steps, like an L shaped diaphragm.

Step 4 - Determine where lines generated in step 3 cross constituent geometry.

Use these points to create the section cuts in ETABs.

The Code

The main struggle on the coding side was controlling all the lists of data and maintaining their structure. The algorithm works for many areas and openings, so the amount of data that gets generated to perform these checks inflates quite quickly. To my surprise, the tool does not seem to struggle with generating all of the section cut data, the slowest part is still the analysis of the semi-rigid diaphragm.

Once again, chatGPT really helped out with the coding. The intersection function was exactly copied and pasted and it worked, how surprising!

Here is my chat with the AI overlord bot, THEY TOOK OUR JOBS! :

Me: Given that two line segments, each with an x and y value, that are known to intersect, write c# code that determines the intersection point, x and y, of the two line segments

ChatGPT

To find the intersection point of two line segments, you can use the concept of parametric equations. Given two line segments defined by their endpoints (x1, y1) to (x2, y2) and (x3, y3) to (x4, y4), you can calculate the intersection point (xi, yi) using C# code as follows:

using System;

class Program
{
    static void Main()
    {
        // Example endpoints of two line segments
        int x1 = 1, y1 = 2;
        int x2 = 4, y2 = 6;
        int x3 = 3, y3 = 1;
        int x4 = 5, y4 = 5;

        // Calculate the intersection point
        if (Intersect(x1, y1, x2, y2, x3, y3, x4, y4, out int xi, out int yi))
        {
            Console.WriteLine($"Intersection Point: ({xi}, {yi})");
        }
        else
        {
            Console.WriteLine("The line segments do not intersect.");
        }
    }

    // Function to check if two line segments intersect and calculate the intersection point
    static bool Intersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, out int xi, out int yi)
    {
        // Calculate the denominator for parametric equations
        int denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);

        // Check if the line segments are parallel or coincident
        if (denominator == 0)
        {
            xi = 0;
            yi = 0;
            return false;
        }

        // Calculate the parameters for each line segment
        int ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator;
        int ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator;

        // Check if the intersection point lies within both line segments
        if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1)
        {
            // Calculate the intersection point
            xi = x1 + ua * (x2 - x1);
            yi = y1 + ua * (y2 - y1);
            return true;
        }

        xi = 0;
        yi = 0;
        return false;
    }
}

Replace the example endpoints (x1, y1, x2, y2, x3, y3, x4, y4) with the actual endpoints of your line segments. The code will then calculate the intersection point (xi, yi) if the two line segments intersect, or indicate that they do not intersect.

ChatGPT used an expression "out" that I had never seen before and it was super helpful. I still need to read up on "out" and "ref" in C#, but these seem to be ways to add additional function returns in C#.

Throwing this function into the main portion of the code, I was able to perform step 4 of the algorithm outlined above. Working in the LCS system was nice, allowing for easy manipulations of items that were perpendicular/parallel to the LCS. With the LCS point geometry known, it was easy to convert back into the GCS.

In addition to the main "smart sections" addition, a few features were added

  • For Trenno, Imperial (kip, ft), freedom units, and Metric (kN, m), superior units, results.
  • Section Cut plot at the bottom of the graphical user interface has been updated to look better.
  • A few more data validations items on user input have been added

I have more updates I want to get around to listed on the github repo readme page. If you have suggestions/bugs, please let me know. Looking to make this better.

Project Management with Deltek

Deltek is a powerful tool to track all things AEC related. At my level, I use it mostly for project management and tracking project budgets. 

You can get a lot of powerful reports out of it quickly, but at face value, it's just a sea of data. We need to visualize this data to get a better feel for what's happening. The plot above shows hours on a fictitious project over time for differing employees.

Fun notes from fake project, brown engineer leaves company, olive main engineer goes back to school mid project, blue project manager scrambles to pick up the project mid way through.

If you use deltek, you can quickly get this data in an excel format from the project review tab and clicking "export to excel". 

The sample excel file will have the following format:

Person Date Hrs Checked
Help Proj Eng 1 10/14/2021 4 Checked
QAQC Eng   15  
QAQC Eng 9/14/2022 4 Checked
QAQC Eng 12/6/2022 2 Checked
QAQC Eng 5/8/2023 1 Unchecked
QA/QC Eng 5/9/2023 6 Unchecked
QA/QC Eng 5/10/2023 2 Unchecked
Help Eng 2   10  
Help Eng 2 11/21/2022 0.5 Checked
Help Eng 2 11/22/2022 5.5 Checked
Help Eng 2 11/23/2022 4 Checked
Drafter QAQC   4.5  
Drafter QAQC 4/27/2023 4.5 Checked
Drafter QAQC 5/15/2023 0 Unchecked
Proj Eng 3   130  
Proj Eng 3 9/15/2022 0.5 Checked

With this excel file, we can do a little python on the file, using pandas and matplotlib and create fun plots.

I am still quite a beginner with pandas and I am sure there is a much more elegant way to do the cumulative time vs date plot. I struggled through this, but the code works:

 

### Multiple Plots

df_all = pd.read_excel('H:\\MyGenericProject.xlsx', sheet_name = 'HoursForProject')
names = df_all.iloc[:,0]

my_column_changes = names.shift() != names        
index_change = [i for i, x in enumerate(my_column_changes) if x]

PersonHrs = {}
PersonDate = {}

for i in range(len(index_change)):
    if i == len(index_change)-1:
        print(i)
        PersonHrs[names[index_change[i]+1]] = df_all.iloc[index_change[i]+1:,2]
        PersonDate[names[index_change[i]+1]] = df_all.iloc[index_change[i]+1:,1]
        
    else: ###grabs the last person in the list
        print(i)
        PersonHrs[names[index_change[i]+1]] = df_all.iloc[index_change[i]+1:index_change[i+1],2]
        PersonDate[names[index_change[i]+1]] = df_all.iloc[index_change[i]+1:index_change[i+1],1]
    
sum_time = []
for i in PersonHrs.values():
    indiv_sum = []
    indiv_time = 0
    for time in i:
        indiv_time += time
        indiv_sum.append(indiv_time)
    sum_time.append(indiv_sum)
    
for indiv_person_hrs, indiv_person_date in zip(sum_time, PersonDate.values()):
    DF = pd.DataFrame()
    DF['value'] = indiv_person_hrs
    
    person_date = pd.to_datetime(indiv_person_date) 
    DF = DF.set_index(person_date)
    
    plt.plot(DF)
    plt.gcf().autofmt_xdate()

plt.legend(PersonDate.keys())
plt.show()

The code to do this and sample excel file is found on github.

In addition, I made a cool stacked bar plot that tracks hours on Engineering, Drafting and QA/QC type work.

This fake project worked out to be about 70% engineering, 23% drafting and 7% QA/QC.

Moving forward, I would like to access Deltek's API directly. It would be awesome to make these plots directly without having to export excel files and pull other data manually. If you have accessed Deltek's API before, let me know, it would be fun to explore how to do this.

 

First Previous 1 2 3 4 Next Last

Sidebar

Site Info

  • Latest Comments