is there a possibility to select a certain class from a 2D classification job and display the raw images of all particles belonging to that class?
The way I do it is to run a select job to select one class, run an extract job with particles of this class and then open the mrc files in the corresponding job-folder. But that is somewhat cumbersome.
Best
Dario
I would also be interested, if someone figured out how to do this.
It would help a lot to judge the quality of 2d classification when working with certain datasets.
It is indeed possible using cryosparc-tools. I’ve included a script to do this below.
I do want to point out that we do not expect single particle images to be particularly interpretable, or look like much at all. For instance, here are some particle images from a T20S dataset which goes to 2.8 Å:
from cryosparc.tools import CryoSPARC
import json
import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
with open(Path('~/instance-info.json').expanduser(), 'r') as f:
instance_info = json.load(f)
cs = CryoSPARC(**instance_info)
assert cs.test_connection()
project_number = "P325"
workspace_number = "W4"
job_number = "J117"
class_number = 4
project = cs.find_project(project_number)
job = project.find_job(job_number)
particles = job.load_output("particles")
particle_subset = particles.query({'alignments2d/class': class_number})
particle_subset = particle_subset.query({
'uid': np.random.choice(
particle_subset['uid'], size = 12, replace = False
)
})
mrcs = {
path: project.download_mrc(path)[1]
for path in set(
row['blob/path'] for row in particle_subset.rows()
)
}
particle_images = []
for row in particle_subset.rows():
particle_images.append(mrcs[row['blob/path']][row['blob/idx']])
fig, axs = plt.subplots(3, 4)
plt.subplots_adjust(wspace=0.1, hspace=0.1)
axs = axs.flatten()
for idx, ax in enumerate(axs):
img = particle_images[idx]
# set greyscale to cover the middle 90% of pixel values.
# Note this means that 10% of pixels are clipped to 0 or 1.
lims = (np.percentile(img, 5), np.percentile(img, 95))
ax.axis('off')
ax.imshow(
particle_images[idx],
cmap = 'gray',
vmin = lims[0],
vmax = lims[1]
)
fig.show()
Hi Rich - the particles should be pretty clearly visible (and interpretable) if contrast adjusted and lowpass filtered though, right? After all, they are clearly identifiable on the original micrographs?
Hi @olibclarke! This is a good point – I suppose I should have said “…look like much at all without additional processing”. Certainly if the particle images are lowpass filtered, we’d expect it to become clear what they are.
Is it possible to do this on the fly for visualization (prior to the greyscale adjustment)? Or does it require running a Downsample job on the whole stack? Or some simpler adjustments - e.g. just adjusting levels a bit makes the same particles more visible (just done all at once here, not per particle):
Hi @olibclarke! Definitely can be done on the fly. We use internal code to present the images, so this won’t be exactly the same as what you see in the GUI, but using scikit-image’s Butterworth filter, we can produce this plot of low-pass filtered particle images (note the images are of different particles b/c the script picked a different random sample when I re-ran it):
from skimage.filters import butterworth
N = particle_images[0].shape[0]
def lowpass(img):
return butterworth(
img,
cutoff_frequency_ratio = 6/N,
high_pass = False,
order = 1
)
fig_lp, axs_lp = plt.subplots(3, 4)
plt.subplots_adjust(wspace=0.1, hspace=0.1)
axs_lp = axs_lp.flatten()
for idx, ax in enumerate(axs_lp):
img = lowpass(particle_images[idx])
ax.axis('off')
ax.imshow(img, cmap = 'gray')
fig_lp.show()