2014-01-24 12 views
11

Vier-Wege-logarithmische Darstellung ist ein sehr häufig verwendeter Graph für Vibrationskontrolle und Erdbebenschutz. Ich bin ziemlich interessant, wie dieses Diagramm in Matplotlib geplottet werden kann, anstatt Achsen in Inkscape hinzuzufügen. Eine Probe der logarithmischen Four-Way-Darstellung ist hier.Wie man logarithmische 4-Wege-Darstellung in Matplotlib macht?

Four-way logarithmic plot

A schnell und schmutzig kann Python Code Hauptteil der Figur erzeugen, aber ich kann die beiden Achsen auf der Figur nicht hinzuzufügen. http://matplotlib.org/examples/axes_grid/demo_curvelinear_grid.html bietet ein Beispiel für das Hinzufügen von Achsen, aber es funktioniert nicht. Hat jemand ähnliche Erfahrung mit dem Hinzufügen von Achsen zu Matplotlib?

from pylab import * 
from mpl_toolkits.axisartist.grid_helper_curvelinear import GridHelperCurveLinear 
from mpl_toolkits.axisartist import Subplot 
beta=logspace(-1,1,500) 
Rd={} 
for zeta in [0.01,0.1,0.2,0.7,1]: 
    Rd[zeta]=beta/sqrt((1-beta*beta)**2+(2*beta*zeta)**2) 
    loglog(beta,Rd[zeta]) 
ylim([0.1,10]) 
xlim([0.1,10]) 
grid('on',which='minor') 

my plot

Update: Vielen Dank! Ich benutze Inkscape, um die obige Abbildung zu ändern. Ich denke, das Ergebnis ist in Ordnung. Ich suche jedoch immer noch nach Methoden, um diese Figur in Matplotlib zu zeichnen. Inkscape Modified

+0

sind Sie, dass bestimmte Figur zu erzeugen suchen, oder suchen Sie zeichnen Daten und erhalten diese Art der Ausgabe (Stil der Tickbeschriftungen, Rasterlinien, Bereich der Achsen, Textbeschriftungen auf den Diagonalachsen Ticks, etc ...), oder suchen Sie nach etwas, das automatisch eine schön aussehende Handlung für was auch immer macht Daten, die du zufällig machst? –

+0

Ich suche nach Möglichkeiten, Achsen, Zecken und Etiketten frei zu manipulieren. Ich bin nicht so glücklich mit Achsen, die standardmäßig von Matplotlib erzeugt werden, besonders Axes3D. Eigentlich habe ich eine Frage über 3D-Achsen in Matplotlib gestellt, es scheint, dass niemand an diesem Thema interessiert ist. Diese Frage ist nur ein Beispiel für Manipulationsachsen in Matplotlib. – Kattern

+0

Hatten Sie im Zusammenhang mit dieser Frage die Möglichkeit, die zusätzlichen Achsen zum Plotten zu verwenden? –

Antwort

2

Hier ist eine Teillösung. Ich arbeite immer noch daran, wie man das alles in einem natürlichen loglog() Plot tut, anstatt die Daten zu skalieren. (Um dieses Beispiel vervollständigen würden Sie definieren müssen, um benutzerdefinierte tick-Lables, so dass sie 10**x anzuzeigen, anstatt x.)

%matplotlib inline     # I am doing this in an IPython notebook. 
from matplotlib import pyplot as plt 
import numpy as np 
from numpy import log10 

# Generate the data 
beta = np.logspace(-1, 1, 500)[:, None] 
zeta = np.array([0.01,0.1,0.2,0.7,1])[None, :] 
Rd = beta/np.sqrt((1 - beta*beta)**2 + (2*beta*zeta)**2) 

def draw(beta=beta, Rd=Rd): 
    plt.plot(log10(beta), log10(Rd)) 
    plt.ylim([log10(0.1), log10(10)]) 
    plt.xlim([log10(0.1), log10(10)]) 
    plt.grid('on',which='minor') 
    ax = plt.gca() 
    ax.set_aspect(1) 

from mpl_toolkits.axisartist import GridHelperCurveLinear 
from matplotlib.transforms import Affine2D 
from mpl_toolkits.axisartist import SubplotHost 
from mpl_toolkits.axisartist import Subplot 

#tr = Affine2D().rotate(-np.pi/2) 
#inv_tr = Affine2D().rotate(np.pi/2) 

