岁吢

文章 评论 浏览 30

岁吢 2025-02-17 01:19:02

只需使用MemoryStream而不是指向文件并以后将其转换为字符串。

public string GetLogs()
{
    // use MemoryStream instead of file
    using (var ms = new MemoryStream())
    using (var writer = new StreamWriter(ms))
    {
        // write everything
        ...

        // ensure write is finished
        writer.Flush();

        // convert memory stream to string
        return Encoding.UTF8.GetString(ms.ToArray());
    }
}

PS,但请注意Mohitganorkar-Mt所写的内容。

Just use MemoryStream instead of pointing to file and convert it to string later.

public string GetLogs()
{
    // use MemoryStream instead of file
    using (var ms = new MemoryStream())
    using (var writer = new StreamWriter(ms))
    {
        // write everything
        ...

        // ensure write is finished
        writer.Flush();

        // convert memory stream to string
        return Encoding.UTF8.GetString(ms.ToArray());
    }
}

P.S. But pay attention to what MohitGanorkar-MT wrote.

如何在要附加到电子邮件的内存中编写CSV?

岁吢 2025-02-16 11:03:18

强制性 np.einsum 基准

def banded_matrix_einsum(M):
    return np.einsum('ij, kl-> ikjl',
              np.eye(M)*(1 + np.cos(np.linspace(0, 2 * np.pi, M))),
              np.array([[1, 1], [1, -1]])).reshape(2*M, 2*M)

banded_matrix_einsum(4)

输出

array([[ 2. ,  2. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ],
       [ 2. , -2. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ],
       [ 0. ,  0. ,  0.5,  0.5,  0. ,  0. ,  0. ,  0. ],
       [ 0. ,  0. ,  0.5, -0.5,  0. ,  0. ,  0. ,  0. ],
       [ 0. ,  0. ,  0. ,  0. ,  0.5,  0.5,  0. ,  0. ],
       [ 0. ,  0. ,  0. ,  0. ,  0.5, -0.5,  0. ,  0. ],
       [ 0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  2. ,  2. ],
       [ 0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  2. , -2. ]])

基准基准结果

”

import perfplot

perfplot.show(
    setup = lambda M: M,
    kernels = [banded_matrix_einsum, banded_matrix_scipy, banded_matrix],
    n_range = [50, 100, 150, 200, 250, 300],
    logx = False
)

scipy.linalg.block_diag vs vs np.einsum np.einsum 详细信息

perfplot.show(
    setup = lambda M: M,
    kernels = [banded_matrix_einsum, banded_matrix_scipy],
    n_range = [50, 100, 150, 200, 250, 300, 350, 400],
    logx = False
)

The obligatory np.einsum benchmark

def banded_matrix_einsum(M):
    return np.einsum('ij, kl-> ikjl',
              np.eye(M)*(1 + np.cos(np.linspace(0, 2 * np.pi, M))),
              np.array([[1, 1], [1, -1]])).reshape(2*M, 2*M)

banded_matrix_einsum(4)

Output

array([[ 2. ,  2. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ],
       [ 2. , -2. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ],
       [ 0. ,  0. ,  0.5,  0.5,  0. ,  0. ,  0. ,  0. ],
       [ 0. ,  0. ,  0.5, -0.5,  0. ,  0. ,  0. ,  0. ],
       [ 0. ,  0. ,  0. ,  0. ,  0.5,  0.5,  0. ,  0. ],
       [ 0. ,  0. ,  0. ,  0. ,  0.5, -0.5,  0. ,  0. ],
       [ 0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  2. ,  2. ],
       [ 0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  2. , -2. ]])

Benchmark results

vs all

import perfplot

perfplot.show(
    setup = lambda M: M,
    kernels = [banded_matrix_einsum, banded_matrix_scipy, banded_matrix],
    n_range = [50, 100, 150, 200, 250, 300],
    logx = False
)

scipy.linalg.block_diag vs np.einsum details

scipy vs einsum

perfplot.show(
    setup = lambda M: M,
    kernels = [banded_matrix_einsum, banded_matrix_scipy],
    n_range = [50, 100, 150, 200, 250, 300, 350, 400],
    logx = False
)

创建频带(或带子)矩阵的有效方法

岁吢 2025-02-16 08:20:32

只需从项目中删除.ESLINTRC和任何其他ESLINT配置文件(如果有)。

另外,请检查您的 package.json 并删除所有ESLINT软件包,然后在项目上进行 npm install

If you are using vscode, you can disable it with a simple setting

Just delete .eslintrc and any other eslint config files, if any, from the project.

Also, check your package.json and delete all eslint packages and do npm install on your project.

If you are using vscode, you can disable it with a simple setting.

如何从项目中完全删除ESLINT

岁吢 2025-02-16 07:20:57

那是因为您需要将溢出设置:scroll 到Div。否则,滚动道具将无法正常工作。

但是请记住,使用上面的解决方案会导致不必要的额外滚动条。
因此,您可以尝试一下:

  const [background, setBackground] = React.useState(false);

  React.useEffect(() => {
    window.addEventListener("scroll", (e) => setBackground(true));

    return () => {
      window.removeEventListener("scroll", (e) => setBackground(false));
    };
  }, [background]);

That's because you need to set overflow:scroll to the div. Otherwise the onScroll prop won't work.

But remember that using the solution above will render unwanted extra scrollbars.
So you can try this instead:

  const [background, setBackground] = React.useState(false);

  React.useEffect(() => {
    window.addEventListener("scroll", (e) => setBackground(true));

    return () => {
      window.removeEventListener("scroll", (e) => setBackground(false));
    };
  }, [background]);

滚动ReactJS时如何更改状态?

岁吢 2025-02-16 01:36:38

由于您的 int dateTime 属性未标记为无效(使用 sign -eg int?) - 他们默认情况下,被视为必需。它仅应用于值类型( dateTime structs 或原语的 int )。您可以阅读更多

Since your int and DateTime properties are not marked as nullable (with ? sign - e.g. int?) - they are considered as Required by default. It is applied only to value types (structs as DateTime or primitives as int). You can read more here

某些类型的EF核心脚手架缺失[必需]

岁吢 2025-02-15 14:34:01

为了使功能模型具有分类层和回归层,您可以如下更改模型。请注意,有多种方法可以实现这一目标,这就是其中之一。

import tensorflow as tf
from tensorflow import keras 

prev_model = keras.applications.EfficientNetV2B0(
    input_tensor=keras.Input(shape=(224, 224, 3)),
    include_top=False
)

接下来,我们将写下我们的预期头层,如下所示。

neck_branch = keras.Sequential(
    [
        # we can add more layers i.e. batch norm, etc.
        keras.layers.GlobalAveragePooling2D()
    ],
    name='neck_head'
)

classification_head = keras.Sequential(
    [
        keras.layers.Dense(10, activation='softmax')
    ],
    name='classification_head'
)

regression_head = keras.Sequential(
    [
        keras.layers.Dense(1, activation=None)
    ],
    name='regression_head'
)

现在,我们可以构建所需的模型。

x = neck_branch(prev_model.output)
output_a = classification_head(x)
output_b = regression_head(x)
final_model = keras.Model(prev_model.inputs, [output_a, output_b])

进行测试

keras.utils.plot_model(final_model, expand_nested=True)
# OK

final_model(tf.ones(shape=(1, 224, 224, 3)))
# OK

更新

根据您的评论

如果从 h5 文件导入以前的模型,您将如何解决问题,因为我无法声明不包括上层?

如果我了解您的查询,则具有顶层的保存模型(以 .h5 格式)。在这种情况下,您没有 include_top 参数来排除顶级分支。因此,您可以做的是首先删除保存模型的顶部分支。这是这样,

# a saved model with top layers
prev_model = keras.models.load_model('model.h5')

prev_model_with_top_remove = keras.Model(
     prev_model.input ,
     prev_model.layers[-4].output
)
prev_model_with_top_remove.summary()

prev_model.layers [-4] .output 将删除顶部分支。最后,您将提供类似的输出,因为我们可以使用 include_top = true 获得类似的输出。检查模型摘要以进行视觉检查。

To enable a functional model to have a classification layer and a regression layer, you can change the model as follows. Note, there are various ways to achieve this, and this is one of them.

import tensorflow as tf
from tensorflow import keras 

prev_model = keras.applications.EfficientNetV2B0(
    input_tensor=keras.Input(shape=(224, 224, 3)),
    include_top=False
)

Next, we will write our expected head layers, shown below.

neck_branch = keras.Sequential(
    [
        # we can add more layers i.e. batch norm, etc.
        keras.layers.GlobalAveragePooling2D()
    ],
    name='neck_head'
)

classification_head = keras.Sequential(
    [
        keras.layers.Dense(10, activation='softmax')
    ],
    name='classification_head'
)

regression_head = keras.Sequential(
    [
        keras.layers.Dense(1, activation=None)
    ],
    name='regression_head'
)

Now, we can build the desired model.

x = neck_branch(prev_model.output)
output_a = classification_head(x)
output_b = regression_head(x)
final_model = keras.Model(prev_model.inputs, [output_a, output_b])

Test

keras.utils.plot_model(final_model, expand_nested=True)
# OK

final_model(tf.ones(shape=(1, 224, 224, 3)))
# OK

Update

Based on your comments,

how you would tackle the problem if the previous model was imported from a h5 file since there I cannot declare the top layer not to be included?

If I understand your query, you have a saved model (in .h5 format) with top layers. In that case, you don't have include_top params to exclude the top branch. So, what you can do is remove the top branch of your saved model first. Here is how,

# a saved model with top layers
prev_model = keras.models.load_model('model.h5')

prev_model_with_top_remove = keras.Model(
     prev_model.input ,
     prev_model.layers[-4].output
)
prev_model_with_top_remove.summary()

This prev_model.layers[-4].output will remove the top branch. In the end, you will give similar output as we can get with include_top=True. Check the model summary to visually inspect.

如何在Keras中编辑功能模型?

岁吢 2025-02-15 11:20:52

这取决于实体的映射方式。

这是我的尝试:

CriteriaBuilder criteriaBuilder = getCurrentSession().getCriteriaBuilder();
CriteriaQuery<N> criteria = criteriaBuilder.createQuery(N.class);
Root<N> news = criteria.from(N.class);
Join<Object, Object> nsJoin = news.join( "ns", JoinType.LEFT );
Join<Object, Object> nodeJoin = nsJoin.join( "node" );
query.where( builder.and(
        builder.isTrue( news.get( "public" ) ),
        builder.or( nsJoin.isNull(), nodeJoin.get("id" ).in( 25, 1307114 ) )
) );

如果您向我展示实体,我可以给您更好的答案

It depends how the entities are mapped.

Here's my attempt:

CriteriaBuilder criteriaBuilder = getCurrentSession().getCriteriaBuilder();
CriteriaQuery<N> criteria = criteriaBuilder.createQuery(N.class);
Root<N> news = criteria.from(N.class);
Join<Object, Object> nsJoin = news.join( "ns", JoinType.LEFT );
Join<Object, Object> nodeJoin = nsJoin.join( "node" );
query.where( builder.and(
        builder.isTrue( news.get( "public" ) ),
        builder.or( nsJoin.isNull(), nodeJoin.get("id" ).in( 25, 1307114 ) )
) );

I can give you better answer if you show me the entities

在标准查询中转换SQL查询

岁吢 2025-02-15 07:31:09

对于我们使用JumpCloud和Rundeck的我们来说,上一个配置无效。

我们必须将这个

multiauth {
    com.dtolabs.rundeck.jetty.jaas.JettyCachingLdapLoginModule sufficient
        debug="true"
        contextFactory="com.sun.jndi.ldap.LdapCtxFactory"
        providerUrl="xxxxxxx"
        bindDn="uid=xxxxx,ou=Users,o=xxxxxx,dc=jumpcloud,dc=com"
        bindPassword="xxxxxxx"
        authenticationMethod="simple"
        forceBindingLogin="true"
        userBaseDn="ou=Users,o=xxxxxxx,dc=jumpcloud,dc=com"
        userRdnAttribute="uid"
        userIdAttribute="uid"
        userPasswordAttribute="userPassword"
        userObjectClass="inetOrgPerson"
        userLastNameAttribute="sn"
        userFirstNameAttribute="givenName"
        userEmailAttribute="mail"
        roleBaseDn="ou=Users,o=xxxxxx,dc=jumpcloud,dc=com"
        roleNameAttribute="cn"
        roleMemberAttribute="member"
        roleObjectClass="groupOfNames"
        rolePrefix=""
        cacheDurationMillis="300000"
        reportStatistics="true"
        timeoutRead="10000"
        timeoutConnect="20000"
        nestedGroups="false";

    org.eclipse.jetty.jaas.spi.PropertyFileLoginModule required
        debug="true"
        file="/etc/rundeck/realm.properties";
};

用户团体在Rundeck享受中也工作

For us with Jumpcloud and rundeck the previous config didn't work.

We have to put this one

multiauth {
    com.dtolabs.rundeck.jetty.jaas.JettyCachingLdapLoginModule sufficient
        debug="true"
        contextFactory="com.sun.jndi.ldap.LdapCtxFactory"
        providerUrl="xxxxxxx"
        bindDn="uid=xxxxx,ou=Users,o=xxxxxx,dc=jumpcloud,dc=com"
        bindPassword="xxxxxxx"
        authenticationMethod="simple"
        forceBindingLogin="true"
        userBaseDn="ou=Users,o=xxxxxxx,dc=jumpcloud,dc=com"
        userRdnAttribute="uid"
        userIdAttribute="uid"
        userPasswordAttribute="userPassword"
        userObjectClass="inetOrgPerson"
        userLastNameAttribute="sn"
        userFirstNameAttribute="givenName"
        userEmailAttribute="mail"
        roleBaseDn="ou=Users,o=xxxxxx,dc=jumpcloud,dc=com"
        roleNameAttribute="cn"
        roleMemberAttribute="member"
        roleObjectClass="groupOfNames"
        rolePrefix=""
        cacheDurationMillis="300000"
        reportStatistics="true"
        timeoutRead="10000"
        timeoutConnect="20000"
        nestedGroups="false";

    org.eclipse.jetty.jaas.spi.PropertyFileLoginModule required
        debug="true"
        file="/etc/rundeck/realm.properties";
};

The users groups are working as well on the rundeck

Enjoy !

如何从Spring Boot中的传入请求中检查角色

岁吢 2025-02-15 01:14:43

如果您需要变量“ most_common”,“ second_mast”:

您可以使用: mutate &amp; str_count 在字符串中计数每个字符


library dplyr

#range
r <- 1:5 |> as.character()

d |> 
  group_by(id) |> 
  mutate(most_common = which(unique(str_count(seq, r)) == last(sort(str_count(seq, r)))),
         second_most_common = first(which(str_count(seq, r) == nth(sort(str_count(seq, r)), length(r) - 1))),
         third_most_common = first(which(str_count(seq, r) == nth(sort(str_count(seq, r)), length(r) - 2))))
id seq                                                                                 most_common second_most_com… third_most_comm…
   <int> <chr>                                                                                     <int>            <int>            <int>
 1     1 3451122353321532415512241532113224441251251254542314534141431523132515542431525553…           1                5                2
 2     2 1432431521432121553144243252433424314222143112242423421524144222151123234314255321…           2                1                4
 3     3 4232245131422525453443332555312143535325221555344453323342533222344112134311342335…           3                2                4
 4     4 4252525524252335331144111244343534224454131341553141342131354215143133213214314241…           1                3                4
 5     5 2223513245222513345115334422121115412343225125312335414233115453235322543311352331…           3                2                1
 6     6 3244331444151221411123513334135553324122122233134315145451545423111325253225325141…           1                1                2
 7     7 4353332532552141211553131123521145214552211231144155553152131124221522333222343355…           5                1                3
 8     8 1432215433134223221222143432454314232514255344213444342235252213324245413213554121…           2                4                3
 9     9 2335142431432434123121254343455134511124323335211514354553145531115232541551252421…           1                1                3
10    10 1552245312213342315524134513123511112311314321112334533252141242212345432435421535…           1                3                2

If you need the variables "Most_common", "second_most":

You can use: mutate & str_count which counts each character in a string


library dplyr

#range
r <- 1:5 |> as.character()

d |> 
  group_by(id) |> 
  mutate(most_common = which(unique(str_count(seq, r)) == last(sort(str_count(seq, r)))),
         second_most_common = first(which(str_count(seq, r) == nth(sort(str_count(seq, r)), length(r) - 1))),
         third_most_common = first(which(str_count(seq, r) == nth(sort(str_count(seq, r)), length(r) - 2))))
id seq                                                                                 most_common second_most_com… third_most_comm…
   <int> <chr>                                                                                     <int>            <int>            <int>
 1     1 3451122353321532415512241532113224441251251254542314534141431523132515542431525553…           1                5                2
 2     2 1432431521432121553144243252433424314222143112242423421524144222151123234314255321…           2                1                4
 3     3 4232245131422525453443332555312143535325221555344453323342533222344112134311342335…           3                2                4
 4     4 4252525524252335331144111244343534224454131341553141342131354215143133213214314241…           1                3                4
 5     5 2223513245222513345115334422121115412343225125312335414233115453235322543311352331…           3                2                1
 6     6 3244331444151221411123513334135553324122122233134315145451545423111325253225325141…           1                1                2
 7     7 4353332532552141211553131123521145214552211231144155553152131124221522333222343355…           5                1                3
 8     8 1432215433134223221222143432454314232514255344213444342235252213324245413213554121…           2                4                3
 9     9 2335142431432434123121254343455134511124323335211514354553145531115232541551252421…           1                1                3
10    10 1552245312213342315524134513123511112311314321112334533252141242212345432435421535…           1                3                2

每一行的第二大元素

岁吢 2025-02-15 00:26:23

由于ID永远不会更改(您正在使用UUID初始化它),并且您的== func仅在查看每个卡的ID以确定平等,因此Foreach将永远不会看到其他属性的任何更改。我不得不写下== func,它对我有用。

static func == (lhs: MemoryGame.Card, rhs: MemoryGame.Card) -> Bool {
   return lhs.isFaceUp == rhs.isFaceUp &&
   lhs.isMatched == rhs.isMatched &&
   lhs.content == rhs.content &&
   lhs.id == rhs.id
}

Since the id never changes (you are initializing it with a UUID) and your == func is only looking at the id of each card to determine equality, the ForEach will never see any change in the other attributes. I had to write the == func as below, and it worked for me.

static func == (lhs: MemoryGame.Card, rhs: MemoryGame.Card) -> Bool {
   return lhs.isFaceUp == rhs.isFaceUp &&
   lhs.isMatched == rhs.isMatched &&
   lhs.content == rhs.content &&
   lhs.id == rhs.id
}

当给定数据符合等式时,为什么SwiftUi foreach不更新?

岁吢 2025-02-14 19:33:44

您可以尝试根据您的测试方法嘲笑地图方法(例如获取或放置)。例如。

Mockito.when(map.get("KEY")).thenReturn("objectYouWantToReturn");

You can try mocking the Map methods like get or put based on what you are testing. For eg.

Mockito.when(map.get("KEY")).thenReturn("objectYouWantToReturn");

我如何模拟组件地图

岁吢 2025-02-14 10:48:57

使用期间的月份(和一年)信息,并应用 cumsum

year_col = pd.to_datetime(df_2['Period']).dt.year
month_col = pd.to_datetime(df_2['Period']).dt.month
df_2['count'] = df_2.groupby([year_col, month_col])['size'].cumsum()

结果:

        Period  Code  size  count
0   2022-04-29     A     2      2
1   2022-04-30     A     1      3
2   2022-05-01     A     3      3

Use groupby on the month (and year to be safe) information from Period and apply cumsum:

year_col = pd.to_datetime(df_2['Period']).dt.year
month_col = pd.to_datetime(df_2['Period']).dt.month
df_2['count'] = df_2.groupby([year_col, month_col])['size'].cumsum()

Result:

        Period  Code  size  count
0   2022-04-29     A     2      2
1   2022-04-30     A     1      3
2   2022-05-01     A     3      3

基于月份的列计数

岁吢 2025-02-14 07:22:44

这是我的解决方案

SELECT *
FROM (
    SELECT
        ROW_NUMBER() OVER (PARTITION BY CustomerId ORDER BY OrderDate desc) OrderNumber
        , *
    FROM #Order 
) EnumeratedOrders
WHERE OrderNumber <= 2

,详细说明了 row_number() function 此处

This is my solution

SELECT *
FROM (
    SELECT
        ROW_NUMBER() OVER (PARTITION BY CustomerId ORDER BY OrderDate desc) OrderNumber
        , *
    FROM #Order 
) EnumeratedOrders
WHERE OrderNumber <= 2

A detailed explanation about the ROW_NUMBER() function here

我如何为每个客户获得前2个订单

岁吢 2025-02-14 05:38:11

问题没有在问题中提到,但是代码使用 dnne package 创建一个导出的本地库所有标记的功能都带有属性 UnmanagedCallersonly

dnne package 需要将3个文件一起分配:

  1. 托管汇编: testLibrary1。 dll );
  2. 本机汇编( testLibrary1ne.dll );
  3. testlibrary1.runtimeconfig.json

捕获的是,应将托管汇编( testLibrary1.dll )和本机汇编( testLibrary1ne.dll )一起分发。不仅如此,还包括 testLibrary1.runtimeconfig.json 。这是因为本机组装在内部调用托管组件,以便所有文件都应在同一路径上。

dnne在Windows上需要 - Runtime flag或msbuild runtimeidendifier 要将属性设置为目标 win-x86 win-x64 ,又项目应该相同。检查

另外,使用 testLibrary1.dll 的项目应引用该项目。如下:

  <ItemGroup>
    <ProjectReference Include="..\TestLibrary1\TestLibrary1.csproj" />
  </ItemGroup>

C#项目配置文件的更改( testLibrary1.csproj )在下面评论。 Enabledynamicloading 应为 true 生成 testLibrary1.runtimeconfig.json 。和DNNE需要 PlatformTarget RuntimeIdendifier 分别定义为 x64 win-x64

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <RootNamespace>c_sharp</RootNamespace>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>

    <!-- Include the line below to generate the runtimeconfig.json -->
    <EnableDynamicLoading>true</EnableDynamicLoading>

    <!-- DNNE package asks to include those 2 also -->
    <PlatformTarget>x64</PlatformTarget>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>

  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="DNNE" Version="1.0.32" />
  </ItemGroup>

</Project>

It's not mentioned in the question but the code uses the DNNE package to create a native library that exports all marked functions with the attribute UnmanagedCallersOnly.

The DNNE package needs that 3 files be distributed together:

  1. The managed assembly (TestLibrary1.dll);
  2. The native assembly (TestLibrary1NE.dll);
  3. And the TestLibrary1.runtimeconfig.json.

The catch is that both managed assembly (TestLibrary1.dll) and native assembly (TestLibrary1NE.dll) should be distributed together. And not only that but also the TestLibrary1.runtimeconfig.json. This is because the native assembly calls the managed assembly internally so all the files should be on the same path.

DNNE needs on Windows the --runtime flag or MSBuild RuntimeIdentifier property to be set as target win-x86 or win-x64, and both projects should be the same. Check the 3rd bullet here in the docs.

Also, the project that uses TestLibrary1.dll should reference the project. Something like the following:

  <ItemGroup>
    <ProjectReference Include="..\TestLibrary1\TestLibrary1.csproj" />
  </ItemGroup>

The changes to the C# project configuration file (TestLibrary1.csproj) are commented on below. EnableDynamicLoading should be true to generate the TestLibrary1.runtimeconfig.json. And DNNE needs both PlatformTarget and RuntimeIdentifier to be defined as x64 and win-x64 respectively.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <RootNamespace>c_sharp</RootNamespace>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>

    <!-- Include the line below to generate the runtimeconfig.json -->
    <EnableDynamicLoading>true</EnableDynamicLoading>

    <!-- DNNE package asks to include those 2 also -->
    <PlatformTarget>x64</PlatformTarget>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>

  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="DNNE" Version="1.0.32" />
  </ItemGroup>

</Project>

当调用来自C#.NET Core DLL到VB的未管理重新启用函数时错误

岁吢 2025-02-13 16:49:29

解决方案

我第一个解决此问题的解决方法是为我的链路路径的预期界限(开始和结束)定义剪辑路径。这样,伪像只是简单地剪掉的,看不到问题:

<defs>
    <clipPath id="cut-off-link-{i}">
        <rect
            y={link.source.x1 - nodeHeight / 2}
            width="100%"
            height={link.target.x0 - link.source.x1 + nodeHeight}
        />
    </clipPath>
</defs>
<path
    d={d3shape.linkVertical()(link)}
    fill="none"
    stroke='#333'
    stroke-width={link.width}
    stroke-linecap="square"
    clip-path="url(#cut-off-link-{i})"
/>

此代码与上下文有点不合时宜,但我将其包括在内,只是为了给出解决方案的想法。它来自带有垂直Sankey的Svelte应用程序,我简化了代码。

这个解决方法实际上效果很好,但感觉很不错。我想要一个“适当的”解决方案。

@herrstrietzel提出的解决方案( https://stackoverflow.com/a/a/72588392/22230045 )似乎是技术上的更正确的解决方法,但我无法摆脱它仍然感觉像是一个骇人听闻的解决方法。


解决方案

在寻找解决方案时,我遇到了这篇博客文章: https:https:https: //observablehq.com/@enjalot/weird-sankey-links

默认D3.SanKeylinkHorizo​​ntal如果节点太近,宽度是大

“

当问题上的博客文章关注外观略有不同,我敢肯定这是完全相同的问题我正在经历。

从某种意义上说,我觉得这里的根本问题是对路径元素的滥用。设置填充到并增加绘制线路绘制线路的情况下,当线短时,似乎无法正常工作。

博客文章建议改为绘制自定义的Bézier曲线。
这消除了对中风属性的需求,相反,我们可以使用普通填充物。这对我来说是一个适当的解决方案。让我们看一下代码。

在这个问题之前,我并没有真正看一下Sankey图的图形侧。
在尝试理解博客文章中提出的解决方案(我需要更改代码以垂直而不是水平工作)时,我努力地完整地绘制了坐标是指的是什么。
D3文档对此并没有真正的帮助。
在这里,我为自己制作的信息图形:

“

博客文章中的代码使用略有不同的坐标命名。我对此进行了调整,添加了一些评论,并试图简化它。

function sankeyLinkPath(link) {
    /**
     * This function is a drop in replacement for d3.sankeyLinkHorizontal().
     * Except any accessors/options.
     */
    // Start and end of the link
    let sx1 = link.source.x1;
    let tx0 = link.target.x0 + 1;

    // All four outer corners of the link
    // where e.g. lsy0 is the upper corner of the link on the source side
    let lsy0 = link.y0 - link.width / 2;
    let lsy1 = link.y0 + link.width / 2;
    let lty0 = link.y1 - link.width / 2;
    let lty1 = link.y1 + link.width / 2;

    // Center (x) of the link
    let lcx = sx1 + (tx0 - sx1) / 2;

    // Define outline of link as path
    let path = d3.path();
    path.moveTo(sx1, lsy0);
    path.bezierCurveTo(lcx, lsy0, lcx, lty0, tx0, lty0);
    path.lineTo(tx0, lty1);
    path.bezierCurveTo(lcx, lty1, lcx, lsy1, sx1, lsy1);
    path.lineTo(sx1, lsy0);
    return path.toString();
}

这样做的是,它绘制了链接轮廓的路径。

将我的代码简化为:

<path
    d={sankeyLinkPath(link)}
    fill='#333'
/>

调整Sankey的垂直绘图

最后,我调整了代码以垂直而不是水平工作:

function sankeyLinkPath(link) {
    /**
     * This function is a drop in replacement for d3.sankeyLinkVertical().
     * Except any accessors/options.
     */
    // Start and end of the link
    let sy1 = link.source.x1;
    let ty0 = link.target.x0 + 1;

    // All four outer corners of the link
    // where e.g. lsx0 is the right corner of the link on the source side
    let lsx0 = link.y0 - (link.width / 2) * linkWidth;
    let lsx1 = link.y0 + (link.width / 2) * linkWidth;
    let ltx0 = link.y1 - (link.width / 2) * linkWidth;
    let ltx1 = link.y1 + (link.width / 2) * linkWidth;

    // Center (y) of the link
    let lcy = sy1 + (ty0 - sy1) / 2;

    // Define outline of link as path
    let path = d3.path();
    path.moveTo(lsx0, sy1);
    path.bezierCurveTo(lsx0, lcy, ltx0, lcy, ltx0, ty0);
    path.lineTo(ltx1, ty0);
    path.bezierCurveTo(ltx1, lcy, lsx1, lcy, lsx1, sy1);
    path.lineTo(lsx0, sy1);
    return path.toString();
}

现在可以产生这种绝对良好的工作桑基情节:

.opacity-40 {
    opacity: 0.4;
}
<div width="100%" height="100%">
    <svg width="648" height="384">
        <g class="sankey-links">
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M11.370422535211262,40C11.370422535211262,77.83333333333334,11.370422535211262,77.83333333333334,11.370422535211262,115.66666666666667L216.03802816901413,115.66666666666667C216.03802816901413,77.83333333333334,216.03802816901413,77.83333333333334,216.03802816901413,40L11.370422535211262,40"
                    fill="#0011ff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M5.47464788732394,154.66666666666669C5.47464788732394,249.83333333333334,5.47464788732394,249.83333333333334,5.47464788732394,345L104.01830985915494,345C104.01830985915494,249.83333333333334,104.01830985915494,249.83333333333334,104.01830985915494,154.66666666666669L5.47464788732394,154.66666666666669"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M318.26478873239444,40C318.26478873239444,192.5,312.9971830985916,192.5,312.9971830985916,345L403.9605633802817,345C403.9605633802817,192.5,409.22816901408453,192.5,409.22816901408453,40L318.26478873239444,40"
                    fill="#0011ff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M487.8718309859155,40C487.8718309859155,192.5,559.9845070422538,192.5,559.9845070422538,345L643.367605633803,345C643.367605633803,192.5,571.2549295774647,192.5,571.2549295774647,40L487.8718309859155,40"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M113.70422535211267,154.66666666666669C113.70422535211267,249.83333333333334,123.70422535211273,249.83333333333334,123.70422535211273,345L199.50704225352118,345C199.50704225352118,249.83333333333334,189.50704225352112,249.83333333333334,189.50704225352112,154.66666666666669L113.70422535211267,154.66666666666669"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M231.1985915492958,40C231.1985915492958,192.5,412.8042253521127,192.5,412.8042253521127,345L481.0267605633804,345C481.0267605633804,192.5,299.4211267605634,192.5,299.4211267605634,40L231.1985915492958,40"
                    fill="#0011ff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M417.22957746478875,40C417.22957746478875,77.83333333333334,413.3159790754746,77.83333333333334,413.3159790754746,115.66666666666667L466.37795090646057,115.66666666666667C466.37795090646057,77.83333333333334,470.2915492957747,77.83333333333334,470.2915492957747,40L417.22957746478875,40"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M577.9929577464789,40C577.9929577464789,192.5,486.92253521126764,192.5,486.92253521126764,345L524.8239436619718,345C524.8239436619718,192.5,615.894366197183,192.5,615.894366197183,40L577.9929577464789,40"
                    fill="#0011ff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M412.4737255543479,154.66666666666669C412.4737255543479,249.83333333333334,205.82394366197187,249.83333333333334,205.82394366197187,345L243.72535211267612,345C243.72535211267612,249.83333333333334,450.37513400505213,249.83333333333334,450.37513400505213,154.66666666666669L412.4737255543479,154.66666666666669"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M195.40281690140844,154.66666666666669C195.40281690140844,249.83333333333334,257.5154929577465,249.83333333333334,257.5154929577465,345L287.8366197183099,345C287.8366197183099,249.83333333333334,225.72394366197184,249.83333333333334,225.72394366197184,154.66666666666669L195.40281690140844,154.66666666666669"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M453.32302132899576,154.66666666666669C453.32302132899576,192.5,457.2918698867473,192.5,457.2918698867473,230.33333333333334L472.452433267029,230.33333333333334C472.452433267029,192.5,468.48358470927747,192.5,468.48358470927747,154.66666666666669L453.32302132899576,154.66666666666669"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M465.2932783374515,269.33333333333337C465.2932783374515,307.1666666666667,289.94225352112676,307.1666666666667,289.94225352112676,345L297.5225352112676,345C297.5225352112676,307.1666666666667,472.87356002759236,307.1666666666667,472.87356002759236,269.33333333333337L465.2932783374515,269.33333333333337"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M456.8707431261839,269.33333333333337C456.8707431261839,307.1666666666667,537.3507042253524,307.1666666666667,537.3507042253524,345L544.9309859154931,345C544.9309859154931,307.1666666666667,464.4510248163248,307.1666666666667,464.4510248163248,269.33333333333337L456.8707431261839,269.33333333333337"
                    fill="#00bbff"
                ></path>
            </g>
        </g>
    </svg>
</div>

我对与SVGS和D3合作有了很多了解。我希望该解决方案将来对其他人有所帮助。

Workarounds

My first workaround to resolve this issue was to also define a clip path for the expected bounds (start and end) of my link path. This way the artifact is simply clipped and no issue is visible:

<defs>
    <clipPath id="cut-off-link-{i}">
        <rect
            y={link.source.x1 - nodeHeight / 2}
            width="100%"
            height={link.target.x0 - link.source.x1 + nodeHeight}
        />
    </clipPath>
</defs>
<path
    d={d3shape.linkVertical()(link)}
    fill="none"
    stroke='#333'
    stroke-width={link.width}
    stroke-linecap="square"
    clip-path="url(#cut-off-link-{i})"
/>

This code is a bit out of context but I included it just to give an idea of the solution. It's from a Svelte application with a vertical Sankey and I reduced the code for brevity.

This workaround actually works great but it feels so wrong. I wanted a "proper" solution.

The solution proposed by @herrstrietzel (https://stackoverflow.com/a/72588392/2230045) seems to be a technically more correct workaround but I can't shake off that it still feels like a hacky workaround.


Solution

While looking for solutions I came across this blog post: https://observablehq.com/@enjalot/weird-sankey-links

The default d3.sankeyLinkHorizontal tends to break down if the nodes are too close together and the width is to big

Sankey Link Failing

While the issue the blog post focuses on looks slightly different, I'm sure it's the exact same issue I'm experiencing.

In some sense, I feel like the underlying issue here is a misuse of the path element. Setting fill to none and increasing the stroke width to draw the line seems to not work properly when the line is shorter than the stroke width.

The blog post proposes to draw custom Bézier curves instead.
This removes the need for the stroke property and instead we can just use the normal fill. This feels like a proper solution to me. Let's look into the code.

Before this question I did not really look into the graphical side of Sankey diagrams.
While trying to understand the solution proposed in the blog post (I need to change the code to work vertically instead of horizontally), I struggled to fully graphs what coordinates are referring to what.
The d3 docs are not really helpful on that.
Here an info graphic I made for myself:

Sankey Diagram Coordinates

The code from the blog post uses a slightly different coordinate naming. I adapted this, added some comments and tried to simplify it.

function sankeyLinkPath(link) {
    /**
     * This function is a drop in replacement for d3.sankeyLinkHorizontal().
     * Except any accessors/options.
     */
    // Start and end of the link
    let sx1 = link.source.x1;
    let tx0 = link.target.x0 + 1;

    // All four outer corners of the link
    // where e.g. lsy0 is the upper corner of the link on the source side
    let lsy0 = link.y0 - link.width / 2;
    let lsy1 = link.y0 + link.width / 2;
    let lty0 = link.y1 - link.width / 2;
    let lty1 = link.y1 + link.width / 2;

    // Center (x) of the link
    let lcx = sx1 + (tx0 - sx1) / 2;

    // Define outline of link as path
    let path = d3.path();
    path.moveTo(sx1, lsy0);
    path.bezierCurveTo(lcx, lsy0, lcx, lty0, tx0, lty0);
    path.lineTo(tx0, lty1);
    path.bezierCurveTo(lcx, lty1, lcx, lsy1, sx1, lsy1);
    path.lineTo(sx1, lsy0);
    return path.toString();
}

What this does is, that it draws a path of the outline of the link.

Steps to draw outline of link.

Which reduces my code to:

<path
    d={sankeyLinkPath(link)}
    fill='#333'
/>

Adjust for Vertical Plotting of Sankey

Finally, I adjusted the code to work vertically instead of horizontally:

function sankeyLinkPath(link) {
    /**
     * This function is a drop in replacement for d3.sankeyLinkVertical().
     * Except any accessors/options.
     */
    // Start and end of the link
    let sy1 = link.source.x1;
    let ty0 = link.target.x0 + 1;

    // All four outer corners of the link
    // where e.g. lsx0 is the right corner of the link on the source side
    let lsx0 = link.y0 - (link.width / 2) * linkWidth;
    let lsx1 = link.y0 + (link.width / 2) * linkWidth;
    let ltx0 = link.y1 - (link.width / 2) * linkWidth;
    let ltx1 = link.y1 + (link.width / 2) * linkWidth;

    // Center (y) of the link
    let lcy = sy1 + (ty0 - sy1) / 2;

    // Define outline of link as path
    let path = d3.path();
    path.moveTo(lsx0, sy1);
    path.bezierCurveTo(lsx0, lcy, ltx0, lcy, ltx0, ty0);
    path.lineTo(ltx1, ty0);
    path.bezierCurveTo(ltx1, lcy, lsx1, lcy, lsx1, sy1);
    path.lineTo(lsx0, sy1);
    return path.toString();
}

Which now yields this absolutely fine working Sankey plot:

.opacity-40 {
    opacity: 0.4;
}
<div width="100%" height="100%">
    <svg width="648" height="384">
        <g class="sankey-links">
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M11.370422535211262,40C11.370422535211262,77.83333333333334,11.370422535211262,77.83333333333334,11.370422535211262,115.66666666666667L216.03802816901413,115.66666666666667C216.03802816901413,77.83333333333334,216.03802816901413,77.83333333333334,216.03802816901413,40L11.370422535211262,40"
                    fill="#0011ff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M5.47464788732394,154.66666666666669C5.47464788732394,249.83333333333334,5.47464788732394,249.83333333333334,5.47464788732394,345L104.01830985915494,345C104.01830985915494,249.83333333333334,104.01830985915494,249.83333333333334,104.01830985915494,154.66666666666669L5.47464788732394,154.66666666666669"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M318.26478873239444,40C318.26478873239444,192.5,312.9971830985916,192.5,312.9971830985916,345L403.9605633802817,345C403.9605633802817,192.5,409.22816901408453,192.5,409.22816901408453,40L318.26478873239444,40"
                    fill="#0011ff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M487.8718309859155,40C487.8718309859155,192.5,559.9845070422538,192.5,559.9845070422538,345L643.367605633803,345C643.367605633803,192.5,571.2549295774647,192.5,571.2549295774647,40L487.8718309859155,40"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M113.70422535211267,154.66666666666669C113.70422535211267,249.83333333333334,123.70422535211273,249.83333333333334,123.70422535211273,345L199.50704225352118,345C199.50704225352118,249.83333333333334,189.50704225352112,249.83333333333334,189.50704225352112,154.66666666666669L113.70422535211267,154.66666666666669"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M231.1985915492958,40C231.1985915492958,192.5,412.8042253521127,192.5,412.8042253521127,345L481.0267605633804,345C481.0267605633804,192.5,299.4211267605634,192.5,299.4211267605634,40L231.1985915492958,40"
                    fill="#0011ff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M417.22957746478875,40C417.22957746478875,77.83333333333334,413.3159790754746,77.83333333333334,413.3159790754746,115.66666666666667L466.37795090646057,115.66666666666667C466.37795090646057,77.83333333333334,470.2915492957747,77.83333333333334,470.2915492957747,40L417.22957746478875,40"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M577.9929577464789,40C577.9929577464789,192.5,486.92253521126764,192.5,486.92253521126764,345L524.8239436619718,345C524.8239436619718,192.5,615.894366197183,192.5,615.894366197183,40L577.9929577464789,40"
                    fill="#0011ff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M412.4737255543479,154.66666666666669C412.4737255543479,249.83333333333334,205.82394366197187,249.83333333333334,205.82394366197187,345L243.72535211267612,345C243.72535211267612,249.83333333333334,450.37513400505213,249.83333333333334,450.37513400505213,154.66666666666669L412.4737255543479,154.66666666666669"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M195.40281690140844,154.66666666666669C195.40281690140844,249.83333333333334,257.5154929577465,249.83333333333334,257.5154929577465,345L287.8366197183099,345C287.8366197183099,249.83333333333334,225.72394366197184,249.83333333333334,225.72394366197184,154.66666666666669L195.40281690140844,154.66666666666669"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M453.32302132899576,154.66666666666669C453.32302132899576,192.5,457.2918698867473,192.5,457.2918698867473,230.33333333333334L472.452433267029,230.33333333333334C472.452433267029,192.5,468.48358470927747,192.5,468.48358470927747,154.66666666666669L453.32302132899576,154.66666666666669"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M465.2932783374515,269.33333333333337C465.2932783374515,307.1666666666667,289.94225352112676,307.1666666666667,289.94225352112676,345L297.5225352112676,345C297.5225352112676,307.1666666666667,472.87356002759236,307.1666666666667,472.87356002759236,269.33333333333337L465.2932783374515,269.33333333333337"
                    fill="#00bbff"
                ></path>
            </g>
            <g class="sankey-link group">
                <path
                    class="opacity-40 group-hover:opacity-80"
                    d="M456.8707431261839,269.33333333333337C456.8707431261839,307.1666666666667,537.3507042253524,307.1666666666667,537.3507042253524,345L544.9309859154931,345C544.9309859154931,307.1666666666667,464.4510248163248,307.1666666666667,464.4510248163248,269.33333333333337L456.8707431261839,269.33333333333337"
                    fill="#00bbff"
                ></path>
            </g>
        </g>
    </svg>
</div>

I gained quite some insight into working with SVGs and d3 with this. I hope the solution helps someone else in the future.

如何在SANKEY与D3链接的SVG路径元素上固定不需要的圆圈?

更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

更多

友情链接

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文