Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Instruments #3

Merged
merged 3 commits into from
Nov 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/reference/instruments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Survey Instruments

::: circumplex.instrument
314 changes: 299 additions & 15 deletions docs/tutorials/Intro_to_SSM_Analysis.ipynb

Large diffs are not rendered by default.

404 changes: 300 additions & 104 deletions docs/tutorials/Random_exs.ipynb

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ nav:
- 'API reference':
- 'Core functions': reference/api.md
- 'Dealing with results': reference/classes.md
- 'Survey Instruments': reference/instruments.md
- 'Utils': reference/utils.md
- 'News': news.md
theme:
Expand Down
3 changes: 3 additions & 0 deletions src/circumplex/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
from circumplex.circumplex import *

# from circumplex import datasets
from circumplex import instrument
119 changes: 95 additions & 24 deletions src/circumplex/circumplex.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ class SSMParams(object):
A class to store the results of a single SSM analysis.

Attributes:
scores (np.array): A numeric vector (or single row dataframe) containing one score for each of a set of circumplex scales.
angles (tuple): A numeric vector containing the angular displacement of each circumplex scale included in `scores`.
scores (np.array): A numeric vector (or single row dataframe) containing one score for each of a
set of circumplex scales.
angles (tuple): A numeric vector containing the angular displacement of each circumplex scale
included in `scores`.
scales (list): A list of the names of the circumplex scales included in `scores`.
group (list): A list of the names of the groups included in `scores`.
measure (list): A list of the names of the measures included in `scores`.
Expand Down Expand Up @@ -94,9 +96,23 @@ def __repr__(self):

def __str__(self):
# TODO: Add param results
return f"{self.label}: {self.params})"
return (
"====================================\n"
f"Measure: {self.measure}\n"
f"Group: {self.group}\n"
f"Scales: {self.scales}\n"
f"Scale Angles: {self.angles}\n"
f"\nProfile [All]:\n"
f" Estimate\n"
f"Elevation: {round(self.elevation, 3)}\n"
f"X-Value: {round(self.xval, 3)}\n"
f"Y-Value: {round(self.yval, 3)}\n"
f"Amplitude: {round(self.amplitude, 3)}\n"
f"Displacement: {round(self.displacement, 3)}\n"
f"R2: {round(self.r2, 3)}\n"
)

def profile_plot(self, ax=None) -> plt.Axes:
def profile_plot(self, ax=None, **kwargs) -> plt.Axes:
"""
Plot the SSM profile.

Expand All @@ -112,6 +128,7 @@ def profile_plot(self, ax=None) -> plt.Axes:
self.scores,
self.label,
ax=ax,
**kwargs,
)

def plot(self) -> plt.Axes:
Expand Down Expand Up @@ -153,6 +170,9 @@ def __init__(
self.measures = measures
self.grouping = grouping

def __str__(self):
return "\n".join([str(res) for res in self.results])

@property
def groups(self) -> set:
"""Return a list of the groups included in the analysis."""
Expand Down Expand Up @@ -221,6 +241,7 @@ def profile_plots(self, axes=None) -> plt.Axes:
figsize=(8, 4 * len(self.results)),
)
for i, res in enumerate(self.results):
# BUG: Raises error if we only need a single plot
fig, ax = res.profile_plot(ax=axes.flatten()[i])
plt.tight_layout()
# plt.show()
Expand All @@ -246,7 +267,10 @@ def ssm_analyse(
scales (list): A list of the names of the circumplex scales to be included in the analysis.
measures (list, optional): A list of the names of the measures to be included in the analysis. Defaults to None.
grouping (list, optional): A list of the names of the groups to be included in the analysis. Defaults to None.
angles (tuple, optional): A tuple containing the angular displacement of each circumplex scale included in `scores`. Defaults to OCTANTS.
angles (tuple, optional): A tuple containing the angular displacement of each circumplex scale
included in `scores`. Defaults to OCTANTS.
grouped_angles (dict, optional): A dictionary containing the angular displacement of each circumplex scale
included in `scores` for each group. Defaults to None.

Returns:
SSMResults: A SSMResults object containing the results of the analysis.
Expand Down Expand Up @@ -282,7 +306,8 @@ def ssm_analyse_grouped_corrs(
scales (tuple): A list of the names of the circumplex scales to be included in the analysis.
measures (list): A list of the names of the measures to be included in the analysis.
grouping (list): A list of the names of the groups to be included in the analysis.
angles (tuple, optional): A tuple containing the angular displacement of each circumplex scale included in `scores`. Defaults to OCTANTS.
angles (tuple, optional): A tuple containing the angular displacement of each circumplex scale
included in `scores`. Defaults to OCTANTS.

Returns:
SSMResults: A SSMResults object containing the results of the analysis.
Expand Down Expand Up @@ -318,7 +343,8 @@ def ssm_analyse_corrs(
data (pd.DataFrame): A dataframe containing the data to be analysed.
scales (tuple): A list of the names of the circumplex scales to be included in the analysis.
measures (list): A list of the names of the measures to be included in the analysis.
angles (tuple, optional): A tuple containing the angular displacement of each circumplex scale included in `scores`. Defaults to OCTANTS.
angles (tuple, optional): A tuple containing the angular displacement of each circumplex scale
included in `scores`. Defaults to OCTANTS.
group (str, optional): The name of the group to be included in the analysis. Defaults to None.

Returns:
Expand Down Expand Up @@ -348,7 +374,8 @@ def ssm_analyse_means(
data (pd.DataFrame): A dataframe containing the data to be analysed.
scales (tuple): A list of the names of the circumplex scales to be included in the analysis.
grouping (list): A list of the names of the groups to be included in the analysis.
angles (tuple, optional): A tuple containing the angular displacement of each circumplex scale included in `scores`. Defaults to OCTANTS.
angles (tuple, optional): A tuple containing the angular displacement of each circumplex scale
included in `scores`. Defaults to OCTANTS.

Returns:
SSMResults: A SSMResults object containing the results of the analysis.
Expand Down Expand Up @@ -382,9 +409,12 @@ def ssm_parameters(scores, angles, bounds=BOUNDS) -> tuple:
"""Calculate SSM parameters (without confidence intervals) for a set of scores.

Args:
scores (np.array): A numeric vector (or single row dataframe) containing one score for each of a set of circumplex scales.
angles (tuple): A numeric vector containing the angular displacement of each circumplex scale included in `scores`.
bounds (tuple, optional): The bounds for each of the parameters of the curve optimisation. Defaults to ([0, 0, -1], [np.inf, 360, 1]).
scores (np.array): A numeric vector (or single row dataframe) containing one score for each of a
set of circumplex scales.
angles (tuple): A numeric vector containing the angular displacement of each circumplex scale
included in `scores`.
bounds (tuple, optional): The bounds for each of the parameters of the curve optimisation.
Defaults to ([0, 0, -1], [np.inf, 360, 1]).

Returns:
tuple: A tuple containing the elevation, x-value, y-value, amplitude, displacement, and R2 fit of the SSM curve.
Expand Down Expand Up @@ -416,35 +446,65 @@ def polar2cart(r, theta):


def profile_plot(
amplitude, displacement, elevation, r2, angles, scores, label, ax=None
amplitude,
displacement,
elevation,
r2,
angles,
scores,
label,
ax=None,
reorder_scales=True,
incl_pred=True,
incl_fit=True,
incl_disp=True,
incl_amp=True,
) -> plt.Axes:
"""
Plot the SSM profile.

Args:
reorder_scales:
incl_pred:
incl_fit:
incl_disp:
incl_amp:

Returns:
plt.Axes: A tuple containing the figure and axis objects.
"""
thetas = np.linspace(0, 360, 1000)
fit = cosine_form(thetas, amplitude, displacement, elevation)

if ax is None:
fig, ax = plt.subplots(figsize=(8, 4))
else:
fig = ax.get_figure()

ax.plot(thetas, fit, color="black")
if reorder_scales:
angles, scores = sort_angles(angles, scores)
if angles[-1] == 360:
angles = (0,) + angles
scores = (scores[-1],) + scores

if incl_pred:
thetas = np.linspace(0, 360, 1000)
fit = cosine_form(thetas, amplitude, displacement, elevation)
ax.plot(thetas, fit, color="black")

ax.plot(angles, scores, color="red", marker="o")
# ax.scatter(self.angles, self.scores, marker="o", color="black")
ax.axvline(displacement, color="black", linestyle="--")
ax.text(
displacement + 5,
elevation,
f"d = {int(displacement)}",
)
ax.axhline(amplitude + elevation, color="black", linestyle="--")
ax.text(0, amplitude + elevation * 0.9, f"a = {amplitude:.2f}")
if incl_disp:
ax.axvline(displacement, color="black", linestyle="--")
ax.text(
displacement + 5,
elevation,
f"d = {int(displacement)}",
)
if incl_amp:
ax.axhline(amplitude + elevation, color="black", linestyle="--")
ax.text(0, amplitude + elevation * 0.9, f"a = {amplitude:.2f}")

ax.text(0, elevation * 0.5, f"R2 = {r2:.2f}")
if incl_fit:
ax.text(0, elevation * 0.5, f"R2 = {r2:.2f}")

ax.set_xticks(OCTANTS)
ax.set_xticklabels(
Expand All @@ -454,3 +514,14 @@ def profile_plot(
ax.set_ylabel("Score", fontsize=16)
ax.set_title(f"{label} Profile", fontsize=20)
return fig, ax


def sort_angles(angles, scores):
"""Sort angles, scores, and scales in order of scale."""
# Zip the values and labels together
zipped = list(zip(angles, scores))
# Sort the list of zipped tuples
zipped.sort(key=lambda x: x[0])
# Unzip the list of tuples
angles, scores = zip(*zipped)
return angles, scores
Binary file added src/circumplex/data/SATP Dataset v1.4.xlsx
Binary file not shown.
Empty file added src/circumplex/data/__init__.py
Empty file.
Loading