5

I am plotting seismological data and am creating a figure featuring 16 subplots of different depth slices. Each subplot displays the lat/lon of the epicenter and the color is scaled to its magnitude. I am trying to do two things:

  1. Adjust the scale of all plots to equal the x and y min and max for the area selected. This will allow easy comparison across the plots. (so all plots would range from xmin to xmax etc)

  2. adjust the magnitude colors so they also represent the scale (ie colors represent all available points not just the points on that specific sub plot)

I have seen this accomplished a number of ways but am struggling to apply them to the loop in my code. The data I am using is here: Data.

I posted my code and what the current output looks like below.

import matplotlib.pyplot as plt
import pandas as pd

eq_df = pd.read_csv(eq_csv)
eq_data = eq_df[['LON', 'LAT', 'DEPTH', 'MAG']]
nbound = max(eq_data.LAT)
sbound = min(eq_data.LAT)
ebound = max(eq_data.LON)
wbound = min(eq_data.LON)

xlimit = (wbound, ebound)
ylimit = (sbound, nbound)

magmin = min(eq_data.MAG)
magmax = max(eq_data.MAG)

for n in list(range(1,17)):
    km = eq_data[(eq_data.DEPTH > n - 1) & (eq_data.DEPTH <= n)]
    plt.subplot(4, 4, n)
    plt.scatter(km["LON"], km['LAT'], s = 10, c = km['MAG'], vmin = magmin, vmax = magmax) #added vmin/vmax to scale my magnitude data
    plt.ylim(sbound, nbound) # set y limits of plot
    plt.xlim(wbound, ebound) # set x limits of plot
    plt.tick_params(axis='both', which='major', labelsize= 6)
    plt.subplots_adjust(hspace = 1)
    plt.gca().set_title('Depth = ' + str(n - 1) +'km to ' + str(n) + 'km', size = 8) #set title of subplots
    plt.suptitle('Magnitude of Events at Different Depth Slices, 1950 to Today')
plt.show()

Current Figure

ETA: new code to resolve my issue

4
  • 2
    Scatter had vmin/vmax kwargs. Commented Jan 22, 2020 at 20:59
  • @JodyKlymak what? Commented Jan 22, 2020 at 21:17
  • 1
    plt.scatter(km["LON"], km['LAT'], s = 10, c = km['MAG'], vmin = ebound, vmax= wbound) Commented Jan 22, 2020 at 22:22
  • @parfait vmin/vmax adjust the color scale, so setting that equivalent to my min and max magnitude helps to scale the marker color. Thanks! I still need a way to scale my axes to my NESW boundaries Commented Jan 22, 2020 at 22:38

2 Answers 2

4

In response to this comment on the other answer, here is a demonstration of the use of sharex=True and sharey=True for this use case:

import matplotlib.pyplot as plt
import numpy as np

# Supply the limits since random data will be plotted
wbound = -0.1
ebound = 1.1
sbound = -0.1
nbound = 1.1

fig, axs = plt.subplots(nrows=4, ncols=4, figsize=(16,12), sharex=True, sharey=True)
plt.xlim(wbound, ebound)
plt.ylim(sbound, nbound)
for n, ax in enumerate(axs.flatten()):
    ax.scatter(np.random.random(20), np.random.random(20), 
               c = np.random.random(20), marker = '.')
    ticks = [n % 4 == 0, n > 12]
    ax.tick_params(left=ticks[0], bottom=ticks[1])
    ax.set_title('Depth = ' + str(n - 1) +'km to ' + str(n) + 'km', size = 12)

plt.suptitle('Magnitude of Events at Different Depth Slices, 1950 to Today', y = 0.95)
plt.subplots_adjust(wspace=0.05)
plt.show()

enter image description here

Explanation of a couple things:

  1. I have reduced the horizontal spacing between subplots with subplots_adjust(wspace=0.05)
  2. plt.suptitle does not need to be (and should not be) in the loop.
  3. ticks = [n % 4 == 0, n > 12] creates a pair of bools for each axis which is then used to control which tick marks are drawn.
  4. Left and bottom tick marks are controlled for each axis with ax.tick_params(left=ticks[0], bottom=ticks[1])
  5. plt.xlim() and plt.ylim() need only be called once, before the loop
Sign up to request clarification or add additional context in comments.

3 Comments

So several things: No matter what I cannot remove the tick marks in between figures. Also if I remove the plt.xlim() and plt.ylim() from the loop the axes are no longer even. My code has evolved since the question was initially posted. I can open a new question if you think that would be beneficial to see my updated code?
@Rebekah I would suggest editing this question to include your current code - I can then modify my example to reflect the changes in your code
@Rebekah If you run my exact code here do you get the same result I show in the answer?
2

Finally got it thanks to some help above and some extended googling.

I have updated my code above with notes indicating where code was added.

To adjust the limits of my plot axes I used:

plt.ylim(sbound, nbound)
plt.xlim(wbound, ebound)

To scale my magnitude data across all plots I added vmin, vmax to the following line:

plt.scatter(km["LON"], km['LAT'], s = 10, c = km['MAG'], vmin = magmin, vmax = magmax)

And here is the resulting figure:New Figure

3 Comments

If you want to get rid of the tick labels in between subplots and only display the leftmost and bottommost you can add sharex=True, sharey=True to plt.subplot().
@WilliamMiller, a great idea to clean this up! My code has evolved a little since I posted this question, so I am having some trouble getting it to work. The loop now looks like fig, axes = plt.subplots(4,4, sharex=True, sharey=True) for ax in axes.flat: for n in list(range(1, 17)): but the sharex functions aren't adjusting the axes. Should there be a plt.subplots within the loop?
See my answer for an example of the usage

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.