-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcharts.py
More file actions
158 lines (135 loc) · 7.88 KB
/
charts.py
File metadata and controls
158 lines (135 loc) · 7.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import pandas as pd
import matplotlib.pyplot as plt
from pathlib import Path
import seaborn as sns
sns.set_context('talk')
sns.set_palette("muted", n_colors = 10)
responseloc = Path("/mnt/ahoerman/outreach/sxns17/survey")
outloc = Path("/mnt/ahoerman/outreach/2024_SAS/talk/survey")
responses = pd.read_excel(responseloc / "GISAS instrument survey(1-16).xlsx",
sheet_name="Form1")
responses.to_csv(Path('./GISAS_instrument_survey.csv'))
columns = {"type": 'What type of instrument is it?',
"hardware": 'What type of hardware allows you to control the relative positions and orientations of beam and sample?\n',
"orientation": 'What sample orientations do you use on a regular basis?\n',
"software": 'What interface(s) do you have to control your instrument?\n',
"alignment": 'What sequence of steps do you use to align individual samples?\n',
"beamshadow": 'What measures are available to quantify shadowing of the beam?\n',
"calibration": 'What signal do you use for angle and sample-to-detector calibration?\n',
"institution": "What large scale facility or other organization is your instrument located at?\n",
"name": "What is the name of your instrument?\n",
"standardization_need": "How great a need do you see for standardization in GISAS?\n",
"beam_measurement": "What option(s) do you have to measure the direct beam?\n"
}
responses.replace(to_replace = {'Sample normal parallel to x axis as incident angle 0;': 'vertical',
'Sample normal parallel to y axis as incident angle 0;': 'horizontal;',
'Sample normal parallel to y axis as incident angle 0;Sample normal parallel to x axis as incident angle 0;': 'both;',
'Sample normal parallel in both x & y;': 'both;'
}, inplace = True)
responses[columns["type"]] = responses[columns["type"]].replace(to_replace = {"SAXS;": "lab GISAXS;"})
responses[columns["institution"]] = responses[columns["institution"]].str.replace("NSLS II",
"National Synchrotron Light Source II")
responses[columns["institution"]] = responses[columns["institution"]].str.replace("NSLS-II",
"National Synchrotron Light Source II")
responses[columns["institution"]] = responses[columns["institution"]].str.replace(", UK",
"")
responses[columns["software"]] = responses[columns["software"]].str.replace("Home-grown scripts in [language];",
"Home-grown scripts")
responses[columns["software"]] = responses[columns["software"]].str.replace("Other, please specify:;",
"Other")
responses[columns["software"]] = responses[columns["software"]].str.replace("Bluesky + EPICS;",
"EPICS + Bluesky;")
responses[columns["software"]] = responses[columns["software"]].str.replace("In the near future, BLISS.",
"Bliss")
responses[columns["hardware"]] = responses[columns["hardware"]].str.replace(
"Individual motor stages for translation and rotation of the sample (beam fixed)",
"motor stages (sample)")
responses[columns["hardware"]] = responses[columns["hardware"]].str.replace(
"A hexapod, moving the sample",
"hexapod (sample)")
responses[columns["hardware"]] = responses[columns["hardware"]].str.replace(
"A linear rail under the hexapod head to allow for different positions along the sample to be scanned, avoiding beam damaged areas;", "linear rail under the hexapod;")
responses[columns["alignment"]] = responses[columns["alignment"]].str.replace(
"alternation of rocking and height scans on the direct and at the reflected for refinement. Eventually, if necessary, roll and yaw scans and lateral translations.",
"Alternating rocking and y scans (direct + reflected).\nOptional: roll, yaw scans, lateral translations")
responses[columns["alignment"]] = responses[columns["alignment"]].str.replace(
"Knife edge scans, rocking curves and roll alignment with also potentially yaw alignment if required;",
"Knife edge scans, rocking curves, roll alignment.\nOptional: yaw alignment;")
responses[columns["calibration"]] = responses[columns["calibration"]].str.replace(
"The position of the specular reflection.;",
"specular reflection;"
)
responses[columns["calibration"]] = responses[columns["calibration"]].str.replace(
"Known positions of peaks or rings of a calibrant.;",
"calibrant;"
)
responses[columns["calibration"]] = responses[columns["calibration"]].str.replace(
"Peaks or rings of a calibrant measured at different distances;",
"calibrant at different distances;"
)
responses[columns["calibration"]] = responses[columns["calibration"]].str.replace(
"and position of direct beam and sample/detector distance measurement;",
"position of direct beam and\nsample/detector distance measurement;"
)
for id, col in columns.items():
fig, ax = plt.subplots()
if id != "standardization_need": # that one is numerical
responses[col] = responses[col].str.rstrip(";")
counts = responses[col].str.split(pat =";", expand = True)
else:
counts = responses[[col]]
if id in ["type", "orientation", "name", "institution", "standardization_need"]:
cols = counts.columns[:1]
combined = counts[counts.columns[0]]
elif id in ["calibration", "software", "hardware", "beam_measurement"]:
# sort these in reverse alphabetical order (several answers possible)
cols = counts.columns[:2]
combined = counts[cols]
combined["first"] = pd.Series()
combined["second"] = pd.Series()
for i, row in combined.iterrows():
if row[cols[1]] is None:
combined.at[i, "first"] = row[cols[0]]
combined.at[i, "second"] = ""
elif row[cols[0]] > row[cols[1]]:
combined.at[i, "first"] = f"{row[cols[0]]}"
combined.at[i, "second"] = f"{row[cols[1]]}"
else:
combined.at[i, "first"] = f"{row[cols[1]]}"
combined.at[i, "second"] = f"{row[cols[0]]}"
combined = combined[["first", "second"]]
else:
cols = counts.columns[:2]
combined = pd.concat([counts[counts.columns[0]], counts[counts.columns[1]]])
combined = combined.str.wrap(64)
if id in ["type", "orientation"]:
wrap = True
else:
wrap = False
counted = combined.value_counts()
labels = []
for label in counted.index:
if type(label) == str:
labelstr = label.rstrip(",")
elif type(label) == int:
labelstr = str(label)
elif (len(label) == 2) and (label[1] == ""):
labelstr = label[0].rstrip(",")
else:
labelstr = "{},\n{}".format(*label)
#for l in label:
# labelstr += str(l)
labels.append(labelstr)
if id == "software":
startangle = -20
else:
startangle = 30
if id != "standardization_need":
wedges, texts = ax.pie(counted, labeldistance = 1.15, labels = labels, startangle = startangle,
textprops = {"size": "small", "wrap": wrap}, wedgeprops=dict(width=0.5), rotatelabels = False)
else:
ax.bar(counted.index, height = counted.values)
ax.set_ylabel("# respondents")
ax.set_xlabel("need for standardization")
fig.savefig(outloc / f"{id}.png", bbox_inches = "tight")
plt.close('all')