ondrolexa / apsg

Structural geology package for Python
https://apsg.readthedocs.io
Other
102 stars 27 forks source link

Rose Diagram with separated Shapes in PDF method. #34

Closed NimaDolatabadi closed 1 year ago

NimaDolatabadi commented 1 year ago

this is my code that plots normal Rose Diagram using PDF method:

import pandas as pd

from apsg import *
from apsg.feature import Vector2Set as vec2set
from apsg.helpers._notation import *
from apsg.plotting._roseplot import *

##### ROSE DIAGRAM ######
# read data from CSV file
df = pd.read_csv('../test-stereonet-anticline1.csv')

# create a list of 2D vectors from the data
vectors2 = [vec2((sind(x - 90) * cosd(y)), (cosd(x + 90) * cosd(y))) for x, y in zip(df['DipD'], df['Dip'])]

# create a Vector2Set object from the list of vectors
vs1 = vec2set(vectors2)

p = RosePlot(grid=True, title='Test Rose Diagram',
             bins=36, axial=True,
             density=True, kappa=250,
             scaled=False, ticks=True,
             arrowness=0.95, rwidth=1,
             pdf_res=1000, cmap="jet")

p.pdf(vs1, fc='White', ec='Blue', ls="-", lw=1, legend=True)
p.show()

the output is like the first photo that is drawn in Blue Rose_diagram1

and a second code that does plot each shape individually using this code:

import pandas as pd
from apsg import *
from apsg.feature import Vector2Set as vec2set
from apsg.helpers._notation import *
from apsg.plotting._roseplot import *
from sklearn.cluster import KMeans

##### ROSE DIAGRAM ######

# read data from CSV file
df = pd.read_csv('../test-stereonet-anticline1.csv')

# Add k-means clustering
clust = 5
kmeans = KMeans(n_clusters=clust, n_init="auto", random_state=0)
kmeans.fit(df)
centers = kmeans.cluster_centers_
SD = [(centers[i][0], centers[i][1]) for i in range(clust)]
colors = ['red', 'green', 'blue', 'orange', 'purple']

p = RosePlot(grid=True, title='Test Rose Diagram',
             bins=36, axial=True,
             density=True, kappa=250,
             scaled=False, ticks=False,
             arrowness=0, rwidth=1,
             pdf_res=1000)

for i, center in enumerate(SD):
    vectors = []
    vector2 = [vec2((sind(center[0] - 90) * cosd(center[1])), (cosd(center[0] + 90) * cosd(center[1])))]
    vectors.extend(vector2)
    vs = vec2set(vectors)
    p.pdf(vs, fc='White', ec=colors[i], ls="-", lw=1, label=f'Cluster {i+1}')

p.show() 

and the output is the second photo that has different colors: Rose_diagram

Here is the Issuse

I want those shapes completely separated so that i can set each one a new color meanwhile i want them to be scaled just like the first one.

and Idea on how to integrate this?

My input data is some folded beddings in righ hand rule format (ignore the header please) and it's it attached as well.

test-stereonet-anticline1.csv

Regards Nima

ondrolexa commented 1 year ago

In your second example you plotting pdf of vector set with just single vector. If you want to plot pdf of individual clusters you should select all data belonging to that cluster. Something like:

for i in range(clust):
    sel = df[kmeans.labels_ == i]
    vectors2 = [vec2((sind(x - 90) * cosd(y)), (cosd(x + 90) * cosd(y))) for x, y in zip(sel['DipD'], sel['Dip'])]
    vs2 = vec2set(vectors2)
    p.bar(vs2, fc='White', ec=colors[i], ls="-", lw=1, label=f'Cluster {i+1}')

Anyway,for each group the values of densities will be different as is first example as number of samples is different. Only possibility would be to implement some weighting factor, which allows user to weight individual pdfs...

I can try to do it....

ondrolexa commented 1 year ago

Using latest master version, you can use weight kwarg...

from apsg import *
from apsg.helpers import sind, cosd
from sklearn.cluster import KMeans

##### ROSE DIAGRAM ######

# read data from CSV file
df = pd.read_csv('../test-stereonet-anticline1.csv')

# Add k-means clustering
clust = 5
kmeans = KMeans(n_clusters=clust, n_init="auto", random_state=0)
kmeans.fit(df)
centers = kmeans.cluster_centers_
SD = [(centers[i][0], centers[i][1]) for i in range(clust)]
colors = ['red', 'green', 'blue', 'orange', 'purple']

p = RosePlot(title='Test Rose Diagram', pdf_res=1000, tight_layout=True)

for i in range(clust):
    sel = df[kmeans.labels_ == i]
    vectors2 = [vec2((sind(x - 90) * cosd(y)), (cosd(x + 90) * cosd(y))) for x, y in zip(sel['DipD'], sel['Dip'])]
    vs2 = vec2set(vectors2, name=f'Cluster {i+1}')
    p.pdf(vs2, fc='White', ec=colors[i], lw=1, legend=True, weight=len(vs2)/len(df))

p.show()

separated

NimaDolatabadi commented 1 year ago

Hello again. I was begining to getting no answer. it is a great pleasure of your help within the Plot. It really helped a lot. Regards

NimaDolatabadi commented 7 months ago

I have another question about this issue, i believe that rose diagram reads the data as vector2, I just created this method to get it in 2d vector: vectors2 = [vec2((sind(x - 90) * cosd(y)), (cosd(x + 90) * cosd(y))) for x, y in zip(sel['DipD'], sel['Dip'])] I think it is wrong because I am plotting rose diagram only for dip directions there is dip usage in this code. do you have any better idea on this one? Regards

ondrolexa commented 7 months ago

If you want to create unit length Vector2 you can use just a single argument, e.g.: v = vec2(30). Or, you can create Vector2Set directly from the array as: vs = vec2set.from_direction(array) So in your code it will be

for i in range(clust):
    sel = df[kmeans.labels_ == i]
    vs2 = vec2set.from_direction(sel['DipD'], name=f'Cluster {i+1}')
    p.pdf(vs2, fc='White', ec=colors[i], lw=1, legend=True, weight=len(vs2)/len(df))