ivoflipse / Pawlabeling

Tool for processing and analyzing pressure measurements
Other
18 stars 1 forks source link

Add results for separate paws #44

Closed ivoflipse closed 10 years ago

ivoflipse commented 10 years ago

Currently the program only allows you to view average results, but Lyn requested to also have a way to view results of individual paws.

This would require a way to switch from average results to individual paws and you'll have to be able to select one of each of the four paws.

Given the way it's structured right now, I'll need to change the type of data that's supplied to the analysis tab

ivoflipse commented 10 years ago

While I'm displaying the curves for each separate contact in combination with the average of the whole session, you can't easily highlight a contact that's being selected. The problem here is that I currently calculate my results like so:

def calculate_results(self):
    # If we don't have any data, its no use to try and calculate something
    if len(self.data_list.keys()) == 0:
        return

    self.results.clear()
    self.max_results.clear()

    for contact_label, data_list in self.data_list.items():
        self.results[contact_label]["filtered"] = utility.filter_outliers(data_list, contact_label)
        for data in data_list:
            force = calculations.force_over_time(data)
            self.results[contact_label]["force"].append(force)
            max_force = np.max(force)
            if max_force > self.max_results.get("force", 0):
                self.max_results["force"] = max_force

            pressure = calculations.pressure_over_time(data, sensor_surface=self.sensor_surface)
            self.results[contact_label]["pressure"].append(pressure)
            max_pressure = np.max(pressure)
            if max_pressure > self.max_results.get("pressure", 0):
                self.max_results["pressure"] = max_pressure

            surface = calculations.surface_over_time(data, sensor_surface=self.sensor_surface)
            self.results[contact_label]["surface"].append(surface)
            max_surface = np.max(surface)
            if max_surface > self.max_results.get("surface", 0):
                self.max_results["surface"] = max_surface

            cop_x, cop_y = calculations.calculate_cop(data)
            self.results[contact_label]["cop"].append((cop_x, cop_y))

            x, y, z = np.nonzero(data)
            max_duration = np.max(z)
            if max_duration > self.max_results.get("duration", 0):
                self.max_results["duration"] = max_duration

    pub.sendMessage("update_results", results=self.results, max_results=self.max_results)

self.results is a nested dictionary, where first have the different types of results as keys, their values are dictionaries where the keys are the contact labels and the value is a list of the results for each contact with that contact label.

The order is somewhat random, since it comes from self.data_list, which in turn is just a dictionary with the data from all the contacts for each contact label. So I don't know which line maps to which contact. I reckon the real solution would be to remove any calculation from the views and just pass the views a dictionary of contacts, which happens to hold the relevant results, but is also more self-aware.

So I guess my next task is to first refactor model.py so its less cluttered and so I can add the required code for calculating session based results, that now resides within the views.

ivoflipse commented 10 years ago

I currently changed it so the analysis widgets either use the average_paw (which I don't know how to filter yet) or self.model.contacts for drawing the results. This should make it easier to highlight a specific contact if I know the measurement it was from and its index within that measurement, but I think there could be a faster way.

Perhaps I can create a dictionary that points to the contacts in self.model.contacts, but has as its keys the contact_label (making it easy to check if there are results) and as a value another dictionary where the keys are a tuple of (measurement_name/id, contact_index/id).

I'll probably also have to change the trees, which are currently split into two separate ones, into one big tree that has the measurements as a root item and its contacts as the leafs.

ivoflipse commented 10 years ago

I've made it possible to toggle between looking at the average or looking at individual contacts. This does require you to select each contact you want to look at, though it'll select the first contact for each label if available.

For now its only working in 2D view, but I'm going to make it work with the rest now as well.

ivoflipse commented 10 years ago

The slider for analysis_widget is set to the max_length of all contacts, but if you select 4 random ones, it probably no longer matches. So it would be nice if this got updated when we switch between average and 4 random contacts.

ivoflipse commented 10 years ago

It now also works for the pressure curves, but given that the data is 1D, I decided to overlay the selected contact with a black line, where the other lines are still visible, as is the mean +/- standard deviation.

I might tweak it to remove the other individual lines and only display the average.

image

ivoflipse commented 10 years ago

Interestingly, if for some reason the first measurement in the measurement tree doesn't have any labeled contacts, it'll show nothing.

Preferably it would look through all labeled data until it has found a contact for each of the four contacts.

ivoflipse commented 10 years ago

Also, check how the slider gets updated, because changing contacts might mean all 4 contacts are shorter than the max_length.

And make sure that 2D and COP go to black on the last frame if possible (though I don't know what to do with the COP...

ivoflipse commented 10 years ago

This seems to have been resolved now. There was some function missing from COP that the others did have.