@@ -199,64 +199,133 @@ def shear(self, x, dx=0.01, order=5):
199199 )
200200
201201 def bending_stress (self , x , dx = 1 , c = 1 ):
202- """returns the bending stress at global coordinate x"""
202+ """
203+ returns the bending stress at global coordinate x
204+
205+ .. deprecated:: 0.1.7a1
206+ calculate bending stress as :obj:`Beam.moment(x) * c / Ixx`
207+
208+ """
209+ warn ("bending_stress will be removed soon" , DeprecationWarning )
203210 return self .moment (x , dx = dx ) * c / self .Ixx
204211
212+ @staticmethod
213+ def __validate_plot_diagrams (diagrams , diagram_labels ):
214+ """
215+ Validate the parameters for the plot function
216+ """
217+
218+ # create default (and complete list of valid) diagrams that are
219+ # implemented
220+ default_diagrams = ("shear" , "moment" , "deflection" )
221+ if diagrams is None and diagram_labels is None :
222+ # set both the diagrams and labels to their defaults
223+ # no need for further validation of these values since they are
224+ # set internally
225+ return default_diagrams , default_diagrams
226+
227+ if diagrams is None and diagram_labels is not None :
228+ raise ValueError ("cannot set diagrams from labels" )
229+
230+ if diagram_labels is None :
231+ diagram_labels = diagrams
232+
233+ if len (diagrams ) != len (diagram_labels ):
234+ raise ValueError (
235+ "length of diagram_labels must match length of diagrams"
236+ )
237+ for diagram in diagrams :
238+ if diagram not in default_diagrams :
239+ raise ValueError (
240+ f"values of diagrams must be in { default_diagrams } "
241+ )
242+ return diagrams , diagram_labels
243+
205244 def plot (
206- self , n = 250 , plot_stress = False , title = "Beam Analysis"
207- ): # pragma: no cover
245+ self ,
246+ n = 250 ,
247+ title = "Beam Analysis" ,
248+ diagrams = None ,
249+ diagram_labels = None ,
250+ ** kwargs ,
251+ ):
208252 """
209- plot the deflection, moment, and shear along the length of the beam
253+ Plot the deflection, moment, and shear along the length of the beam
210254
211- The plot method will create a matplotlib.pyplot figure with the
212- deflection, moment, shear, and optionally stress along the length of
213- the beam element.
255+ The plot method will create a :obj:`matplotlib.pyplot` figure with the
256+ deflection, moment, and shear diagrams along the length of the beam
257+ element. Which of these diagrams, and their order may be customized.
258+
259+ Parameters:
260+ n (:obj:`int`): defaults to `250`:
261+ number of data-points to use in plots
262+ title (:obj:`str`) defaults to 'Beam Analysis`
263+ title on top of plot
264+ diagrams (:obj:`tuple`): defaults to
265+ `('shear', 'moment', 'deflection')`
266+ tuple of diagrams to plot. All values in tuple must be strings,
267+ and one of the defaults.
268+ Valid values are :obj:`('shear', 'moment', 'deflection')`
269+ diagram_labels (:obj:`tuple`): y-axis labels for subplots.
270+ Must have the same length as `diagrams`
214271
215272 Returns:
216- :obj:`tuple`: Tuple of matplitlib.pyplot figure and list of axes
217- in the form (figure, axes)
273+ :obj:`tuple`:
274+ Tuple of :obj:`matplotlib.pyplot` figure and list of axes in
275+ the form :obj:`(figure, axes)`
218276
219277 .. note:: The plot method will create the figure handle, but will not
220278 automatically show the figure.
221279 To show the figure use :obj:`Beam.show()` or
222280 :obj:`matplotlib.pyplot.show()`
223281
282+ .. versionchanged:: 0.1.7a1 Removed :obj:`bending_stress` parameter
283+ .. versionchanged:: 0.1.7a1
284+ Added :obj:`diagrams` and :obj:`diagram_labels` parameters
285+
224286 """
225- rows = 4 if plot_stress else 3
226- fig , axes = plt .subplots (rows , 1 , sharex = "all" )
227287
228- # locations of nodes in global coordinate system
229- locations = self .mesh .nodes
288+ kwargs .setdefault ("title" , "Beam Analysis" )
289+ kwargs .setdefault ("grid" , True )
290+ kwargs .setdefault ("xlabel" , "Beam position, x" )
291+ kwargs .setdefault ("fill" , True )
292+ kwargs .setdefault ("plot_kwargs" , {})
293+ kwargs .setdefault ("fill_kwargs" , {"color" : "b" , "alpha" : 0.25 })
294+
295+ diagrams , diagram_labels = self .__validate_plot_diagrams (
296+ diagrams , diagram_labels
297+ )
298+ fig , axes = plt .subplots (len (diagrams ), 1 , sharex = "all" )
299+ if len (diagrams ) == 1 :
300+ # make sure axes are iterable, even if there is only one
301+ axes = [axes ]
230302
231- # Get the global x values. Note that the x-values for the moment and
232- # shear do not contain the endpoints of the x values for the deflection
233- # curve. This is because differentiation technique used is the central
234- # difference formula, which cannot calculate the value at the
235- # endpoints
236303 xd = np .linspace (0 , self .length , n ) # deflection
237- xm = xd [1 :- 2 ] # moment (and stress)
238- xv = xm [2 :- 3 ] # shear
239- v = [self .deflection (xi ) for xi in xd ] # deflection
240- m = [self .moment (xi , dx = self .length / n ) for xi in xm ] # moment
241- V = [self .shear (xi , dx = self .length / n ) for xi in xv ] # shear
242-
243- # Set up plotting variables to be able to iterate over them more easily
244- xs = [xv , xm , xd ]
245- y = [V , m , v ]
246- labels = ["shear" , "moment" , "deflection" ]
247- if plot_stress :
248- q = [self .bending_stress (xi , dx = self .length / n ) for xi in xm ]
249- xs .append (xm )
250- y .append (q )
251- labels .append ("stress" )
252-
253- for ax , x , y , label in zip (axes , xs , y , labels ):
254- ax .plot (x , y )
255- ax .fill_between (x , y , 0 , color = "b" , alpha = 0.25 )
304+ x , y = None , None
305+ for ax , diagram , label in zip (axes , diagrams , diagram_labels ):
306+ if diagram == "deflection" :
307+ x = xd
308+ y = [self .deflection (xi ) for xi in x ]
309+ if diagram == "moment" :
310+ x = xd
311+ y = [self .moment (xi , dx = self .length / (n + 3 )) for xi in x ]
312+ if diagram == "shear" :
313+ x = np .linspace (0 , self .length , n + 4 )[2 :- 2 ]
314+ y = [self .shear (xi , dx = self .length / (n + 4 )) for xi in x ]
315+
316+ # regardless of the diagram that is being plotted, the number of
317+ # data points should always equal the number specified by user
318+ assert len (x ) == n , "x does not match n"
319+ assert len (y ) == n , "y does not match n"
320+
321+ ax .plot (x , y , ** kwargs ["plot_kwargs" ])
322+ if kwargs ["fill" ]:
323+ ax .fill_between (x , y , 0 , ** kwargs ["fill_kwargs" ])
256324 ax .set_ylabel (label )
257- ax .grid (True )
325+ ax .grid (kwargs [ "grid" ] )
258326
259- axes [- 1 ].set_xlabel ("Beam position, x" )
327+ locations = self .mesh .nodes # in global coordinate system
328+ axes [- 1 ].set_xlabel (kwargs ["xlabel" ])
260329 axes [- 1 ].set_xticks (locations )
261330
262331 fig .subplots_adjust (hspace = 0.25 )
0 commit comments