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

A method to plot beam diagram using sympy's own plot() #17345

Open
wants to merge 11 commits into
base: master
from

Conversation

@ishanaj
Copy link
Contributor

commented Aug 5, 2019

This PR is an initiative to find an alternative to PR #17240 . With both PR's having the same goal. This PR intends to directly use sympy.plot() rather than using matplotlib or the backend attribute.
Currently the draw() function in this PR can plot:

  • rectangle for the beam
  • loads except moment and point loads
  • supports
  • arrows for the loads
  • arrows (or colour fill) for uniformly varying loads and other higher order loads
  • scaling of the plot
  • documentation

Release Notes

  • physics.continuum_mechanics
    • a new method draw() has been added in the beam module which gives functionality to draw the beam diagrams using matplotlib
  • plotting
    • functionalities of adding markers, annotations, rectangles, filling color in a plot have been added to the matplotlib backend of the plotting module
@sympy-bot

This comment has been minimized.

Copy link

commented Aug 5, 2019

Hi, I am the SymPy bot (v147). I'm here to help you write a release notes entry. Please read the guide on how to write release notes.

Your release notes are in good order.

Here is what the release notes will look like:

  • physics.continuum_mechanics

    • a new method draw() has been added in the beam module which gives functionality to draw the beam diagrams using matplotlib (#17345 by @ishanaj)
  • plotting

    • functionalities of adding markers, annotations, rectangles, filling color in a plot have been added to the matplotlib backend of the plotting module (#17345 by @ishanaj)

This will be added to https://github.com/sympy/sympy/wiki/Release-Notes-for-1.5.

Note: This comment will be updated with the latest check if you edit the pull request. You need to reload the page to see it.

Click here to see the pull request description that was parsed.

This PR is an initiative to find an alternative to PR #17240 . With both PR's having the same goal. This PR intends to directly use `sympy.plot()` rather than using matplotlib or the `backend` attribute.
Currently the `draw()` function in this PR can plot:
- [x] rectangle for the beam 
- [x] loads ~~except moment and point loads~~
- [x] supports
- [x] arrows for the loads
- [x] arrows (or colour fill) for uniformly varying loads and other higher order loads
- [x] scaling of the plot
- [x] documentation


#### Release Notes

<!-- BEGIN RELEASE NOTES -->
- physics.continuum_mechanics
    - a new method `draw()` has been added in the beam module which gives functionality to draw the beam diagrams using matplotlib
-  plotting
    -  functionalities of adding markers, annotations, rectangles, filling color in a plot have been added to the matplotlib backend of the plotting module
<!-- END RELEASE NOTES -->

@ishanaj ishanaj changed the title Aa method to plot beam diagram using sympy's own plot() A method to plot beam diagram using sympy's own plot() Aug 5, 2019

@ishanaj

This comment has been minimized.

Copy link
Contributor Author

commented Aug 5, 2019

Tested the following example:

>>> E, I = symbols('E, I')
>>> b = Beam(9, E, I)
>>> b.apply_load(-12, 9, -1)  # gets skipped
>>> b.apply_load(50, 5, -2)  # gets skipped
>>> b.apply_load(3, 6, 1, end=8)
>>> b.apply_load(4, 0, 0, end=5)
>>> b.draw()

Screenshot - 05-08-2019 , 19_49_21

I have a few questions to discuss:

  • How to put arrows for these loads or fill it with color? I have tried fill=True but that doesn't work as probably there is no closed area.
  • Also, currently the magnitude of the load is low, but if it gets high we might need to scale down the height of the plot of uniform load and varying load. I have tried yscale but not able to get how that works. Any ideas?

ping @jashan498 @moorepants

@moorepants

This comment has been minimized.

Copy link
Member

commented Aug 5, 2019

How to put arrows for these loads or fill it with color? I have tried fill=True but that doesn't work as probably there is no closed area.

You'll have to add that to the sympy.plot() features if it doesn't already exist. Or you add them manually with matplotlib in the beam code. The ideal thing is to enhance sympy.plot() so that it benefits all sympy plotting needs. For example, adding a common way to plot y = 1 @ x = 0, y = 0 x!=0 would be a nice addition.

Also, currently the magnitude of the load is low, but if it gets high we might need to scale down the height of the plot of uniform load and varying load. I have tried yscale but not able to get how that works. Any ideas?

Good point. There is the idea of plotting an accurate load curve and the idea of making a pleasing pictorial version of the beam. For the latter, you may need to take liberties to scale so the beam always looks nice (like in text books). Maybe both should ultimately be supported. For example you could do Beam.draw() for the realistic one and Beam.draw(pictorial=True) for the scaled version.

added features in the plotting module for plotting annotations, marke…
…rs, and

rectangles, and modified the beam.draw() function to use these to plot
the beam diagram
@ishanaj

This comment has been minimized.

Copy link
Contributor Author

commented Aug 8, 2019

I have added some features in the plotting module using which we can now use annotations, markers and rectangle via sympy.plot. I will be adding documentation and test for both the modules later.

Also, annotations, markers, rectangles are used as keyword arguments in the plot function. They are in fact a list of the dictionaries, eg:
annotations=[{'a': x, 'b': y........}, {'a2': x2, 'b2': x2.....},....]
where each dictionary represents all the parameters that are to be passed in the ax.annotate() function in the backend

I have tested the following example:

R1, R2 = symbols('R1, R2')
E, I = symbols('E, I')

b1 = Beam(50, 20, 30)

b1.apply_load(10, 2, -1)
b1.apply_load(R1, 10, -1)
b1.apply_load(R2, 30, -1)
b1.apply_load(1, 5, 0, 23)
b1.apply_load(1, 30, 1, 50)
b1.apply_support(50, "pin")
b1.apply_support(0, "fixed")
b1.apply_support(20, "roller")
b1.draw()

Screenshot - 08-08-2019 , 21_48_25

PS: I have updated the TODO's in the first comment.

@moorepants

This comment has been minimized.

Copy link
Member

commented Aug 8, 2019

Looks nice!

added functionality of filling colour in plot using matplotlib's
fill_between(), and used the same in representing higher order beam loads
@ishanaj

This comment has been minimized.

Copy link
Contributor Author

commented Aug 9, 2019

The diagram now looks like:
image

I have considered coloring the higher loads (rather than filling them with arrows) as it would further make the plot clean in cases where a point load is superimposed on them.

added functionality to scale the beam diagram using a parameter
pictorial=True, also modified plot.markers a bit
@ishanaj

This comment has been minimized.

Copy link
Contributor Author

commented Aug 10, 2019

I have added the option for the user to scale the plot via a parameter pictorial=True.
This would be helpful in the cases where the magnitude of the load is too high (or too low) and might look a bit indecent or may go out of the plot.
This is an example that has a similar problem:

>>> R1, R2 = symbols('R1, R2')
>>> E, I = symbols('E, I')

>>> b1 = Beam(50, 20, 30)

>>> b1.apply_load(10, 2, -1)
>>> b1.apply_load(R1, 10, -1)
>>> b1.apply_load(R2, 30, -1)
>>> b1.apply_load(90, 5, 0, 23)
>>> b1.apply_load(10, 30, 1, 50)
>>> b1.apply_support(50, "pin")
>>> b1.apply_support(0, "fixed")
>>> b1.apply_support(20, "roller")
# case 1 on the left
>>> p = b1.draw()
>>> p.show()

# case 2 on the right
>>> p1 = b1.draw(pictorial=True)
>>> p1.show()

Screenshot - 10-08-2019 , 23_04_45

@ishanaj ishanaj marked this pull request as ready for review Aug 10, 2019

@moorepants

This comment has been minimized.

Copy link
Member

commented Aug 12, 2019

If you are plotting the unit of length on the x axis and unit of force on the y axis, what is your default scaling factor, 1:1? Does it make sense to do 1:1 as a default? I'm not sure it does. What is the exact difference in the pictorial or not?

@ishanaj

This comment has been minimized.

Copy link
Contributor Author

commented Aug 12, 2019

Setting pictorial=True would simply alter the height of the udl, vdl or higher loads and the rest would remain same. Here we set udl magnitude to length/2, and vdl and other higher order loads magnitude/unit to 1N/m, for any plot.

pictorial =False makes the diagram with the exact dimensions, so a scale of 1:1 is present.
But in some cases the magnitude of the load becomes high due to which the height of the udl or vdl gets high enough to go out of the plot as the ylimit is set to -length, length. So as to decrease this height to a nominal amount such that the plot looks better we can use pictorial=True

@codecov

This comment has been minimized.

Copy link

commented Aug 12, 2019

Codecov Report

Merging #17345 into master will decrease coverage by 0.023%.
The diff coverage is 16.363%.

@@              Coverage Diff              @@
##            master    #17345       +/-   ##
=============================================
- Coverage   74.669%   74.646%   -0.024%     
=============================================
  Files          631       632        +1     
  Lines       163259    163893      +634     
  Branches     38302     38451      +149     
=============================================
+ Hits        121905    122340      +435     
- Misses       36014     36199      +185     
- Partials      5340      5354       +14
@ishanaj

This comment has been minimized.

Copy link
Contributor Author

commented Aug 14, 2019

The build fails for python 3.7. I don't know why it is not able to import numpy usingimport_kwargs.
Initially, I was running it on python 3.5 and everything works well with it.
Any idea why it does so?

@asmeurer

This comment has been minimized.

Copy link
Member

commented Aug 15, 2019

Your tests need to correctly skip when numpy is not installed. NumPy is an optional dependency, so the tests should not fail when it is not installed.

@ishanaj

This comment has been minimized.

Copy link
Contributor Author

commented Aug 17, 2019

@asmeurer I have added a line in the function which checks whether numpy is successfully imported and raises import error accordingly.
Also I have skipped the doctests currently, but is there a way to skip them only when numpy is not installed?

@jashan498

This comment has been minimized.

Copy link
Contributor

commented Aug 17, 2019

You can use @doctest_depends_on(modules=('numpy')) decorator to skip doctests in such scenarios.

@ishanaj

This comment has been minimized.

Copy link
Contributor Author

commented Aug 17, 2019

ping @moorepants @jashan498 The work on this PR is complete. Please have a look

@ishanaj

This comment has been minimized.

Copy link
Contributor Author

commented Aug 18, 2019

The tests have finally passed!

markers += support_markers

sing_plot = plot(height + load_eq, (x, 0, length),
xlim=(-2, length + 2), ylim=(-length, length), annotations=annotations,

This comment has been minimized.

Copy link
@oscargus

oscargus Aug 20, 2019

Contributor

Would it make sense to use relative spacing instead of absolute? Like (-0.05*length, 1.05*length)?

This comment has been minimized.

Copy link
@ishanaj

ishanaj Aug 20, 2019

Author Contributor

I tried xlim=(-0.05*length, 1.05*length), it more or less gives similar output.

The main aim of having xlim is to include the rectangle (denoting the fixed support) in the plot.
Since the width of this rectangle is every time length/10 (see line 1651), I think then we can rather go for xlim=(-length/10, length + length/10).
I guess then even this would now be relative.
Should we go for this then? @oscargus

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
7 participants
You can’t perform that action at this time.