Skip to content

Specifying tolerance distance in streamplot #9269

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

Open
liangwang0734 opened this issue Oct 2, 2017 · 13 comments
Open

Specifying tolerance distance in streamplot #9269

liangwang0734 opened this issue Oct 2, 2017 · 13 comments
Labels
Difficulty: Hard https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues keep Items to be ignored by the “Stale” Github Action

Comments

@liangwang0734
Copy link

liangwang0734 commented Oct 2, 2017

Desired results

Tecplot can produce continuous 2d contours with arrows nicely centered on the lines. For example,
teplot_treamtracer_with_arrows.

Outcome of Matplotlib

  • Matplotlib can make similar plots with streamplot. However, the stopping of tracing is hard to adjust and one often gets broken (i.e., not continuous) lines, which can misleadingly look like sudden disappearance/stopping of streams or field lines. For example, matplotlib_streamplot.
    • Increasing minlength and density at the same time helps, but this basically traces more seeds and rejects many of them unless a carefully chosen set of seeds are used. This could be better done by using smaller tolerance distance between integration points.
  • Another way I tried to place arrows along contour lines using quiver. But the arrow tips usually fall off the contour lines a little.

Requested feature

  • Better control of streamplot is desirable. Right now, it appears to me that streamplot divides the domain into blocks and stop tracing when entering a block occupied by another traced line. But the number of blocks, and thus the size of the blocks rely on density only. Maybe it is better to allow specifying the tolerance distance. Or, maybe we can simply allow a "density_stop" to set the block sizes separately.
@jklymak
Copy link
Member

jklymak commented Oct 3, 2017

In my opinion, what you really want is a way to put arrows on contour. streamplot, if I understand correctly, is something different than a streamline (though they should co-incide for a steady flow). I'd look at clabel, and steal the code that figures out the angle for the labels, and then write a cmarker. I think if you are careful with the marker placement you could get it to look pretty good.

@liangwang0734
Copy link
Author

liangwang0734 commented Oct 3, 2017

Thank you, @jklymak . I just played with clabel a little without looking into the source. Here is what I got:

import numpy as np
import matplotlib.ticker as ticker
import matplotlib.pyplot as plt


def calc_psi2d(fx, fy, dx=1, dy=1):#solenoidal flows
    '''
    Calcualte psi by integrating dpsi = -fy*dx + fx*dy, psi[0,0]=0.
    Notes: 
        1. (fx=dpsi/dy,fy=-dpsi/dx) is called Hamiltonian gradient of psi
        2. contours of psi give vector field (fx, fy);
        3. div(f)=0
    '''
    ny,nx=fx.shape
    psi=np.zeros((ny,nx))
    for jx in range(1,nx):
        psi[0,jx]=psi[0,jx-1]-fy[0,jx]*dx
    for jy in range(1,ny):
        psi[jy,:]=psi[jy-1,:]+fx[jy,:]*dy
    return psi

delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
U = Y
V = -X
Z = calc_psi2d(U,V)

plt.figure()

CS = plt.contour(X, Y, Z)
fmt = ticker.StrMethodFormatter('>')
plt.clabel(CS, CS.levels, fmt=fmt, inline=False)
plt.title('contour+clabel: arrow directions randomly wrong')

plt.figure()
plt.streamplot(X,Y,U,V)
plt.title('streamplot: arrow directions correct')

plt.show()

This looks nice (though the "arrow" tips are still off a little), but the some arrow directions are wrong? Is possible to further improve the results using marker instead of string labels, so that we can place sharp, pointed arrows instead of textual ">"?

PS: I think calc_label_rot_and_inline does the rotation of label.

@tacaswell
Copy link
Member

@tacaswell
Copy link
Member

I think the right long-term path here is to split the streamplot code in half along the 'integrate the lines' vs 'create the artists to draw the lines' axes. That way we can continue to ship a simple integrator and make it easy for users to bring their own integrator.

@tacaswell tacaswell added this to the 2.2 (next next feature release) milestone Oct 3, 2017
@jklymak
Copy link
Member

