web-dev-qa-db-fra.com

Couleur des cellules par valeur absolue dans une plage dans Excel 2010

Je cherche à colorer une table de valeurs dans Excel 2010 en fonction de leur valeur absolue. Fondamentalement, si j'ai la table:

enter image description here

... les cellules sont colorées par la valeur brute de la cellule. Ce que je voudrais faire, c’est colorer par la valeur absolue de la cellule, donc avec la coloration de la cellule de ce tableau:

enter image description here

... mais avec les valeurs du premier tableau (les valeurs réelles). Des idées sur la façon dont on pourrait faire cela? Via l'interface graphique ou avec VBA?

7
HotDogCannon

Je ne pense pas qu'il existe un moyen de faire cela avec trois couleurs (rouge, jaune, vert), mais vous pouvez le faire avec deux couleurs (par exemple jaune et vert). Faites simplement la même couleur pour la valeur basse et la couleur pour la valeur haute. De cette façon, les cellules avec la valeur absolue la plus basse auront la couleur du milieu et les cellules avec la valeur absolue la plus haute auront l’autre couleur.

  • Sélectionnez vos données
  • Mise en forme conditionnelle
  • Échelle de couleur
  • Plus de règles
  • Sélectionnez "Échelle 3 points" sous Style de format.
  • Changer les couleurs pour que les couleurs maximum et minimum soient les mêmes
6
DHerls

Voici ma solution à ce problème. La formule de format conditionnel lit 

=AND(ABS(B3)>0,ABS(B3)<=500) 

pour le vert le plus foncé, l'échelle passe de 500 à 1 000, de 1 000 à 1 500 et enfin de 1 500 à 2 000 pour la bande rouge.

Formats conditionnels

Conditional Formats

Valeurs d'échelle de couleur

Color Scale Values

Voici une photo de l'ensemble de données que j'ai utilisé pour tester ces formats conditionnels:

Test

4
scottpjohnson

Une variante de cette illustration de mise en forme conditionnelle simple peut fonctionner pour vous.

Mettez en surbrillance l’ensemble de la plage de données (la cellule LH supérieure doit être le point d’ancrage de l’adressage relatif) et entrez la formule: en «notation relative», c’est-à-dire les références de cellule sans le signe dollar. Vous devez également tenir compte de l'ordre des règles.

La formule la plus haute est masquée mais lit =(ABS(B3)>39) * (ABS(B3)<41) Notez que le symbole * applique une opération AND.

enter image description here

2
barryleajo

Ok, j'ai une solution qui fonctionne avec le conditionnement 3 couleurs. Fondamentalement, vous fournissez une région à mon code. Il crée ensuite deux plages, une de nombres négatifs et une de valeurs positives. Il applique ensuite la mise en forme conditionnelle 

rouge-bas jaune-moyen vert-haut à la plage positive et 

rouge-haut jaune-moyen vert-bas jusqu'à la plage négative. 

C’était une solution rapide, donc elle était bâclée et peu robuste (par exemple, elle ne fonctionne que dans les colonnes A à Z en raison d’une conversion ascii paresseuse pour les numéros de colonne), mais cela fonctionne. (Je posterais une photo mais je n'ai pas assez de points)

---------------------modifier---------------------------- ---

@pnuts a raison, à moins que les données soient symétriques, cette solution ne fonctionnera pas telle quelle. C'est pourquoi j'ai proposé une nouvelle solution. Je vais d’abord expliquer l’idée générale, puis, en gros, vider le code. Si vous comprenez la logique, le code devrait être assez clair. C'est une solution plutôt compliquée pour un problème aussi simple en apparence, mais n'est-ce pas toujours le cas? :-P

Nous continuons d’utiliser l’idée de base du code original, de créer une plage négative et de lui appliquer une échelle de couleurs, puis de créer une plage positive et de lui appliquer l’échelle de couleur inversée. Comme vu ci-dessous

Négatif ........... 0 ................ positif

vert jaune rouge | rouge jaune vert

Donc, avec nos données asymétriques data_set = {- 1, -1, -2, -2, -2, -2, -3, -4,1,5,8,13} ce que je fais est le reflet de la la valeur extrême. Dans ce cas 13, donc maintenant data_set = {- 13, -1, -1, -2, -2, -2, -2, -3, -4,1,5,8,13} Notice l'élément additionnel -13 . Je suppose que vous avez un bouton pour activer cette macro, donc je stocke le supplément -13 dans une cellule située sous le bouton, de sorte que même si elle n’est pas visible (ouais, je sais qu’ils peuvent déplacer le bouton, etc., mais c’était la chose la plus facile à laquelle je pouvais penser)

Bien, tout cela est bien et les cartes vertes correspondent aux cartes 13 ET -13, mais le dégradé de couleurs est basé sur les centiles (en fait, le code à barres des couleurs utilise le 50e centile pour déterminer le point médian, ou dans notre cas, où la section jaune est) 

Selection.FormatConditions(1).ColorScaleCriteria(2).Value = 50

donc avec notre distribution {-13, -1, -1, -2, -2, -2, -2, -3, -4,1,5,8,13}, nous pourrions commencer à voir le jaune dans la plage positive autour du nombre 8.5 Depuis 8.5 est le 50ème percentile. mais dans la plage négative (même si nous ajoutons un -13 en miroir), le 50e centile est égal à -2, de sorte que notre jaune dans la plage négative commence à 2 !! À peine idéal. tout comme les pnuts mentionnés, mais nous nous rapprochons. si vous avez des données assez symétriques, ce problème ne sera pas présent, mais encore une fois, nous examinons le pire cas de jeux de données asymétriques

Ce que j'ai ensuite fait est de faire correspondre statistiquement les points médians ... ou du moins leurs couleurs. Donc, puisque notre valeur extrême (13) est dans la plage positive, nous laissons le jaune au 50e centile et essayons de la refléter dans la plage négative en modifiant le pourcentage de la couleur jaune qui apparaît (si la plage négative avait la valeur extrême, nous le ferions). laissez le jaune à ce 50e percentile et essayez de le refléter dans la plage positive). Cela signifie que, dans notre gamme négative, nous voulons déplacer notre jaune (50ème centile) de -2 à un nombre autour de -8.5 afin qu'il corresponde à la gamme positive. J'ai écrit une fonction appelée Function iGetPercentileFromNumber(my_range As Range, num_to_find As Double) Cela ne fait que ça! Plus spécifiquement, il prend une plage et lit les valeurs dans un tableau. Il ajoute ensuite num_to_find au tableau et détermine le pourcentage correspondant à num_to_find en tant que i nteger 0-100 (d'où le i du nom de la fonction). En utilisant à nouveau nos exemples de données, nous appellerions quelque chose comme

imidcolorpercentile = iGetPercentileFromNumber(negrange with extra element -13, -8.5)

Où -8,5 est le négatif (50ème percentile de la plage positive = 8,5). Ne vous inquiétez pas, le code fournit automatiquement les plages et les chiffres, ceci est pour votre compréhension. La fonction ajouterait -8,5 à notre tableau de valeurs négatives {-13, -1, -1, -2, -2, -2, -3, -4, -8,5} puis déterminer quel centile c'est.

Maintenant, prenons ce centile et le transmettons comme point médian de notre formatage conditionnel de négation. donc nous avons changé le jaune du 50e centile

Selection.FormatConditions(1).ColorScaleCriteria(2).Value = 50

à notre nouvelle valeur

Selection.FormatConditions(1).ColorScaleCriteria(2).Value = imidcolorpercentile 'was 50

qui maintenant a décalé les couleurs !! nous avons essentiellement créé une barre de couleur d'aspect symétrique. Même si nos chiffres sont loin d'être symétriques. 

Ok, je sais que c'était une tonne à lire et à digérer. mais voici les principales conclusions de ce code - utilise la mise en forme conditionnelle complète à 3 couleurs (ne pas simplement définir les deux couleurs extrêmes de la même manière pour ressembler à la valeur abs) - crée des plages de couleurs symétriques en utilisant un cellule obstruée (par exemple sous un bouton) pour conserver les valeurs extrêmes - utilise une analyse statistique pour faire correspondre les dégradés de couleurs, même dans des ensembles de données asymétriques

les deux étapes sont nécessaires et aucune ne suffit à elle seule pour créer une vraie échelle de couleurs en miroir

Étant donné que cette solution nécessite une analyse statistique de l'ensemble de données, vous devrez l'exécuter à chaque fois que vous modifiez un numéro (ce qui était en fait le cas auparavant, je ne l'ai jamais dit).

et maintenant le code. Mettez-le dans vba ou un autre programme de mise en évidence. Il est presque impossible de lire tel quel ..... prend une profonde respiration

Sub main()
    Dim Rng As Range
    Dim Cell_under_button As String
    
    Set Rng = Range("A1:H10") 'change me!!!!!!!
    Cell_under_button = "A15"

    Call AbsoluteValColorBars(Rng, Cell_under_button)
    
End Sub

Function iGetPercentileFromNumber(my_range As Range, num_to_find As Double)
    If (my_range.Count <= 0) Then
        Exit Function
    End If
    
    Dim dval_arr() As Double
    'this is one bigger than the range becasue we will add "num_to_find" to it
    ReDim dval_arr(my_range.Count + 1)
    Dim icurr_idx As Integer
    Dim ipos_num As Integer
    
    icurr_idx = 0
        
    'creates array of all the numbers in your range
    For Each cell In my_range
        dval_arr(icurr_idx) = cell.Value
        icurr_idx = icurr_idx + 1
    Next
    
    'adds the number we are searching for to the array
    dval_arr(icurr_idx) = num_to_find
    
    'sorts array in descending order
    dval_arr = BubbleSrt(dval_arr, False)
    
    'if match_type is 0, MATCH finds an exact match
    ipos_exact = Application.Match(CLng(num_to_find), dval_arr, 0)

    'there is a runtime error that can crop up when num_to_find isn't formated as long
    'so we converted it, if it was a double we may not find an exact match so ipos_Exact
    'may fail. now we have to find the closest numbers below or above clong(num_to_find)
    'If match_type is -1, MATCH finds the value <= num_to_find
    ipos_small = Application.Match(CLng(num_to_find), dval_arr, -1)
        
    If (IsError(ipos_small)) Then
        Exit Function
    End If
    
    'sorts array in ascending order
    dval_arr = BubbleSrt(dval_arr, True)
    
    'now we find the index of our  mid color point
    'If match_type is 1, MATCH finds the value >= num_to_find
    ipos_large = Application.Match(CLng(num_to_find), dval_arr, 1)
    
    If (IsError(ipos_large)) Then
        Exit Function
    End If

    'barring any crazy errors descending order = reverse order (ascending) so
    ipos_small = UBound(dval_arr) - ipos_small
    
    'to minimize color error we pick the value closest to num_to_find
    If Not (IsError(ipos_exact)) Then
        'barring any crazy errors descending order = reverse order (ascending) so
        'since the index was WRT descending subtract that from the length to get ascending
        ipos_num = UBound(dval_arr) - ipos_exact
    Else
        If (Abs(dval_arr(ipos_large) - num_to_find) < Abs(dval_arr(ipos_small) - num_to_find)) Then
            ipos_num = ipos_large
        Else
            ipos_num = ipos_small
        End If
    End If
       
    'gets the percentile as an integer value 0-100
    iGetPercentileFromNumber = Round(CDbl(ipos_num) / my_range.Count * 100)
End Function

'fairly well known algorithm doesn't need muxh explanation
Public Function BubbleSrt(ArrayIn, Ascending As Boolean)
    Dim SrtTemp As Variant
    Dim i As Long
    Dim j As Long
    
    
    If Ascending = True Then
        For i = LBound(ArrayIn) To UBound(ArrayIn)
             For j = i + 1 To UBound(ArrayIn)
                 If ArrayIn(i) > ArrayIn(j) Then
                     SrtTemp = ArrayIn(j)
                     ArrayIn(j) = ArrayIn(i)
                     ArrayIn(i) = SrtTemp
                 End If
             Next j
         Next i
    Else
        For i = LBound(ArrayIn) To UBound(ArrayIn)
             For j = i + 1 To UBound(ArrayIn)
                 If ArrayIn(i) < ArrayIn(j) Then
                     SrtTemp = ArrayIn(j)
                     ArrayIn(j) = ArrayIn(i)
                     ArrayIn(i) = SrtTemp
                 End If
             Next j
         Next i
    End If
    
    BubbleSrt = ArrayIn
End Function

Sub AbsoluteValColorBars(Rng As Range, Cell_under_button As String)
    negrange = ""
    posrange = ""
    
    'deletes existing rules
    Rng.FormatConditions.Delete
    
    'makes a negative and positive range
    For Each cell In Rng
        If cell.Value < 0 Then
            ' im certain there is a better way to get the column character
            negrange = negrange & Chr(cell.Column + 64) & cell.Row & ","
        Else
            ' im certain there is a better way to get the column character
            posrange = posrange & Chr(cell.Column + 64) & cell.Row & ","
        End If
    Next cell
    
    'removes trailing comma
    If Len(negrange) > 0 Then
        negrange = Left(negrange, Len(negrange) - 1)
    End If
    
    If Len(posrange) > 0 Then
        posrange = Left(posrange, Len(posrange) - 1)
    End If
    
    'finds the data extrema
    most_pos = WorksheetFunction.Max(Range(posrange))
    most_neg = WorksheetFunction.Min(Range(negrange))
    
    'initial values
    neg_range_percentile = 50
    pos_range_percentile = 50
    
    'if the negative range has the most extreme value
    If (most_pos + most_neg < 0) Then
        'put the corresponding positive number in our obstructed cell
        Range(Cell_under_button).Value = -1 * most_neg
        'and add it to the positive range, to reskew the data
        posrange = posrange & "," & Cell_under_button
        
        'gets the 50th percentile number from neg range and tries to mirror it in pos range
        'this should statistically skew the data
        the_num = WorksheetFunction.Percentile_Inc(Range(negrange), 0.5)
        pos_range_percentile = iGetPercentileFromNumber(Range(posrange), -1 * the_num)
    Else
        'put the corresponding negative number in our obstructed cell
        Range(Cell_under_button).Value = -1 * most_pos
        'and add it to the positive range, to reskew the data
        negrange = negrange & "," & Cell_under_button
        
        'gets the 50th percentile number from pos range and tries to mirror it in neg range
        'this should statistically skew the data
        the_num = WorksheetFunction.Percentile_Inc(Range(posrange), 0.5)
        neg_range_percentile = iGetPercentileFromNumber(Range(negrange), -1 * the_num)
    End If
    
    'low red high green for positive range
    Call addColorBar(posrange, False, pos_range_percentile)
    
     'high red low green for negative range
    Call addColorBar(negrange, True, neg_range_percentile)
   
End Sub
Sub addColorBar(my_range, binverted, imidcolorpercentile)
    If (binverted) Then
        'ai -> array ints
        adcolor = Array(8109667, 8711167, 7039480)
        '               green  , yellow , red
    Else
        adcolor = Array(7039480, 8711167, 8109667)
        '               red    , yellow , greeb
    End If
    
    Range(my_range).Select
    
     'these were just found using the record macro feature
    Selection.FormatConditions.AddColorScale ColorScaleType:=3
    Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
    
    'assigns a color for the lowest values in the range
    Selection.FormatConditions(1).ColorScaleCriteria(1).Type = _
        xlConditionValueLowestValue
    With Selection.FormatConditions(1).ColorScaleCriteria(1).FormatColor
        .Color = adcolor(0)
        .TintAndShade = 0
    End With
    
    'assigns color to... midpoint of range
    Selection.FormatConditions(1).ColorScaleCriteria(2).Type = _
        xlConditionValuePercentile
    Selection.FormatConditions(1).ColorScaleCriteria(2).Value = imidcolorpercentile 'originally 50
    With Selection.FormatConditions(1).ColorScaleCriteria(2).FormatColor
        .Color = adcolor(1)
        .TintAndShade = 0
    End With
    
    'assigns colors to highest values in the range
    Selection.FormatConditions(1).ColorScaleCriteria(3).Type = _
        xlConditionValueHighestValue
    With Selection.FormatConditions(1).ColorScaleCriteria(3).FormatColor
        .Color = adcolor(2)
        .TintAndShade = 0
    End With
End Sub

2
andrew

Je vais beaucoup emprunter à la réponse de @barryleajo (cela ne me fera pas de mal si vous sélectionnez cette réponse). Comme indiqué dans cette réponse, l'ordre de la mise en forme conditionnelle est la clé, commencez par les valeurs absolues les plus petites et progressez vers le haut. La différence entre cette réponse et celle-ci est qu'il n'est pas nécessaire d'utiliser une instruction "et", car le PO semble indiquer que toutes les valeurs comprises dans une certaine plage de valeur absolue doivent recevoir le même format de couleur. Voici un petit exemple:

enter image description here

0
Clif