Randomize custom palettes

Discussion about writing code for Inkscape.
oigo
Posts: 2
Joined: Mon Feb 03, 2014 10:05 pm

Randomize custom palettes

Postby oigo » Mon Feb 03, 2014 11:00 pm

Hello,

I'm working on extension to randomize color of selected objects, something like "color>randomize" but by specific palette colors. So far I made it somewhat to work but not exactly as I wanted.
What I want to do: lets say I select 10 objects and I want to assign random color to each object from specific palette but excluding color that already was randomly chosen on previous objects in that selection set, that is I want each color to be used out, to be unique. In case of my palette consisting of 5 colors and 10 objects being selected I would want this extension to pick unique colors from that palette for first 5 objects and only then colors could start repeating since there are no more unique colors in that palette.
At the moment I made it to load palette from file, parse it to list and randomly color selected objects, but the problem is that most of the time those colors repeat even if I have palette of 5 colors and 5 objects selected.

P.s. I only know a bit of php and can't understand how to go further about this in python.

My code:

Code: Select all

import coloreffect,random,inkex


class C(coloreffect.ColorEffect):
   def __init__(self):
      coloreffect.ColorEffect.__init__(self)
      self.OptionParser.add_option("--palette",
         action="store", type="int",
         dest="palette", default=1,
         help="list item in palette")
      self.OptionParser.add_option("--random",
         action="store", type="inkbool",
         dest="random", default=False,
         help="random color from palette")
      self.OptionParser.add_option("--refresh",
         action="store", type="inkbool",
         dest="refresh", default=False,
         help="refresh with new colors")

   def colmod(self,r,g,b):
      palettes = []
      f = open('color_palette.cfg', 'r')
      for line in f:
         palettes.append(line)
      from random import choice
      if self.options.random:
         palette = choice(palettes)
      else:
         if self.options.palette < len(palettes):
            palette = palettes [self.options.palette]
         else:
            palette = 'ff0000'
      palette = palette.split(',')
      color = choice(palette)
      return str(color)

c = C()
c.affect()


And palette file basically contains lines with hex colors separated by commas, each line represents a color palette:

Code: Select all

874E3B,B5A694,120303,400A0A,851414
69D2E7,A7DBD8,E0E4CC,F38630,FA6900
ECD078,D95B43,C02942,542437,53777A
FE4365,FC9D9A,F9CDAD,C8C8A9,83AF9B


.inx:

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
   <_name>Randomize palettes</_name>
   <id>org.inkscape.color.randomize_palette</id>
   <dependency type="executable" location="extensions">coloreffect.py</dependency>
   <dependency type="executable" location="extensions">color_palette.py</dependency>
   <dependency type="executable" location="extensions">simplestyle.py</dependency>
   <param name="palette" type="int" min="0" max="100" _gui-text="Palette">true</param>
   <param name="random" type="boolean" _gui-text="Random">true</param>
   <param name="refresh" type="boolean" _gui-text="Refresh">true</param>
   <effect>
      <object-type>all</object-type>
      <effects-menu>
         <submenu _name="Color"/>
      </effects-menu>
   </effect>
   <script>
      <command reldir="extensions" interpreter="python">color_palette.py</command>
   </script>
</inkscape-extension>
Last edited by oigo on Tue Feb 04, 2014 5:23 am, edited 1 time in total.

User avatar
ragstian
Posts: 1181
Joined: Thu Oct 11, 2012 2:44 am
Location: Stavanger-Norway

Re: Randomize custom palettes

Postby ragstian » Tue Feb 04, 2014 2:30 am

Hi

Interesting challenge, could we please have the INX extension file as well?
Makes it easier when testing without having to make it from scratch.

You have (more or less) answered this yourself! By turning your "specification into "pseudocode" you got the outline of the code.
Then you just have to translate the pseudocode into python code.

Personally I would not use the "random.choice" function the way you do where you have no control,
as you have discovered the random function can return the same number (color) more than once.

It might be a better idea to;
('pseudocode')

Code: Select all

make the palette list
shuffle the palette list
for each enumerate.object: (check python enumerate)
   assign object color from list using the enumerate index
  ( If you got more objects than unique colors in the palette list you
     would have to get the palette list index by; index = index % colors (% = mod operator) )


I have made several palette related extensions - check this;
viewtopic.php?f=5&t=14090&hilit=ragstian+palette
(as my code is 'terrible" I have not "released" some of my other work!)

Hope this helps.

RGDS
Ragnar
Good Luck!
( ͡° ͜ʖ ͡°)
RGDS
Ragnar

oigo
Posts: 2
Joined: Mon Feb 03, 2014 10:05 pm

Re: Randomize custom palettes

Postby oigo » Tue Feb 04, 2014 5:37 am

Updated original post with inx code.
Thank you, I'll look in to that enumerate and what you suggest. Well I think I could somehow even hack it with that random.choice by saving already used colors in some list and matching it against full palette or just removing values from full palette list and randomizing the remainder although I don't even know how Inkscape + python handles it, how does it go through objects, does it use whole colmod function fresh while cycling through objects, do I need to play with some global variables and such.

User avatar
ragstian
Posts: 1181
Joined: Thu Oct 11, 2012 2:44 am
Location: Stavanger-Norway

Re: Randomize custom palettes

Postby ragstian » Tue Feb 04, 2014 6:42 am

Hi.

For an idea on how to iterate over the selected objects in the SVG file take a look at my code here; it goes through ALL SELECTED objects in the SVG file and change the colors.
(You have to select the objects before running this extension. This is only part of th complete extension.)

Code: Select all

        # Iterate over all selected items
        swaps = 0
        items = 0
        colors_found = False
        items_found = False
        allowed_to_change = ('stroke', 'fill')
        for myid, myitem in self.selected.iteritems():
            node = self.getElementById(myid)
            styles = simplestyle.parseStyle(myitem.get("style"))
            items_found = True
            items += 1
            color_index = 0

            # Create copy of styles - change values in this to
            # avoid "double change"
            # Use deepcopy to get a new copy and not only a reference
            # to original styles
            new_styles = copy.deepcopy(styles)
            # for key, value in styles.iteritems():
                # change color value in dictionary (styles)
                # iterate over all keys in styles dictionary
                # if stroke or fill keys are found replace
                # with corresponding value from new palette.
            for key, value in styles.iteritems():
                # allow changes for stroke and fill only
                if key in allowed_to_change:
                    if value in old_p_list:
                        # Get numerical position in list
                        pos = old_p_list.index(value)
                        new_styles[key] = (new_p_list[pos])
                        colors_found = "True"
                        swaps += 1
                        if debug:
                            message = ("Found Color: " + value +
                                       " at index: " + str(pos+1) +
                                       " in the palette, SVG item:  " +
                                       str(myid) + ", Key: " +
                                       str(key) + ", Value: " +
                                       str(value) + ". New Color: " +
                                       new_p_list[pos])
                            inkex.debug(message)
                color_index = color_index + 1
            node.set("style", simplestyle.formatStyle(new_styles))


Good Luck ;)
RGDS
Ragnar
Good Luck!
( ͡° ͜ʖ ͡°)
RGDS
Ragnar


Return to “Programming”