jklymak commented Oct 3, 2017

I think thats great as well. I'm sure there are lots of different ways to calculate streams, so a flexible way to do it would probably be welcome.

But in this case I think the OP wants to contour the streamfunction, which in a two-d flow is a field. But he would also like some helpful markers to indicate flow direction. Thats actually pretty different than what stream does. For instance, if you space streamlines evenly in stream function, the distance they are apart tells you the flow speed. I don't think stream does that. So I'd still say adding arrows or markers to a contour would be another useful addition.

@liangwang0734
Copy link
Author

What I need is nice 2d lines showing local velocity or magnetic field directions. Which of contour or streamplot is more useful depending on the data. Most of the time, contour suits my needs, since it creates nice smooth line plots. But

  1. contour does not have markers like arrows; clabel helps as jklymak suggested
  2. Sometimes the quantity spans over a huge range in small region, and the resulting field lines are condensed in this tiny region; this can be avoided by choosing the proper levels. In this case, streamplot is more useful since it only traces from uniformly distributed seeds (by default). An example is the dipole magnetic field of the Earth shown below. Left is contour using the psedo potential psi integrated from two components of the vector (Bx,By) using the calc_psi2d function I showed above; right is the streamplot using the two components directly. Since the magnitude of Bx and By increased very fast near the origin, the values of the psedo potential psi also increases very fast, and as a result, the default levels chosen by contour show up only near the origin.

@liangwang0734
Copy link
Author

liangwang0734 commented Oct 3, 2017

For the issue with discontinuous streamplot, I as a user still feel that it might be solved by completing the controlling parameters, particularly the tolerance of stopping distance. Is it possible to follow what vtk or mayavi do?

I am not very familiar with the source code nor a python expert, but I am willing to look into and play with streamplot.py if some help/suggestion is given.

@tacaswell
Copy link
Member

@jimgreen Sounds good! I suggest asking questions either here or the matplotlib-users@python.org mailing list.

@awaldm
Copy link

awaldm commented Oct 5, 2017

@jimgreen In case this helps: The streamline-breaking behavior appears to be caused by trajectory updating method inside the StreamMask:

def _update_trajectory(self, xm, ym):
        """Update current trajectory position in mask.
        If the new position has already been filled, raise `InvalidIndexError`.
        """
        if self._current_xy != (xm, ym):
            if self[ym, xm] == 0:
                self._traj.append((ym, xm))
                self._mask[ym, xm] = 1
                self._current_xy = (xm, ym)
            else:
                raise InvalidIndexError

In fact, a solution was proposed by @ketch in #8388 a while ago: don't raise the InvalidIndexError if the new position/cell is already marked in case the user asks for such a behavior. That issue apparently hasn't gained any traction since, but a solution along these lines should work.

@lzhadid
Copy link

lzhadid commented Oct 24, 2017

Hi!
Anyone knows how one can get the coordinates of the different streamlines ? I am using lines.get_segments(), but it is not very pactical, I am wondering if there is another way to do it.

@github-actions
Copy link

This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

@github-actions github-actions bot added the status: inactive Marked by the “Stale” Github Action label Apr 19, 2023
@tacaswell tacaswell added the Difficulty: Hard https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues label Apr 19, 2023
@tacaswell
Copy link
Member

draw the lines' axes. That way we can continue to ship a simple integrator and make it easy for users to bring their own integrator.

This continues to be the right solution, and is well aligned with the data-prototype work.

Part of me wants to label this is a "good first issue" as it is a very constrained part of the code base, but there will be API design involved so probably not.

@github-actions github-actions bot removed the status: inactive Marked by the “Stale” Github Action label Apr 20, 2023
Copy link

This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

@github-actions github-actions bot added the status: inactive Marked by the “Stale” Github Action label May 24, 2024
@jklymak jklymak added keep Items to be ignored by the “Stale” Github Action and removed status: inactive Marked by the “Stale” Github Action labels May 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Difficulty: Hard https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues keep Items to be ignored by the “Stale” Github Action
Projects
None yet
Development

No branches or pull requests

5 participants