class Transform(object): 
    """Provides transforms to go to and from rotated grid. 

    Parameters 
    ---------- 
    ilim : (xmin, xmax, ymin, ymax) 
     The limits of the displayed axes (in physical units) 
    olim : (xmin, xmax, ymin, ymax) 
     The limits of the rotated axes (in physical units) 
    """ 
    def __init__(self, ilim, olim): 
     # Convert each to a 3x3 matrix and compute the transform 
     # [x1, y1, 1] = A*[x0, y0, 1] 
     x0, x1, y0, y1 = np.log10(ilim) 
     I = np.array([[x0, x0, x1], 
         [y0, y1, y1], 
         [ 1, 1, 1]]) 

     x0, x1, y0, y1 = np.log10(olim) 
     x_mid = (x0 + x1)/2 
     y_mid = (y0 + y1)/2 
     O = np.array([[ x0, x_mid, x1], 
         [y_mid, y1, y_mid], 
         [ 1,  1,  1]]) 
     self.A = np.dot(O, np.linalg.inv(I)) 
     self.Ainv = np.linalg.inv(self.A) 

    def tr(self, x, y): 
     """From "curved" (rotated) coords to rectlinear coords""" 
     x, y = map(np.asarray, (x, y)) 
     return np.dot(self.A, np.asarray([x, y, 1]))[:2] 

    def inv_tr(self, x, y): 
     """From rectlinear coords to "curved" (rotated) coords""" 
     x, y = map(np.asarray, (x, y)) 
     return np.dot(self.Ainv, np.asarray([x, y, 1]))[:2] 

ilim = (0.1, 10) 
olim = (0.01, 100) 
tr = Transform(ilim + ilim, olim + olim) 

grid_helper = GridHelperCurveLinear((tr.tr, tr.inv_tr)) 

fig = plt.gcf() 
ax0 = Subplot(fig, 1, 1, 1) 
ax1 = Subplot(fig, 1, 1, 1, grid_helper=grid_helper, frameon=False) 
ax1.set_xlim(*np.log10(olim)) 
ax1.set_ylim(*np.log10(olim)) 
ax1.axis["left"] = ax1.new_floating_axis(0, 0.) 
ax1.axis["bottom"] = ax1.new_floating_axis(1, 0.0) 
fig.add_subplot(ax0) 
fig.add_subplot(ax1) 
ax0.grid('on', which='both') 
ax1.grid('on', which='both') 

plt.plot(log10(beta), log10(Rd)) 
plt.ylim(np.log10(ilim)) 
plt.xlim(np.log10(ilim)) 

Output

2

Dies scheint ein bisschen trickreich zu sein, als es sollte. Es gibt Möglichkeiten, die Stacheln (Achsenlinien) zu zentrieren und zu rotieren, aber diese funktionieren nicht zusammen. Das Hinzufügen einer normalen Achse auf einer Linie (a la mpl demos) führt zu einer gekrümmten Achse (weil sie logarithmisch ist). Hier ist ein [armes] Beispiel für das Zeichnen - wie in Inkscape, das mit den Beispieldaten wie ein zusätzliches Paar Achsenstacheln aussieht.

import matplotlib.pyplot as plt 
import numpy as np 

#data 
b = np.logspace(-1, 1, 500) 
Rd = {} 
for zeta in [0.01, 0.1, 0.2, 0.7, 1]: 
    Rd[zeta] = b/np.sqrt((1 - b * b) ** 2 + (2 * b * zeta) ** 2) 

#plot 
fig = plt.figure() 
ax1 = fig.add_subplot(111) 

for z in Rd: 
    ax1.loglog(b, Rd[z]) 

ax1.set_xlim([0.1, 10]) 
ax1.set_ylim([0.1, 10]) 
ax1.set_aspect(1.) 

#draw lines to look like diagonal spines (axes) 
xmin, xmax = ax1.get_xlim() # xlim == ylim 

a = np.log10(xmin) 
b = np.log10(xmax) 
span = b - a 
period_points = 3 # number of points/ticks per decade 
npts = (span * period_points) + 1 # +1 for even powers of 10 
x1 = np.logspace(a, b, num=npts) 
x2 = np.logspace(b, a, num=npts) 

ax1.plot(x1, x1, color='k', marker='x', ms='9') 
ax1.plot(x1, x2, color='k', marker='x', ms='9') 
#NOTE: v1.2.1 lacks 'TICKUP' and similar - these may be 
# a better choice in v1.3x and beyond 

ax1.text(0.97, 0.9, 
     "axis label: A", 
     size='large', 
     horizontalalignment='right', 
     verticalalignment='top', 
     rotation=45, 
     transform=ax1.transAxes, 
     #bbox={'facecolor': 'white', 'alpha': 0.5, 'pad': 10}, 
     ) 

ax1.text(0.03, 0.9, 
     "axis label: B", 
     size='large', 
     horizontalalignment='left', 
     verticalalignment='top', 
     rotation=-45, 
     transform=ax1.transAxes, 
     #bbox={'facecolor': 'white', 'alpha': 0.5, 'pad': 10}, 
     ) 

plt.savefig("example.pdf") 
+0

Ja, ich stimme zu. Matplotlib ist immer noch nicht so ausgereift wie Matlab, Sie werden immer etwas finden, das nicht so funktioniert, wie Sie es erwartet haben. Vielleicht ist es am einfachsten, wenn Sie Inkscape verwenden, um die beiden Achsen hinzuzufügen. – Kattern

+0

Abhängig davon, wie oft Sie solche Diagramme erstellen, könnte das eine bessere Idee sein, als eine allgemeinere Funktion zum Zeichnen der Achsen in Matplotlib zu erhalten. –