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

L-shaped scalebar #64

Closed
swharden opened this issue Dec 1, 2018 · 1 comment
Closed

L-shaped scalebar #64

swharden opened this issue Dec 1, 2018 · 1 comment
Assignees

Comments

@swharden
Copy link
Owner

swharden commented Dec 1, 2018

Plotting data with an L-shaped scalebar is very useful in electrophysiology, but it's not easy to do in matplotlib. Right now there's a tool to do it, but the plotting tools should probably be in a differently-named module. Think about the best way to implement this. This ticket has been opened because this module will soon be removed (replaced by something different later) and I don't want to lose track of this excellent piece of code. Once finalized, this feature should be properly documented.

pyabf.plot.scalebar(abf, hideFrame=True)

pyABF/src/pyabf/plot.py

Lines 104 to 185 in d63172d

def scalebar(abf=None, hideTicks=True, hideFrame=True, fontSize=8, scaleXsize=None, scaleYsize=None, scaleXunits="", scaleYunits="", lineWidth=2):
"""
Add an L-shaped scalebar to the current figure.
This removes current axis labels, ticks, and the figure frame.
"""
# if an ABF objet is given, use its sweep units
if abf:
scaleXunits = abf.sweepUnitsX
scaleYunits = abf.sweepUnitsY
# calculate the current data area
x1, x2, y1, y2 = plt.axis() # bounds
xc, yc = (x1+x2)/2, (y1+y2)/2 # center point
xs, ys = abs(x2-x1), abs(y2-y1) # span
# determine how big we want the scalebar to be
if not scaleXsize:
scaleXsize = abs(plt.xticks()[0][1]-plt.xticks()[0][0])/2
if not scaleYsize:
scaleYsize = abs(plt.yticks()[0][1]-plt.yticks()[0][0])/2
# create the scale bar labels
lblX = str(scaleXsize)
lblY = str(scaleYsize)
# prevent units unecessarially ending in ".0"
if lblX.endswith(".0"):
lblX = lblX[:-2]
if lblY.endswith(".0"):
lblY = lblY[:-2]
if scaleXunits == "sec" and "." in lblX:
lblX = str(int(float(lblX)*1000))
scaleXunits = "ms"
# add units to the labels
lblX = lblX+" "+scaleXunits
lblY = lblY+" "+scaleYunits
lblX = lblX.strip()
lblY = lblY.strip()
# determine the dimensions of the scalebar
scaleBarPadX = 0.10
scaleBarPadY = 0.05
scaleBarX = x2-scaleBarPadX*xs
scaleBarX2 = scaleBarX-scaleXsize
scaleBarY = y1+scaleBarPadY*ys
scaleBarY2 = scaleBarY+scaleYsize
# determine the center of the scalebar (where text will go)
scaleBarXc = (scaleBarX+scaleBarX2)/2
scaleBarYc = (scaleBarY+scaleBarY2)/2
# create a scalebar point array suitable for plotting as a line
scaleBarXs = [scaleBarX2, scaleBarX, scaleBarX]
scaleBarYs = [scaleBarY, scaleBarY, scaleBarY2]
# the text shouldn't touch the scalebar, so calculate how much to pad it
lblPadMult = .005
lblPadMult += .002*lineWidth
lblPadX = xs*lblPadMult
lblPadY = ys*lblPadMult
# hide the old tick marks
if hideTicks:
plt.gca().get_yaxis().set_visible(False)
plt.gca().get_xaxis().set_visible(False)
# hide the square around the image
if hideFrame:
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.gca().spines['bottom'].set_visible(False)
plt.gca().spines['left'].set_visible(False)
# now do the plotting
plt.plot(scaleBarXs, scaleBarYs, 'k-', lw=lineWidth)
plt.text(scaleBarXc, scaleBarY-lblPadY, lblX,
ha='center', va='top', fontsize=fontSize)
plt.text(scaleBarX+lblPadX, scaleBarYc, lblY,
ha='left', va='center', fontsize=fontSize)

@swharden swharden self-assigned this Dec 1, 2018
@swharden
Copy link
Owner Author

swharden commented Dec 1, 2018

@swharden swharden closed this as completed Dec 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant