web-dev-qa-db-ja.com

ハードストップを使用した条件付き書式のカラーグラデーション

Excelシートに正と負の値を持つデータの列があります。私ができるようにしたいのは、正の値の場合は濃い緑から薄緑、負の値の場合は薄赤から濃い赤までの条件付き書式(色のグラデーション)を適用することです。

しかし、私にはそれができないようです。たとえば、最大値からゼロまでの条件付きフォーマットを適用し、ゼロを薄緑色にすると、すべての負の値も薄緑色になります。条件付きフォーマットを特定の値までまでまでのみ適用し、それを超えないようにする方法はありますか?同様に、負の値の条件付きフォーマットを作成することもできますが、正の値は明るい赤になります。同じシートに両方がある場合は、優先度が最も高い方が優先されます。

更新:これは本当に醜いですが、どのセルが0より大きいか(または実際には中間値、この場合は〜1.33)、どのセルが小さいかを調べてみることにしました。セル参照をそれらのセルに明示的に設定します。だから私はこのように定義された条件付きフォーマットを試しました(正の緑のスケール):

<x:conditionalFormatting sqref="$E$5 $E$6 $E$10 $E$13 $E$15 $E$17 $E$18 $E$19 $E$22 $E$24 $E$25..." xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
  <x:cfRule type="colorScale" priority="1">
    <x:colorScale>
      <x:cfvo type="num" val="1.13330279612636" />
      <x:cfvo type="num" val="1.91050388235334" />
      <x:color rgb="d6F4d6" />
      <x:color rgb="148621" />
    </x:colorScale>
  </x:cfRule>
</x:conditionalFormatting>

そしてこのように(負の赤いスケール):

<x:conditionalFormatting sqref="$E$4 $E$7 $E$8 $E$9 $E$11 $E$12 $E$14 $E$16 $E$20 $E$21 $E$23 $E$26 $E$28 $E$29 $E$30..." xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
  <x:cfRule type="colorScale" priority="1">
    <x:colorScale>
      <x:cfvo type="num" val="0.356101709899376" />
      <x:cfvo type="num" val="1.13330279612636" />
      <x:color rgb="985354" />
      <x:color rgb="f4dddd" />
    </x:colorScale>
  </x:cfRule>
</x:conditionalFormatting>

そして、これはうまくいきます!並べ替えを試みるポイント(このシートには自動フィルターがあります)まで、セルの割り当てが台無しになります。これで、1.33より大きい値が得られ、緑のグラデーションルールが適用されるはずですが、赤のグラデーションによって参照されるようになりました(したがって、最終的には淡い赤になります)。

相対セル参照と絶対セル参照の両方(つまり、$を引いたもの)で試しましたが、どちらも機能しないようです。

11
Matt Burland

デフォルトのExcel条件付き書式を使用してこれを機能させる方法を見つけることができませんでした。ただし、この機能を有効にする独自の条件付き書式設定アルゴリズムをVBAで作成することは可能です。

Sub UpdateConditionalFormatting(rng As Range)
    Dim cell As Range
    Dim colorValue As Integer
    Dim min, max As Integer

    min = WorksheetFunction.min(rng)
    max = WorksheetFunction.max(rng)

    For Each cell In rng.Cells
        If (cell.Value > 0) Then
            colorValue = (cell.Value / max) * 255
            cell.Interior.Color = RGB(255 - colorValue, 255, 255 - colorValue)
        ElseIf (cell.Value < 0) Then
            colorValue = (cell.Value / min) * 255
            cell.Interior.Color = RGB(255, 255 - colorValue, 255 - colorValue)
        End If

        Next cell
    End
End Sub

上記のコードは次の配色を生成し、考えているパレットに合わせて簡単に変更できます。

gradient conditional format

このコードをマクロで使用するか、Worksheet_Changeイベントにドロップして、自動的に更新することができます(Worksheet_Changeイベントハンドラーにインストールすると、元に戻す機能が失われることに注意してください)。

Sub Worksheet_Change(ByVal Target As Range)
    UpdateConditionalFormatting Range("A1:A21")
End Sub
8

これは比較的簡単になると思いましたが、もっと考えが必要で、エレガントな解決策ではありません。

あなたがvbaのバックグラウンドを持っていると仮定して、私が使用する方法を紹介します-プログラミングのヘルプが必要な場合は、コメントを残してサポートを提供します。

仮定:範囲は最小-最大または最大-最小でソートされます 'これは他の方法では機能しません

計算または選択時に更新するシートレベルのマクロを作成します-条件付き書式を更新するときはいつでも

このマクロでは、データ範囲の上限と下限、および中点の位置を特定します

上の写真では、

LB = A1
UP = A21
MP = A11

次に、中点が正確になることはないと言ったifステートメントを使用して2つのグラデーションを適用するだけなので、ifステートメントは中点が上限または下限の範囲に属するかどうかを判断します。

その後、ちょうど:

Range(LB:MP).Select .......apply traditional conditional format 1 (CF1)
Range(MP+1:UP).Select .......apply traditional conditional format 2 (CF2)
or
Range(LB:MP-1).Select .......apply traditional conditional format 1
Range(MP:UP).Select .......apply traditional conditional format 2

MPの色として白は使用しませんが、CF1で赤の範囲の場合は、明るい赤から濃い赤、CF2では薄緑から濃い緑を使用します。

--------------------------------------編集------- -------------------------------

私はあなたのソートのジレンマを読んだだけです。

私が過去に使用した別の解決策です。コーディングのサポートが必要な場合は、古いコードを探すことができます。

RGBで単純な回帰を使用して(GまたはRのみを使用する場合はさらに簡単)、実際に各値に色番号を割り当てました。

MP = (0,1,0)
UP = (0,255,0)
MP-1 = (1,0,0)
LB = (255,0,0)

再び同じシートマクロとMP ifロジック上記のように

それから私はセルを繰り返して色を適用しました

if cellVal < MP then CellVal*Mr+Br 'r for red, M & B for slope & intercept
if cellVal > MP then CellVal*Mg+Bg 'g for green, M & B for slope & intercept

それが明確でない場合は私に知らせてください、そしてあなたがコードで助けが必要な場合は私がそれを提供することができます。

-E

編集2:

範囲全体を反復する代わりに、可視範囲のみを反復することをお勧めします。これにより、さらに高速化され、テーブル/データセットのsort/filterコマンドにトリガーを追加できます。また、カラースペクトルをすべてのデータに基づくか、可視データのみに基づくかを自由に選択できます。後者を使用すると、真上に見えるような「クールな」ことを実行できます。 95パーセンタイルであり、色の違いが見られますが、前者の場合はすべてG 250-255であり、識別が困難です。

4
Schalton

私へのコメントの後 前の回答colorScaleを使用すると、2つのスケールまたは4色のスケールが必要になるため(どちらも許可されていません)、これは不可能だと思います。 )。ただし、数式で条件付き形式を使用することで、独自の形式を作成できます。

このアプローチを使用すると、VBAを必要とせずに機能させることができ、シートの並べ替えや編集は引き続き機能します。

これがどのように機能するかを示す(非常に)大まかな例を一緒にノックアップしました。 every値の新しい条件付き形式を作成するのと同じくらい、少しラフです。関心のある範囲ごとに1つ(おそらくパーセンタイルを使用して)作成する方が適切ですが、それが出発点です。

作業の大部分は、次の2つの方法で行われます。さらに説明が必要な場合は、私に知らせてください。

/// <summary>
/// Adds a conditional format to the sheet based on the value passed in
/// </summary>
/// <param name="value">The value going into the cell</param>
/// <param name="minValue">The minimum value in the whole range of values going into the sheet</param>
/// <param name="maxValue">The maximum value in the whole range of values going into the sheet</param>
/// <param name="ignoreRangeLowValue">The lowest value in the mid-point. A value greater than or equal to this and less than or equal to the ignoreRangeHighValue will be unstyled</param>
/// <param name="ignoreRangeHighValue">The highest value in the mid-point. A value greater than or equal to the ignoreRangeLowValue and less than or equal to this value will be unstyled</param>
/// <param name="lowValuesMinColor">The colour of the lowest value below the mid-point</param>
/// <param name="lowValuesMaxColor">The colour of the highest value below the mid-point</param>
/// <param name="highValuesMinColor">The colour of the lowest value above the mid-point</param>
/// <param name="highValuesMaxColor">The colour of the highest value above the mid-point</param>
/// <param name="differentialFormats">A DifferentialFormats object to add the formats to</param>
/// <param name="conditionalFormatting">A ConditionalFormatting object to add the conditional formats to</param>
private static void AddConditionalStyle(decimal value,
                                decimal minValue,
                                decimal maxValue,
                                decimal ignoreRangeLowValue,
                                decimal ignoreRangeHighValue,
                                System.Drawing.Color lowValuesMinColor,
                                System.Drawing.Color lowValuesMaxColor,
                                System.Drawing.Color highValuesMinColor,
                                System.Drawing.Color highValuesMaxColor,
                                DifferentialFormats differentialFormats, 
                                ConditionalFormatting conditionalFormatting)
{
    System.Drawing.Color fillColor;

    if (value >= ignoreRangeLowValue && value <= ignoreRangeHighValue)
        return;

    if (value > ignoreRangeHighValue)
    {
        fillColor = GetColour(value, ignoreRangeHighValue, maxValue, highValuesMinColor, highValuesMaxColor);
    }
    else
    {
        fillColor = GetColour(value, minValue, ignoreRangeLowValue, lowValuesMinColor, lowValuesMaxColor);
    }

    DifferentialFormat differentialFormat = new DifferentialFormat();
    Fill fill = new Fill();
    PatternFill patternFill = new PatternFill();
    BackgroundColor backgroundColor = new BackgroundColor() { Rgb = fillColor.Name };
    patternFill.Append(backgroundColor);
    fill.Append(patternFill);
    differentialFormat.Append(fill);
    differentialFormats.Append(differentialFormat);

    ConditionalFormattingOperatorValues op = ConditionalFormattingOperatorValues.Between;
    Formula formula1 = null;
    Formula formula2 = null;

    if (value > maxValue)
    {
        op = ConditionalFormattingOperatorValues.GreaterThanOrEqual;
        formula1 = new Formula();
        formula1.Text = value.ToString();
    }
    else if (value < minValue)
    {
        op = ConditionalFormattingOperatorValues.LessThanOrEqual;
        formula1 = new Formula();
        formula1.Text = value.ToString();
    }
    else
    {
        formula1 = new Formula();
        formula1.Text = (value - 0.05M).ToString();
        formula2 = new Formula();
        formula2.Text = (value + 0.05M).ToString();
    }

    ConditionalFormattingRule conditionalFormattingRule = new ConditionalFormattingRule()
    {
        Type = ConditionalFormatValues.CellIs,
        FormatId = (UInt32Value)formatId++,
        Priority = 1,
        Operator = op
    };

    if (formula1 != null)
        conditionalFormattingRule.Append(formula1);

    if (formula2 != null)
        conditionalFormattingRule.Append(formula2);

    conditionalFormatting.Append(conditionalFormattingRule);
}

/// <summary>
/// Returns a Color based on a linear gradient
/// </summary>
/// <param name="value">The value being output in the cell</param>
/// <param name="minValue">The minimum value in the whole range of values going into the sheet</param>
/// <param name="maxValue">The maximum value in the whole range of values going into the sheet</param>
/// <param name="minColor">The color of the low end of the scale</param>
/// <param name="maxColor">The color of the high end of the scale</param>
/// <returns></returns>
private static System.Drawing.Color GetColour(decimal value,
                                        decimal minValue,
                                        decimal maxValue,
                                        System.Drawing.Color minColor,
                                        System.Drawing.Color maxColor)
{
    System.Drawing.Color val;

    if (value < minValue)
        val = minColor;
    else if (value > maxValue)
        val = maxColor;
    else
    {
        decimal scaleValue = (value - minValue) / (maxValue - minValue);

        int r = (int)(minColor.R + ((maxColor.R - minColor.R) * scaleValue));
        int g = (int)(minColor.G + ((maxColor.G - minColor.G) * scaleValue));
        int b = (int)(minColor.B + ((maxColor.B - minColor.B) * scaleValue));

        val = System.Drawing.Color.FromArgb(r, g, b);
    }

    return val;
}

使用例として、私はこれを作成しました:

static uint formatId = 0U;
public static void CreateSpreadsheetWorkbook(string filepath)
{
    SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.
        Create(filepath, SpreadsheetDocumentType.Workbook);

    // Add a WorkbookPart to the document.
    WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
    workbookpart.Workbook = new Workbook();

    // Add a WorksheetPart to the WorkbookPart.
    WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();

    SheetData sheetData = new SheetData();
    worksheetPart.Worksheet = new Worksheet(sheetData);

    // Add Sheets to the Workbook.
    Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.
        AppendChild<Sheets>(new Sheets());

    // Append a new worksheet and associate it with the workbook.
    Sheet sheet = new Sheet()
    {
        Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart),
        SheetId = 1,
        Name = "FormattedSheet"
    };
    sheets.Append(sheet);

    WorkbookStylesPart stylesPart = workbookpart.AddNewPart<WorkbookStylesPart>();
    stylesPart.Stylesheet = new Stylesheet();

    Fills fills = new Fills() { Count = (UInt32Value)20U }; //this count is slightly out; we should calculate it really

    //this could probably be more efficient - we don't really need one for each value; we could put them in percentiles for example
    DifferentialFormats differentialFormats = new DifferentialFormats() { Count = (UInt32Value)20U };

    ConditionalFormatting conditionalFormatting = new ConditionalFormatting() { SequenceOfReferences = new ListValue<StringValue>() { InnerText = "A1:A21" } };

    for (decimal i = 1; i > -1.1M; i -= 0.1M)
    {
        AddConditionalStyle(i, -0.8M, 0.8M, 0M, 0M,
                            System.Drawing.Color.FromArgb(152, 83, 84),
                            System.Drawing.Color.FromArgb(244, 221, 221),
                            System.Drawing.Color.FromArgb(214, 244, 214),
                            System.Drawing.Color.FromArgb(20, 134, 33),
                            differentialFormats,
                            conditionalFormatting);
    }

    worksheetPart.Worksheet.Append(conditionalFormatting);
    stylesPart.Stylesheet.Append(differentialFormats);

    uint rowId = 1U;
    for (decimal i = 1; i > -1.1M; i -= 0.1M)
    {
        Cell cell = new Cell();
        cell.DataType = CellValues.Number;
        cell.CellValue = new CellValue(i.ToString());

        Row row = new Row() { RowIndex = rowId++ };
        row.Append(cell);
        sheetData.Append(row);
    }

    workbookpart.Workbook.Save();

    spreadsheetDocument.Close();
}

これにより、次のようなスプレッドシートが作成されます。

enter image description here

3
petelids

あなたのさらなるコメントに基づいて、3色のグラデーションを使用することに関するあなたの特定の懸念は、「遷移」ポイントの周りの区別の欠如であることがわかります。 特定の優先度を持つ重複するセクションで、実際には条件付き書式ルールの複数のセットを使用することに注意してください、次のようになります。

-100から100までの数値を保持する列Aを見ていると仮定します。-100以下のものを真っ赤にし、0近くで徐々に消えていくようにします。次に、たとえば+ .5から-.5、無色の白が必要です。次に、0の近くで薄緑色になり、+ 100で明るい緑色になります。

まず、「0」セクションに関するルールを設定します。何かのようなもの:

=ROUND(A1,0)=0

このルールを優先的に適用し、セルを白にするように設定します。これを使用して、離れたケースを「ホワイトアウト」することもできることに注意してください。何かのようなもの:

=OR(ROUND(A1,0)=0,ROUND(A1,0)>100,ROUND(A1,0)<-100)

このルールは、0のセルを白にし、目的の-100-> 100の範囲外のセルを白にします。

次に、グラデーションを含む2番目のルールを適用します。これにより、3色が設定され、白が0になり(ハードコードされた「0に丸められた」ルールが上に適用され、0の周りの段階的な色が削除されます)、赤が-100に、緑が100になります。

これに基づいて、-100〜> 100の範囲外のものはすべて白になり、0に丸められるものはすべて白になり、範囲内の他の数値は明るい赤から白、明るい緑に均等に移動します。

1

おそらく、numcfvoタイプを使用して、中点を白の色でゼロとして定義することができます。次に、minを赤に設定し、maxを緑に設定します。

たとえばこのようなもの

<conditionalFormatting sqref="A1:A21">
   <cfRule type="colorScale" priority="1">
      <colorScale>
         <cfvo type="min" />
         <cfvo type="num" val="0" />
         <cfvo type="max" />
         <color rgb="ff0000" />
         <color rgb="ffffff" />
         <color rgb="00ff00" />
      </colorScale>
   </cfRule>
</conditionalFormatting>

次のような結果が得られます。

enter image description here

1
petelids

私はvbaの初心者であり、これは興味深い質問だと思いました。 「ブレーンストーミング」ソリューションの投稿にルールがどのように適用されるかわからないので、つま先を踏んでいる場合はお知らせください。回答を削除し、今後は回避する方法を学びます。言われている謙虚な紹介:

Vbaを介して条件付き書式を変更できますか?私はこれを行うことが可能かどうかを調査します:vba条件付き書式の書式設定プロパティとオブジェクトを読むと、TintAndShadeを使用できるようです

ルール#1:希望する中点単色緑色よりも大きいものすべてに色を付ける(数式を使用)

ルール#2:単色の赤の反対側

ルール#3:3方向のグラデーション-> vbaで変更

変更--色を削除参照しますが、設定した場所に行を追加します

 .TintAndShade = .Gradient 

iF内

IF .Gradient < 0.3 Then .TintAndShade = 0.3 Else .TintAndShade = .Gradient End if

(0.3は私の提案です。少なくとも私の画面では、緑@ 0.3の色合いは、赤@ 0.3とは明らかに異なります)

0
Stian Yttervik